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