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