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