if_ole.cpp
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:17k
源码类别:

编辑器/阅读器

开发平台:

DOS

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