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