1/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved		by Bram Moolenaar
4 *
5 * Do ":help uganda"  in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 */
8
9#if defined(FEAT_OLE) && defined(FEAT_GUI_W32)
10/*
11 * OLE server implementation.
12 *
13 * See os_mswin.c for the client side.
14 */
15
16/*
17 * We have some trouble with order of includes here.  For Borland it needs to
18 * be different from MSVC...
19 */
20#ifndef __BORLANDC__
21extern "C" {
22# include "vim.h"
23}
24#endif
25
26#include <windows.h>
27#include <oleauto.h>
28
29extern "C" {
30#ifdef __BORLANDC__
31# include "vim.h"
32#endif
33extern HWND s_hwnd;
34extern HWND vim_parent_hwnd;
35}
36
37#if (defined(_MSC_VER) && _MSC_VER < 1300) || !defined(MAXULONG_PTR)
38/* Work around old versions of basetsd.h which wrongly declares
39 * UINT_PTR as unsigned long */
40# undef UINT_PTR
41# define UINT_PTR UINT
42#endif
43
44#include "if_ole.h"	// Interface definitions
45#include "iid_ole.c"	// UUID definitions (compile here)
46
47/* Supply function prototype to work around bug in Mingw oleauto.h header */
48#ifdef __MINGW32__
49WINOLEAUTAPI UnRegisterTypeLib(REFGUID libID, WORD wVerMajor,
50	    WORD wVerMinor, LCID lcid, SYSKIND syskind);
51#endif
52
53/*****************************************************************************
54 1. Internal definitions for this file
55*****************************************************************************/
56
57class CVim;
58class CVimCF;
59
60/* Internal data */
61// The identifier of the registered class factory
62static unsigned long cf_id = 0;
63
64// The identifier of the running application object
65static unsigned long app_id = 0;
66
67// The single global instance of the class factory
68static CVimCF *cf = 0;
69
70// The single global instance of the application object
71static CVim *app = 0;
72
73/* GUIDs, versions and type library information */
74#define MYCLSID CLSID_Vim
75#define MYLIBID LIBID_Vim
76#define MYIID IID_IVim
77
78#define MAJORVER 1
79#define MINORVER 0
80#define LOCALE 0x0409
81
82#define MYNAME "Vim"
83#define MYPROGID "Vim.Application.1"
84#define MYVIPROGID "Vim.Application"
85
86#define MAX_CLSID_LEN 100
87
88/*****************************************************************************
89 2. The application object
90*****************************************************************************/
91
92/* Definition
93 * ----------
94 */
95
96class CVim : public IVim
97{
98public:
99    ~CVim();
100    static CVim *Create(int *pbDoRestart);
101
102    // IUnknown members
103    STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
104    STDMETHOD_(unsigned long, AddRef)(void);
105    STDMETHOD_(unsigned long, Release)(void);
106
107    // IDispatch members
108    STDMETHOD(GetTypeInfoCount)(UINT *pCount);
109    STDMETHOD(GetTypeInfo)(UINT iTypeInfo, LCID, ITypeInfo **ppITypeInfo);
110    STDMETHOD(GetIDsOfNames)(const IID &iid, OLECHAR **names, UINT n, LCID, DISPID *dispids);
111    STDMETHOD(Invoke)(DISPID member, const IID &iid, LCID, WORD flags, DISPPARAMS *dispparams, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr);
112
113    // IVim members
114    STDMETHOD(SendKeys)(BSTR keys);
115    STDMETHOD(Eval)(BSTR expr, BSTR *result);
116    STDMETHOD(SetForeground)(void);
117    STDMETHOD(GetHwnd)(UINT_PTR *result);
118
119private:
120    // Constructor is private - create using CVim::Create()
121    CVim() : ref(0), typeinfo(0) {};
122
123    // Reference count
124    unsigned long ref;
125
126    // The object's TypeInfo
127    ITypeInfo *typeinfo;
128};
129
130/* Implementation
131 * --------------
132 */
133
134CVim *CVim::Create(int *pbDoRestart)
135{
136    HRESULT hr;
137    CVim *me = 0;
138    ITypeLib *typelib = 0;
139    ITypeInfo *typeinfo = 0;
140
141    *pbDoRestart = FALSE;
142
143    // Create the object
144    me = new CVim();
145    if (me == NULL)
146    {
147	MessageBox(0, "Cannot create application object", "Vim Initialisation", 0);
148	return NULL;
149    }
150
151    // Load the type library from the registry
152    hr = LoadRegTypeLib(MYLIBID, 1, 0, 0x00, &typelib);
153    if (FAILED(hr))
154    {
155	HKEY hKey;
156
157	// Check we can write to the registry.
158	// RegCreateKeyEx succeeds even if key exists. W.Briscoe W2K 20021011
159	if (RegCreateKeyEx(HKEY_CLASSES_ROOT, MYVIPROGID, 0, NULL,
160		  REG_OPTION_NON_VOLATILE,
161		  KEY_ALL_ACCESS, NULL, &hKey, NULL))
162	{
163	    delete me;
164	    return NULL; // Unable to write to registry. Quietly fail.
165	}
166	RegCloseKey(hKey);
167
168	if (MessageBox(0, "Cannot load registered type library.\nDo you want to register Vim now?",
169		    "Vim Initialisation", MB_YESNO | MB_ICONQUESTION) != IDYES)
170	{
171	    delete me;
172	    return NULL;
173	}
174
175	RegisterMe(FALSE);
176
177	// Load the type library from the registry
178	hr = LoadRegTypeLib(MYLIBID, 1, 0, 0x00, &typelib);
179	if (FAILED(hr))
180	{
181	    MessageBox(0, "You must restart Vim in order for the registration to take effect.",
182						     "Vim Initialisation", 0);
183	    *pbDoRestart = TRUE;
184	    delete me;
185	    return NULL;
186	}
187    }
188
189    // Get the type info of the vtable interface
190    hr = typelib->GetTypeInfoOfGuid(MYIID, &typeinfo);
191    typelib->Release();
192
193    if (FAILED(hr))
194    {
195	MessageBox(0, "Cannot get interface type information",
196						     "Vim Initialisation", 0);
197	delete me;
198	return NULL;
199    }
200
201    // Save the type information
202    me->typeinfo = typeinfo;
203    return me;
204}
205
206CVim::~CVim()
207{
208    if (typeinfo && vim_parent_hwnd == NULL)
209	typeinfo->Release();
210    typeinfo = 0;
211}
212
213STDMETHODIMP
214CVim::QueryInterface(REFIID riid, void **ppv)
215{
216    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch) || IsEqualIID(riid, MYIID))
217    {
218	AddRef();
219	*ppv = this;
220	return S_OK;
221    }
222
223    *ppv = 0;
224    return E_NOINTERFACE;
225}
226
227STDMETHODIMP_(ULONG)
228CVim::AddRef()
229{
230    return ++ref;
231}
232
233STDMETHODIMP_(ULONG)
234CVim::Release()
235{
236    // Don't delete the object when the reference count reaches zero, as there
237    // is only a single application object, and its lifetime is controlled by
238    // the running instance, not by its reference count.
239    if (ref > 0)
240	--ref;
241    return ref;
242}
243
244STDMETHODIMP
245CVim::GetTypeInfoCount(UINT *pCount)
246{
247    *pCount = 1;
248    return S_OK;
249}
250
251STDMETHODIMP
252CVim::GetTypeInfo(UINT iTypeInfo, LCID, ITypeInfo **ppITypeInfo)
253{
254    *ppITypeInfo = 0;
255
256    if (iTypeInfo != 0)
257	return DISP_E_BADINDEX;
258
259    typeinfo->AddRef();
260    *ppITypeInfo = typeinfo;
261    return S_OK;
262}
263
264STDMETHODIMP
265CVim::GetIDsOfNames(
266	const IID &iid,
267	OLECHAR **names,
268	UINT n,
269	LCID,
270	DISPID *dispids)
271{
272    if (iid != IID_NULL)
273	return DISP_E_UNKNOWNINTERFACE;
274
275    return typeinfo->GetIDsOfNames(names, n, dispids);
276}
277
278STDMETHODIMP
279CVim::Invoke(
280	DISPID member,
281	const IID &iid,
282	LCID,
283	WORD flags,
284	DISPPARAMS *dispparams,
285	VARIANT *result,
286	EXCEPINFO *excepinfo,
287	UINT *argerr)
288{
289    if (iid != IID_NULL)
290	return DISP_E_UNKNOWNINTERFACE;
291
292    ::SetErrorInfo(0, NULL);
293    return typeinfo->Invoke(static_cast<IDispatch*>(this),
294			    member, flags, dispparams,
295			    result, excepinfo, argerr);
296}
297
298STDMETHODIMP
299CVim::GetHwnd(UINT_PTR *result)
300{
301    *result = (UINT_PTR)s_hwnd;
302    return S_OK;
303}
304
305STDMETHODIMP
306CVim::SetForeground(void)
307{
308    /* Make the Vim window come to the foreground */
309    gui_mch_set_foreground();
310    return S_OK;
311}
312
313STDMETHODIMP
314CVim::SendKeys(BSTR keys)
315{
316    int len;
317    char *buffer;
318    char_u *str;
319    char_u *ptr;
320
321    /* Get a suitable buffer */
322    len = WideCharToMultiByte(CP_ACP, 0, keys, -1, 0, 0, 0, 0);
323    buffer = (char *)alloc(len+1);
324
325    if (buffer == NULL)
326	return E_OUTOFMEMORY;
327
328    len = WideCharToMultiByte(CP_ACP, 0, keys, -1, buffer, len, 0, 0);
329
330    if (len == 0)
331    {
332	vim_free(buffer);
333	return E_INVALIDARG;
334    }
335
336    /* Translate key codes like <Esc> */
337    str = replace_termcodes((char_u *)buffer, &ptr, FALSE, TRUE, FALSE);
338
339    /* If ptr was set, then a new buffer was allocated,
340     * so we can free the old one.
341     */
342    if (ptr)
343	vim_free((char_u *)(buffer));
344
345    /* Reject strings too long to fit in the input buffer. Allow 10 bytes
346     * space to cover for the (remote) possibility that characters may enter
347     * the input buffer between now and when the WM_OLE message is actually
348     * processed. If more that 10 characters enter the input buffer in that
349     * time, the WM_OLE processing will simply fail to insert the characters.
350     */
351    if ((int)(STRLEN(str)) > (vim_free_in_input_buf() - 10))
352    {
353	vim_free(str);
354	return E_INVALIDARG;
355    }
356
357    /* Pass the string to the main input loop. The memory will be freed when
358     * the message is processed.  Except for an empty message, we don't need
359     * to post it then.
360     */
361    if (*str == NUL)
362	vim_free(str);
363    else
364	PostMessage(NULL, WM_OLE, 0, (LPARAM)str);
365
366    return S_OK;
367}
368
369STDMETHODIMP
370CVim::Eval(BSTR expr, BSTR *result)
371{
372#ifdef FEAT_EVAL
373    int len;
374    char *buffer;
375    char *str;
376    wchar_t *w_buffer;
377
378    /* Get a suitable buffer */
379    len = WideCharToMultiByte(CP_ACP, 0, expr, -1, 0, 0, 0, 0);
380    if (len == 0)
381	return E_INVALIDARG;
382
383    buffer = (char *)alloc((unsigned)len);
384
385    if (buffer == NULL)
386	return E_OUTOFMEMORY;
387
388    /* Convert the (wide character) expression to an ASCII string */
389    len = WideCharToMultiByte(CP_ACP, 0, expr, -1, buffer, len, 0, 0);
390    if (len == 0)
391	return E_INVALIDARG;
392
393    /* Evaluate the expression */
394    ++emsg_skip;
395    str = (char *)eval_to_string((char_u *)buffer, NULL, TRUE);
396    --emsg_skip;
397    vim_free(buffer);
398    if (str == NULL)
399	return E_FAIL;
400
401    /* Convert the result to wide characters */
402    MultiByteToWideChar_alloc(CP_ACP, 0, str, -1, &w_buffer, &len);
403    vim_free(str);
404    if (w_buffer == NULL)
405	return E_OUTOFMEMORY;
406
407    if (len == 0)
408    {
409	vim_free(w_buffer);
410	return E_FAIL;
411    }
412
413    /* Store the result */
414    *result = SysAllocString(w_buffer);
415    vim_free(w_buffer);
416
417    return S_OK;
418#else
419    return E_NOTIMPL;
420#endif
421}
422
423/*****************************************************************************
424 3. The class factory
425*****************************************************************************/
426
427/* Definition
428 * ----------
429 */
430
431class CVimCF : public IClassFactory
432{
433public:
434    static CVimCF *Create();
435
436    STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
437    STDMETHOD_(unsigned long, AddRef)(void);
438    STDMETHOD_(unsigned long, Release)(void);
439    STDMETHOD(CreateInstance)(IUnknown *punkOuter, REFIID riid, void ** ppv);
440    STDMETHOD(LockServer)(BOOL lock);
441
442private:
443    // Constructor is private - create via Create()
444    CVimCF() : ref(0) {};
445
446    // Reference count
447    unsigned long ref;
448};
449
450/* Implementation
451 * --------------
452 */
453
454CVimCF *CVimCF::Create()
455{
456    CVimCF *me = new CVimCF();
457
458    if (me == NULL)
459	MessageBox(0, "Cannot create class factory", "Vim Initialisation", 0);
460
461    return me;
462}
463
464STDMETHODIMP
465CVimCF::QueryInterface(REFIID riid, void **ppv)
466{
467    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
468    {
469	AddRef();
470	*ppv = this;
471	return S_OK;
472    }
473
474    *ppv = 0;
475    return E_NOINTERFACE;
476}
477
478STDMETHODIMP_(ULONG)
479CVimCF::AddRef()
480{
481    return ++ref;
482}
483
484STDMETHODIMP_(ULONG)
485CVimCF::Release()
486{
487    // Don't delete the object when the reference count reaches zero, as there
488    // is only a single application object, and its lifetime is controlled by
489    // the running instance, not by its reference count.
490    if (ref > 0)
491	--ref;
492    return ref;
493}
494
495/*ARGSUSED*/
496STDMETHODIMP
497CVimCF::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
498{
499    return app->QueryInterface(riid, ppv);
500}
501
502/*ARGSUSED*/
503STDMETHODIMP
504CVimCF::LockServer(BOOL lock)
505{
506    return S_OK;
507}
508
509/*****************************************************************************
510 4. Registry manipulation code
511*****************************************************************************/
512
513// Internal use only
514static void SetKeyAndValue(const char *path, const char *subkey, const char *value);
515static void GUIDtochar(const GUID &guid, char *GUID, int length);
516static void RecursiveDeleteKey(HKEY hKeyParent, const char *child);
517static const int GUID_STRING_SIZE = 39;
518
519// Register the component in the registry
520// When "silent" is TRUE don't give any messages.
521
522extern "C" void RegisterMe(int silent)
523{
524    BOOL ok = TRUE;
525
526    // Get the application startup command
527    char module[MAX_PATH];
528
529    ::GetModuleFileName(NULL, module, MAX_PATH);
530
531    // Unregister first (quietly)
532    UnregisterMe(FALSE);
533
534    // Convert the CLSID into a char
535    char clsid[GUID_STRING_SIZE];
536    GUIDtochar(MYCLSID, clsid, sizeof(clsid));
537
538    // Convert the LIBID into a char
539    char libid[GUID_STRING_SIZE];
540    GUIDtochar(MYLIBID, libid, sizeof(libid));
541
542    // Build the key CLSID\\{...}
543    char Key[MAX_CLSID_LEN];
544    strcpy(Key, "CLSID\\");
545    strcat(Key, clsid);
546
547    // Add the CLSID to the registry
548    SetKeyAndValue(Key, NULL, MYNAME);
549    SetKeyAndValue(Key, "LocalServer32", module);
550    SetKeyAndValue(Key, "ProgID", MYPROGID);
551    SetKeyAndValue(Key, "VersionIndependentProgID", MYVIPROGID);
552    SetKeyAndValue(Key, "TypeLib", libid);
553
554    // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT
555    SetKeyAndValue(MYVIPROGID, NULL, MYNAME);
556    SetKeyAndValue(MYVIPROGID, "CLSID", clsid);
557    SetKeyAndValue(MYVIPROGID, "CurVer", MYPROGID);
558
559    // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT
560    SetKeyAndValue(MYPROGID, NULL, MYNAME);
561    SetKeyAndValue(MYPROGID, "CLSID", clsid);
562
563    wchar_t w_module[MAX_PATH];
564    MultiByteToWideChar(CP_ACP, 0, module, -1, w_module, MAX_PATH);
565
566    ITypeLib *typelib = NULL;
567    if (LoadTypeLib(w_module, &typelib) != S_OK)
568    {
569	if (!silent)
570	    MessageBox(0, "Cannot load type library to register",
571						       "Vim Registration", 0);
572	ok = FALSE;
573    }
574    else
575    {
576	if (RegisterTypeLib(typelib, w_module, NULL) != S_OK)
577	{
578	    if (!silent)
579		MessageBox(0, "Cannot register type library",
580						       "Vim Registration", 0);
581	    ok = FALSE;
582	}
583	typelib->Release();
584    }
585
586    if (ok && !silent)
587	MessageBox(0, "Registered successfully", "Vim", 0);
588}
589
590// Remove the component from the registry
591//
592// Note: There is little error checking in this code, to allow incomplete
593// or failed registrations to be undone.
594extern "C" void UnregisterMe(int bNotifyUser)
595{
596    // Unregister the type library
597    ITypeLib *typelib;
598    if (SUCCEEDED(LoadRegTypeLib(MYLIBID, MAJORVER, MINORVER, LOCALE, &typelib)))
599    {
600	TLIBATTR *tla;
601	if (SUCCEEDED(typelib->GetLibAttr(&tla)))
602	{
603	    UnRegisterTypeLib(tla->guid, tla->wMajorVerNum, tla->wMinorVerNum,
604			      tla->lcid, tla->syskind);
605	    typelib->ReleaseTLibAttr(tla);
606	}
607	typelib->Release();
608    }
609
610    // Convert the CLSID into a char
611    char clsid[GUID_STRING_SIZE];
612    GUIDtochar(MYCLSID, clsid, sizeof(clsid));
613
614    // Build the key CLSID\\{...}
615    char Key[MAX_CLSID_LEN];
616    strcpy(Key, "CLSID\\");
617    strcat(Key, clsid);
618
619    // Delete the CLSID Key - CLSID\{...}
620    RecursiveDeleteKey(HKEY_CLASSES_ROOT, Key);
621
622    // Delete the version-independent ProgID Key
623    RecursiveDeleteKey(HKEY_CLASSES_ROOT, MYVIPROGID);
624
625    // Delete the ProgID key
626    RecursiveDeleteKey(HKEY_CLASSES_ROOT, MYPROGID);
627
628    if (bNotifyUser)
629	MessageBox(0, "Unregistered successfully", "Vim", 0);
630}
631
632/****************************************************************************/
633
634// Convert a GUID to a char string
635static void GUIDtochar(const GUID &guid, char *GUID, int length)
636{
637    // Get wide string version
638    LPOLESTR wGUID = NULL;
639    StringFromCLSID(guid, &wGUID);
640
641    // Covert from wide characters to non-wide
642    wcstombs(GUID, wGUID, length);
643
644    // Free memory
645    CoTaskMemFree(wGUID);
646}
647
648// Delete a key and all of its descendents
649static void RecursiveDeleteKey(HKEY hKeyParent, const char *child)
650{
651    // Open the child
652    HKEY hKeyChild;
653    LONG result = RegOpenKeyEx(hKeyParent, child, 0,
654			       KEY_ALL_ACCESS, &hKeyChild);
655    if (result != ERROR_SUCCESS)
656	return;
657
658    // Enumerate all of the decendents of this child
659    FILETIME time;
660    char buffer[1024];
661    DWORD size = 1024;
662
663    while (RegEnumKeyEx(hKeyChild, 0, buffer, &size, NULL,
664			NULL, NULL, &time) == S_OK)
665    {
666	// Delete the decendents of this child
667	RecursiveDeleteKey(hKeyChild, buffer);
668	size = 256;
669    }
670
671    // Close the child
672    RegCloseKey(hKeyChild);
673
674    // Delete this child
675    RegDeleteKey(hKeyParent, child);
676}
677
678// Create a key and set its value
679static void SetKeyAndValue(const char *key, const char *subkey, const char *value)
680{
681    HKEY hKey;
682    char buffer[1024];
683
684    strcpy(buffer, key);
685
686    // Add subkey name to buffer.
687    if (subkey)
688    {
689	strcat(buffer, "\\");
690	strcat(buffer, subkey);
691    }
692
693    // Create and open key and subkey.
694    long result = RegCreateKeyEx(HKEY_CLASSES_ROOT,
695				 buffer,
696				 0, NULL, REG_OPTION_NON_VOLATILE,
697				 KEY_ALL_ACCESS, NULL,
698				 &hKey, NULL);
699    if (result != ERROR_SUCCESS)
700	return;
701
702    // Set the value
703    if (value)
704	RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value,
705		      (DWORD)STRLEN(value)+1);
706
707    RegCloseKey(hKey);
708}
709
710/*****************************************************************************
711 5. OLE Initialisation and shutdown processing
712*****************************************************************************/
713extern "C" void InitOLE(int *pbDoRestart)
714{
715    HRESULT hr;
716
717    *pbDoRestart = FALSE;
718
719    // Initialize the OLE libraries
720    hr = OleInitialize(NULL);
721    if (FAILED(hr))
722    {
723	MessageBox(0, "Cannot initialise OLE", "Vim Initialisation", 0);
724	goto error0;
725    }
726
727    // Create the application object
728    app = CVim::Create(pbDoRestart);
729    if (app == NULL)
730	goto error1;
731
732    // Create the class factory
733    cf = CVimCF::Create();
734    if (cf == NULL)
735	goto error1;
736
737    // Register the class factory
738    hr = CoRegisterClassObject(
739	MYCLSID,
740	cf,
741	CLSCTX_LOCAL_SERVER,
742	REGCLS_MULTIPLEUSE,
743	&cf_id);
744
745    if (FAILED(hr))
746    {
747	MessageBox(0, "Cannot register class factory", "Vim Initialisation", 0);
748	goto error1;
749    }
750
751    // Register the application object as active
752    hr = RegisterActiveObject(
753	app,
754	MYCLSID,
755	NULL,
756	&app_id);
757
758    if (FAILED(hr))
759    {
760	MessageBox(0, "Cannot register application object", "Vim Initialisation", 0);
761	goto error1;
762    }
763
764    return;
765
766    // Errors: tidy up as much as needed and return
767error1:
768    UninitOLE();
769error0:
770    return;
771}
772
773extern "C" void UninitOLE()
774{
775    // Unregister the application object
776    if (app_id)
777    {
778	RevokeActiveObject(app_id, NULL);
779	app_id = 0;
780    }
781
782    // Unregister the class factory
783    if (cf_id)
784    {
785	CoRevokeClassObject(cf_id);
786	cf_id = 0;
787    }
788
789    // Shut down the OLE libraries
790    OleUninitialize();
791
792    // Delete the application object
793    if (app)
794    {
795	delete app;
796	app = NULL;
797    }
798
799    // Delete the class factory
800    if (cf)
801    {
802	delete cf;
803	cf = NULL;
804    }
805}
806#endif /* FEAT_OLE */
807