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