1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
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.
9 #if defined(FEAT_OLE) && defined(FEAT_GUI_W32)
11 * OLE server implementation.
13 * See os_mswin.c for the client side.
17 * We have some trouble with order of includes here. For Borland it needs to
18 * be different from MSVC...
34 extern HWND vim_parent_hwnd
;
38 /* Work around old versions of basetsd.h which wrongly declares
39 * UINT_PTR as unsigned long */
40 # define UINT_PTR UINT
43 #include "if_ole.h" // Interface definitions
44 #include "iid_ole.c" // UUID definitions (compile here)
46 /* Supply function prototype to work around bug in Mingw oleauto.h header */
48 WINOLEAUTAPI
UnRegisterTypeLib(REFGUID libID
, WORD wVerMajor
,
49 WORD wVerMinor
, LCID lcid
, SYSKIND syskind
);
52 /*****************************************************************************
53 1. Internal definitions for this file
54 *****************************************************************************/
60 // The identifier of the registered class factory
61 static unsigned long cf_id
= 0;
63 // The identifier of the running application object
64 static unsigned long app_id
= 0;
66 // The single global instance of the class factory
67 static CVimCF
*cf
= 0;
69 // The single global instance of the application object
72 /* GUIDs, versions and type library information */
73 #define MYCLSID CLSID_Vim
74 #define MYLIBID LIBID_Vim
75 #define MYIID IID_IVim
82 #define MYPROGID "Vim.Application.1"
83 #define MYVIPROGID "Vim.Application"
85 #define MAX_CLSID_LEN 100
87 /*****************************************************************************
88 2. The application object
89 *****************************************************************************/
95 class CVim
: public IVim
99 static CVim
*Create(int *pbDoRestart
);
102 STDMETHOD(QueryInterface
)(REFIID riid
, void ** ppv
);
103 STDMETHOD_(unsigned long, AddRef
)(void);
104 STDMETHOD_(unsigned long, Release
)(void);
107 STDMETHOD(GetTypeInfoCount
)(UINT
*pCount
);
108 STDMETHOD(GetTypeInfo
)(UINT iTypeInfo
, LCID
, ITypeInfo
**ppITypeInfo
);
109 STDMETHOD(GetIDsOfNames
)(const IID
&iid
, OLECHAR
**names
, UINT n
, LCID
, DISPID
*dispids
);
110 STDMETHOD(Invoke
)(DISPID member
, const IID
&iid
, LCID
, WORD flags
, DISPPARAMS
*dispparams
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
);
113 STDMETHOD(SendKeys
)(BSTR keys
);
114 STDMETHOD(Eval
)(BSTR expr
, BSTR
*result
);
115 STDMETHOD(SetForeground
)(void);
116 STDMETHOD(GetHwnd
)(UINT_PTR
*result
);
119 // Constructor is private - create using CVim::Create()
120 CVim() : ref(0), typeinfo(0) {};
125 // The object's TypeInfo
133 CVim
*CVim::Create(int *pbDoRestart
)
137 ITypeLib
*typelib
= 0;
138 ITypeInfo
*typeinfo
= 0;
140 *pbDoRestart
= FALSE
;
146 MessageBox(0, "Cannot create application object", "Vim Initialisation", 0);
150 // Load the type library from the registry
151 hr
= LoadRegTypeLib(MYLIBID
, 1, 0, 0x00, &typelib
);
156 // Check we can write to the registry.
157 // RegCreateKeyEx succeeds even if key exists. W.Briscoe W2K 20021011
158 if (RegCreateKeyEx(HKEY_CLASSES_ROOT
, MYVIPROGID
, 0, NULL
,
159 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, NULL
))
162 return NULL
; // Unable to write to registry. Quietly fail.
166 if (MessageBox(0, "Cannot load registered type library.\nDo you want to register Vim now?",
167 "Vim Initialisation", MB_YESNO
| MB_ICONQUESTION
) != IDYES
)
175 // Load the type library from the registry
176 hr
= LoadRegTypeLib(MYLIBID
, 1, 0, 0x00, &typelib
);
179 MessageBox(0, "You must restart Vim in order for the registration to take effect.",
180 "Vim Initialisation", 0);
187 // Get the type info of the vtable interface
188 hr
= typelib
->GetTypeInfoOfGuid(MYIID
, &typeinfo
);
193 MessageBox(0, "Cannot get interface type information",
194 "Vim Initialisation", 0);
199 // Save the type information
200 me
->typeinfo
= typeinfo
;
206 if (typeinfo
&& vim_parent_hwnd
== NULL
)
212 CVim::QueryInterface(REFIID riid
, void **ppv
)
214 if (IsEqualIID(riid
, IID_IUnknown
) || IsEqualIID(riid
, IID_IDispatch
) || IsEqualIID(riid
, MYIID
))
222 return E_NOINTERFACE
;
234 // Don't delete the object when the reference count reaches zero, as there
235 // is only a single application object, and its lifetime is controlled by
236 // the running instance, not by its reference count.
243 CVim::GetTypeInfoCount(UINT
*pCount
)
250 CVim::GetTypeInfo(UINT iTypeInfo
, LCID
, ITypeInfo
**ppITypeInfo
)
255 return DISP_E_BADINDEX
;
258 *ppITypeInfo
= typeinfo
;
271 return DISP_E_UNKNOWNINTERFACE
;
273 return typeinfo
->GetIDsOfNames(names
, n
, dispids
);
282 DISPPARAMS
*dispparams
,
284 EXCEPINFO
*excepinfo
,
288 return DISP_E_UNKNOWNINTERFACE
;
290 ::SetErrorInfo(0, NULL
);
291 return typeinfo
->Invoke(static_cast<IDispatch
*>(this),
292 member
, flags
, dispparams
,
293 result
, excepinfo
, argerr
);
297 CVim::GetHwnd(UINT_PTR
*result
)
299 *result
= (UINT_PTR
)s_hwnd
;
304 CVim::SetForeground(void)
306 /* Make the Vim window come to the foreground */
307 gui_mch_set_foreground();
312 CVim::SendKeys(BSTR keys
)
319 /* Get a suitable buffer */
320 len
= WideCharToMultiByte(CP_ACP
, 0, keys
, -1, 0, 0, 0, 0);
321 buffer
= (char *)alloc(len
+1);
324 return E_OUTOFMEMORY
;
326 len
= WideCharToMultiByte(CP_ACP
, 0, keys
, -1, buffer
, len
, 0, 0);
334 /* Translate key codes like <Esc> */
335 str
= replace_termcodes((char_u
*)buffer
, &ptr
, FALSE
, TRUE
, FALSE
);
337 /* If ptr was set, then a new buffer was allocated,
338 * so we can free the old one.
341 vim_free((char_u
*)(buffer
));
343 /* Reject strings too long to fit in the input buffer. Allow 10 bytes
344 * space to cover for the (remote) possibility that characters may enter
345 * the input buffer between now and when the WM_OLE message is actually
346 * processed. If more that 10 characters enter the input buffer in that
347 * time, the WM_OLE processing will simply fail to insert the characters.
349 if ((int)(STRLEN(str
)) > (vim_free_in_input_buf() - 10))
355 /* Pass the string to the main input loop. The memory will be freed when
356 * the message is processed. Except for an empty message, we don't need
362 PostMessage(NULL
, WM_OLE
, 0, (LPARAM
)str
);
368 CVim::Eval(BSTR expr
, BSTR
*result
)
376 /* Get a suitable buffer */
377 len
= WideCharToMultiByte(CP_ACP
, 0, expr
, -1, 0, 0, 0, 0);
381 buffer
= (char *)alloc((unsigned)len
);
384 return E_OUTOFMEMORY
;
386 /* Convert the (wide character) expression to an ASCII string */
387 len
= WideCharToMultiByte(CP_ACP
, 0, expr
, -1, buffer
, len
, 0, 0);
391 /* Evaluate the expression */
393 str
= (char *)eval_to_string((char_u
*)buffer
, NULL
, TRUE
);
399 /* Convert the result to wide characters */
400 MultiByteToWideChar_alloc(CP_ACP
, 0, str
, -1, &w_buffer
, &len
);
402 if (w_buffer
== NULL
)
403 return E_OUTOFMEMORY
;
411 /* Store the result */
412 *result
= SysAllocString(w_buffer
);
421 /*****************************************************************************
423 *****************************************************************************/
429 class CVimCF
: public IClassFactory
432 static CVimCF
*Create();
434 STDMETHOD(QueryInterface
)(REFIID riid
, void ** ppv
);
435 STDMETHOD_(unsigned long, AddRef
)(void);
436 STDMETHOD_(unsigned long, Release
)(void);
437 STDMETHOD(CreateInstance
)(IUnknown
*punkOuter
, REFIID riid
, void ** ppv
);
438 STDMETHOD(LockServer
)(BOOL lock
);
441 // Constructor is private - create via Create()
442 CVimCF() : ref(0) {};
452 CVimCF
*CVimCF::Create()
454 CVimCF
*me
= new CVimCF();
457 MessageBox(0, "Cannot create class factory", "Vim Initialisation", 0);
463 CVimCF::QueryInterface(REFIID riid
, void **ppv
)
465 if (IsEqualIID(riid
, IID_IUnknown
) || IsEqualIID(riid
, IID_IClassFactory
))
473 return E_NOINTERFACE
;
485 // Don't delete the object when the reference count reaches zero, as there
486 // is only a single application object, and its lifetime is controlled by
487 // the running instance, not by its reference count.
495 CVimCF::CreateInstance(IUnknown
*punkOuter
, REFIID riid
, void **ppv
)
497 return app
->QueryInterface(riid
, ppv
);
502 CVimCF::LockServer(BOOL lock
)
507 /*****************************************************************************
508 4. Registry manipulation code
509 *****************************************************************************/
512 static void SetKeyAndValue(const char *path
, const char *subkey
, const char *value
);
513 static void GUIDtochar(const GUID
&guid
, char *GUID
, int length
);
514 static void RecursiveDeleteKey(HKEY hKeyParent
, const char *child
);
515 static const int GUID_STRING_SIZE
= 39;
517 // Register the component in the registry
518 // When "silent" is TRUE don't give any messages.
520 extern "C" void RegisterMe(int silent
)
524 // Get the application startup command
525 char module
[MAX_PATH
];
527 ::GetModuleFileName(NULL
, module
, MAX_PATH
);
529 // Unregister first (quietly)
532 // Convert the CLSID into a char
533 char clsid
[GUID_STRING_SIZE
];
534 GUIDtochar(MYCLSID
, clsid
, sizeof(clsid
));
536 // Convert the LIBID into a char
537 char libid
[GUID_STRING_SIZE
];
538 GUIDtochar(MYLIBID
, libid
, sizeof(libid
));
540 // Build the key CLSID\\{...}
541 char Key
[MAX_CLSID_LEN
];
542 strcpy(Key
, "CLSID\\");
545 // Add the CLSID to the registry
546 SetKeyAndValue(Key
, NULL
, MYNAME
);
547 SetKeyAndValue(Key
, "LocalServer32", module
);
548 SetKeyAndValue(Key
, "ProgID", MYPROGID
);
549 SetKeyAndValue(Key
, "VersionIndependentProgID", MYVIPROGID
);
550 SetKeyAndValue(Key
, "TypeLib", libid
);
552 // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT
553 SetKeyAndValue(MYVIPROGID
, NULL
, MYNAME
);
554 SetKeyAndValue(MYVIPROGID
, "CLSID", clsid
);
555 SetKeyAndValue(MYVIPROGID
, "CurVer", MYPROGID
);
557 // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT
558 SetKeyAndValue(MYPROGID
, NULL
, MYNAME
);
559 SetKeyAndValue(MYPROGID
, "CLSID", clsid
);
561 wchar_t w_module
[MAX_PATH
];
562 MultiByteToWideChar(CP_ACP
, 0, module
, -1, w_module
, MAX_PATH
);
564 ITypeLib
*typelib
= NULL
;
565 if (LoadTypeLib(w_module
, &typelib
) != S_OK
)
568 MessageBox(0, "Cannot load type library to register",
569 "Vim Registration", 0);
574 if (RegisterTypeLib(typelib
, w_module
, NULL
) != S_OK
)
577 MessageBox(0, "Cannot register type library",
578 "Vim Registration", 0);
585 MessageBox(0, "Registered successfully", "Vim", 0);
588 // Remove the component from the registry
590 // Note: There is little error checking in this code, to allow incomplete
591 // or failed registrations to be undone.
592 extern "C" void UnregisterMe(int bNotifyUser
)
594 // Unregister the type library
596 if (SUCCEEDED(LoadRegTypeLib(MYLIBID
, MAJORVER
, MINORVER
, LOCALE
, &typelib
)))
599 if (SUCCEEDED(typelib
->GetLibAttr(&tla
)))
601 UnRegisterTypeLib(tla
->guid
, tla
->wMajorVerNum
, tla
->wMinorVerNum
,
602 tla
->lcid
, tla
->syskind
);
603 typelib
->ReleaseTLibAttr(tla
);
608 // Convert the CLSID into a char
609 char clsid
[GUID_STRING_SIZE
];
610 GUIDtochar(MYCLSID
, clsid
, sizeof(clsid
));
612 // Build the key CLSID\\{...}
613 char Key
[MAX_CLSID_LEN
];
614 strcpy(Key
, "CLSID\\");
617 // Delete the CLSID Key - CLSID\{...}
618 RecursiveDeleteKey(HKEY_CLASSES_ROOT
, Key
);
620 // Delete the version-independent ProgID Key
621 RecursiveDeleteKey(HKEY_CLASSES_ROOT
, MYVIPROGID
);
623 // Delete the ProgID key
624 RecursiveDeleteKey(HKEY_CLASSES_ROOT
, MYPROGID
);
627 MessageBox(0, "Unregistered successfully", "Vim", 0);
630 /****************************************************************************/
632 // Convert a GUID to a char string
633 static void GUIDtochar(const GUID
&guid
, char *GUID
, int length
)
635 // Get wide string version
636 LPOLESTR wGUID
= NULL
;
637 StringFromCLSID(guid
, &wGUID
);
639 // Covert from wide characters to non-wide
640 wcstombs(GUID
, wGUID
, length
);
643 CoTaskMemFree(wGUID
);
646 // Delete a key and all of its descendents
647 static void RecursiveDeleteKey(HKEY hKeyParent
, const char *child
)
651 LONG result
= RegOpenKeyEx(hKeyParent
, child
, 0, KEY_ALL_ACCESS
, &hKeyChild
);
652 if (result
!= ERROR_SUCCESS
)
655 // Enumerate all of the decendents of this child
660 while (RegEnumKeyEx(hKeyChild
, 0, buffer
, &size
, NULL
,
661 NULL
, NULL
, &time
) == S_OK
)
663 // Delete the decendents of this child
664 RecursiveDeleteKey(hKeyChild
, buffer
);
669 RegCloseKey(hKeyChild
);
672 RegDeleteKey(hKeyParent
, child
);
675 // Create a key and set its value
676 static void SetKeyAndValue(const char *key
, const char *subkey
, const char *value
)
683 // Add subkey name to buffer.
686 strcat(buffer
, "\\");
687 strcat(buffer
, subkey
);
690 // Create and open key and subkey.
691 long result
= RegCreateKeyEx(HKEY_CLASSES_ROOT
,
693 0, NULL
, REG_OPTION_NON_VOLATILE
,
694 KEY_ALL_ACCESS
, NULL
,
696 if (result
!= ERROR_SUCCESS
)
701 RegSetValueEx(hKey
, NULL
, 0, REG_SZ
, (BYTE
*)value
,
702 (DWORD
)STRLEN(value
)+1);
707 /*****************************************************************************
708 5. OLE Initialisation and shutdown processing
709 *****************************************************************************/
710 extern "C" void InitOLE(int *pbDoRestart
)
714 *pbDoRestart
= FALSE
;
716 // Initialize the OLE libraries
717 hr
= OleInitialize(NULL
);
720 MessageBox(0, "Cannot initialise OLE", "Vim Initialisation", 0);
724 // Create the application object
725 app
= CVim::Create(pbDoRestart
);
729 // Create the class factory
730 cf
= CVimCF::Create();
734 // Register the class factory
735 hr
= CoRegisterClassObject(
744 MessageBox(0, "Cannot register class factory", "Vim Initialisation", 0);
748 // Register the application object as active
749 hr
= RegisterActiveObject(
757 MessageBox(0, "Cannot register application object", "Vim Initialisation", 0);
763 // Errors: tidy up as much as needed and return
770 extern "C" void UninitOLE()
772 // Unregister the application object
775 RevokeActiveObject(app_id
, NULL
);
779 // Unregister the class factory
782 CoRevokeClassObject(cf_id
);
786 // Shut down the OLE libraries
789 // Delete the application object
796 // Delete the class factory
803 #endif /* FEAT_OLE */