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 } 191 192 STDMETHODIMP 193 CVim::QueryInterface(REFIID riid, void **ppv) 194 { 195 if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch) || IsEqualIID(riid, MYIID)) 196 { 197 AddRef(); 198 *ppv = this; 199 return S_OK; 200 } 201 202 *ppv = 0; 203 return E_NOINTERFACE; 204 } 205 206 STDMETHODIMP_(ULONG) 207 CVim::AddRef() 208 { 209 return ++ref; 210 } 211 212 STDMETHODIMP_(ULONG) 213 CVim::Release() 214 { 215 // Don't delete the object when the reference count reaches zero, as there 216 // is only a single application object, and its lifetime is controlled by 217 // the running instance, not by its reference count. 218 if (ref > 0) 219 --ref; 220 return ref; 221 } 222 223 STDMETHODIMP 224 CVim::GetTypeInfoCount(UINT *pCount) 225 { 226 *pCount = 1; 227 return S_OK; 228 } 229 230 STDMETHODIMP 231 CVim::GetTypeInfo(UINT iTypeInfo, LCID, ITypeInfo **ppITypeInfo) 232 { 233 *ppITypeInfo = 0; 234 235 if (iTypeInfo != 0) 236 return DISP_E_BADINDEX; 237 238 typeinfo->AddRef(); 239 *ppITypeInfo = typeinfo; 240 return S_OK; 241 } 242 243 STDMETHODIMP 244 CVim::GetIDsOfNames( 245 const IID& iid, 246 OLECHAR** names, 247 UINT n, 248 LCID, 249 DISPID *dispids) 250 { 251 if (iid != IID_NULL) 252 return DISP_E_UNKNOWNINTERFACE; 253 254 return typeinfo->GetIDsOfNames(names, n, dispids); 255 } 256 257 STDMETHODIMP 258 CVim::Invoke( 259 DISPID member, 260 const IID& iid, 261 LCID, 262 WORD flags, 263 DISPPARAMS *dispparams, 264 VARIANT *result, 265 EXCEPINFO *excepinfo, 266 UINT *argerr) 267 { 268 if (iid != IID_NULL) 269 return DISP_E_UNKNOWNINTERFACE; 270 271 ::SetErrorInfo(0, NULL); 272 return typeinfo->Invoke(static_cast<IDispatch*>(this), 273 member, flags, dispparams, 274 result, excepinfo, argerr); 275 } 276 277 STDMETHODIMP 278 CVim::GetHwnd(UINT* result) 279 { 280 *result = (UINT) s_hwnd; 281 return S_OK; 282 } 283 284 STDMETHODIMP 285 CVim::SetForeground(void) 286 { 287 /* Make the Vim window come to the foreground */ 288 gui_mch_set_foreground(); 289 return S_OK; 290 } 291 292 STDMETHODIMP 293 CVim::SendKeys(BSTR keys) 294 { 295 int len; 296 char *buffer; 297 char_u *str; 298 char_u *ptr; 299 300 /* Get a suitable buffer */ 301 len = WideCharToMultiByte(CP_ACP, 0, keys, -1, 0, 0, 0, 0); 302 buffer = (char *)alloc(len+1); 303 304 if (buffer == NULL) 305 return E_OUTOFMEMORY; 306 307 len = WideCharToMultiByte(CP_ACP, 0, keys, -1, buffer, len, 0, 0); 308 309 if (len == 0) 310 { 311 vim_free(buffer); 312 return E_INVALIDARG; 313 } 314 315 /* Translate key codes like <Esc> */ 316 str = replace_termcodes((char_u *)buffer, &ptr, FALSE, TRUE); 317 318 /* If ptr was set, then a new buffer was allocated, 319 * so we can free the old one. 320 */ 321 if (ptr) 322 vim_free((char_u *)(buffer)); 323 324 /* Reject strings too long to fit in the input buffer. Allow 10 bytes 325 * space to cover for the (remote) possibility that characters may enter 326 * the input buffer between now and when the WM_OLE message is actually 327 * processed. If more that 10 characters enter the input buffer in that 328 * time, the WM_OLE processing will simply fail to insert the characters. 329 */ 330 if ((int)(STRLEN(str)) > (vim_free_in_input_buf() - 10)) 331 { 332 vim_free(str); 333 return E_INVALIDARG; 334 } 335 336 /* Pass the string to the main input loop. The memory will be freed when 337 * the message is processed. 338 */ 339 PostMessage(NULL, WM_OLE, 0, (LPARAM)str); 340 341 return S_OK; 342 } 343 344 STDMETHODIMP 345 CVim::Eval(BSTR expr, BSTR *result) 346 { 347 #ifdef FEAT_EVAL 348 int len; 349 char *buffer; 350 char *str; 351 wchar_t *w_buffer; 352 353 /* Get a suitable buffer */ 354 len = WideCharToMultiByte(CP_ACP, 0, expr, -1, 0, 0, 0, 0); 355 if (len == 0) 356 return E_INVALIDARG; 357 358 buffer = (char *)alloc((unsigned)len); 359 360 if (buffer == NULL) 361 return E_OUTOFMEMORY; 362 363 /* Convert the (wide character) expression to an ASCII string */ 364 len = WideCharToMultiByte(CP_ACP, 0, expr, -1, buffer, len, 0, 0); 365 if (len == 0) 366 return E_INVALIDARG; 367 368 /* Evaluate the expression */ 369 ++emsg_skip; 370 str = (char *)eval_to_string((char_u *)buffer, NULL); 371 --emsg_skip; 372 vim_free(buffer); 373 if (str == NULL) 374 return E_FAIL; 375 376 /* Convert the result to wide characters */ 377 MultiByteToWideChar_alloc(CP_ACP, 0, str, -1, &w_buffer, &len); 378 vim_free(str); 379 if (w_buffer == NULL) 380 return E_OUTOFMEMORY; 381 382 if (len == 0) 383 { 384 vim_free(w_buffer); 385 return E_FAIL; 386 } 387 388 /* Store the result */ 389 *result = SysAllocString(w_buffer); 390 vim_free(w_buffer); 391 392 return S_OK; 393 #else 394 return E_NOTIMPL; 395 #endif 396 } 397 398 /***************************************************************************** 399 3. The class factory 400 *****************************************************************************/ 401 402 /* Definition 403 * ---------- 404 */ 405 406 class CVimCF : public IClassFactory 407 { 408 public: 409 static CVimCF *Create(); 410 411 STDMETHOD(QueryInterface)(REFIID riid, void ** ppv); 412 STDMETHOD_(unsigned long, AddRef)(void); 413 STDMETHOD_(unsigned long, Release)(void); 414 STDMETHOD(CreateInstance)(IUnknown *punkOuter, REFIID riid, void ** ppv); 415 STDMETHOD(LockServer)(BOOL lock); 416 417 private: 418 // Constructor is private - create via Create() 419 CVimCF() : ref(0) {}; 420 421 // Reference count 422 unsigned long ref; 423 }; 424 425 /* Implementation 426 * -------------- 427 */ 428 429 CVimCF *CVimCF::Create() 430 { 431 CVimCF *me = new CVimCF(); 432 433 if (me == NULL) 434 MessageBox(0, "Cannot create class factory", "Vim Initialisation", 0); 435 436 return me; 437 } 438 439 STDMETHODIMP 440 CVimCF::QueryInterface(REFIID riid, void **ppv) 441 { 442 if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) 443 { 444 AddRef(); 445 *ppv = this; 446 return S_OK; 447 } 448 449 *ppv = 0; 450 return E_NOINTERFACE; 451 } 452 453 STDMETHODIMP_(ULONG) 454 CVimCF::AddRef() 455 { 456 return ++ref; 457 } 458 459 STDMETHODIMP_(ULONG) 460 CVimCF::Release() 461 { 462 // Don't delete the object when the reference count reaches zero, as there 463 // is only a single application object, and its lifetime is controlled by 464 // the running instance, not by its reference count. 465 if (ref > 0) 466 --ref; 467 return ref; 468 } 469 470 STDMETHODIMP 471 CVimCF::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv) 472 { 473 return app->QueryInterface(riid, ppv); 474 } 475 476 STDMETHODIMP 477 CVimCF::LockServer(BOOL lock) 478 { 479 return S_OK; 480 } 481 482 /***************************************************************************** 483 4. Registry manipulation code 484 *****************************************************************************/ 485 486 // Internal use only 487 static void SetKeyAndValue(const char* path, const char* subkey, const char* value); 488 static void GUIDtochar(const GUID& guid, char* GUID, int length); 489 static void RecursiveDeleteKey(HKEY hKeyParent, const char* child); 490 static const int GUID_STRING_SIZE = 39; 491 492 // Register the component in the registry 493 // When "silent" is TRUE don't give any messages. 494 495 extern "C" void RegisterMe(int silent) 496 { 497 BOOL ok = TRUE; 498 499 // Get the application startup command 500 char module[MAX_PATH]; 501 502 ::GetModuleFileName(NULL, module, MAX_PATH); 503 504 // Unregister first (quietly) 505 UnregisterMe(FALSE); 506 507 // Convert the CLSID into a char 508 char clsid[GUID_STRING_SIZE]; 509 GUIDtochar(MYCLSID, clsid, sizeof(clsid)); 510 511 // Convert the LIBID into a char 512 char libid[GUID_STRING_SIZE]; 513 GUIDtochar(MYLIBID, libid, sizeof(libid)); 514 515 // Build the key CLSID\\{...} 516 char Key[MAX_CLSID_LEN]; 517 strcpy(Key, "CLSID\\"); 518 strcat(Key, clsid); 519 520 // Add the CLSID to the registry 521 SetKeyAndValue(Key, NULL, MYNAME); 522 SetKeyAndValue(Key, "LocalServer32", module); 523 SetKeyAndValue(Key, "ProgID", MYPROGID); 524 SetKeyAndValue(Key, "VersionIndependentProgID", MYVIPROGID); 525 SetKeyAndValue(Key, "TypeLib", libid); 526 527 // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT 528 SetKeyAndValue(MYVIPROGID, NULL, MYNAME); 529 SetKeyAndValue(MYVIPROGID, "CLSID", clsid); 530 SetKeyAndValue(MYVIPROGID, "CurVer", MYPROGID); 531 532 // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT 533 SetKeyAndValue(MYPROGID, NULL, MYNAME); 534 SetKeyAndValue(MYPROGID, "CLSID", clsid); 535 536 wchar_t w_module[MAX_PATH]; 537 MultiByteToWideChar(CP_ACP, 0, module, -1, w_module, MAX_PATH); 538 539 ITypeLib *typelib = NULL; 540 if (LoadTypeLib(w_module, &typelib) != S_OK) 541 { 542 if (!silent) 543 MessageBox(0, "Cannot load type library to register", 544 "Vim Registration", 0); 545 ok = FALSE; 546 } 547 else 548 { 549 if (RegisterTypeLib(typelib, w_module, NULL) != S_OK) 550 { 551 if (!silent) 552 MessageBox(0, "Cannot register type library", 553 "Vim Registration", 0); 554 ok = FALSE; 555 } 556 typelib->Release(); 557 } 558 559 if (ok && !silent) 560 MessageBox(0, "Registered successfully", "Vim", 0); 561 } 562 563 // Remove the component from the registry 564 // 565 // Note: There is little error checking in this code, to allow incomplete 566 // or failed registrations to be undone. 567 extern "C" void UnregisterMe(int bNotifyUser) 568 { 569 // Unregister the type library 570 ITypeLib *typelib; 571 if (SUCCEEDED(LoadRegTypeLib(MYLIBID, MAJORVER, MINORVER, LOCALE, &typelib))) 572 { 573 TLIBATTR *tla; 574 if (SUCCEEDED(typelib->GetLibAttr(&tla))) 575 { 576 UnRegisterTypeLib(tla->guid, tla->wMajorVerNum, tla->wMinorVerNum, 577 tla->lcid, tla->syskind); 578 typelib->ReleaseTLibAttr(tla); 579 } 580 typelib->Release(); 581 } 582 583 // Convert the CLSID into a char 584 char clsid[GUID_STRING_SIZE]; 585 GUIDtochar(MYCLSID, clsid, sizeof(clsid)); 586 587 // Build the key CLSID\\{...} 588 char Key[MAX_CLSID_LEN]; 589 strcpy(Key, "CLSID\\"); 590 strcat(Key, clsid); 591 592 // Delete the CLSID Key - CLSID\{...} 593 RecursiveDeleteKey(HKEY_CLASSES_ROOT, Key); 594 595 // Delete the version-independent ProgID Key 596 RecursiveDeleteKey(HKEY_CLASSES_ROOT, MYVIPROGID); 597 598 // Delete the ProgID key 599 RecursiveDeleteKey(HKEY_CLASSES_ROOT, MYPROGID); 600 601 if (bNotifyUser) 602 MessageBox(0, "Unregistered successfully", "Vim", 0); 603 } 604 605 /****************************************************************************/ 606 607 // Convert a GUID to a char string 608 static void GUIDtochar(const GUID& guid, char* GUID, int length) 609 { 610 // Get wide string version 611 LPOLESTR wGUID = NULL; 612 StringFromCLSID(guid, &wGUID); 613 614 // Covert from wide characters to non-wide 615 wcstombs(GUID, wGUID, length); 616 617 // Free memory 618 CoTaskMemFree(wGUID); 619 } 620 621 // Delete a key and all of its descendents 622 static void RecursiveDeleteKey(HKEY hKeyParent, const char* child) 623 { 624 // Open the child 625 HKEY hKeyChild; 626 LONG result = RegOpenKeyEx(hKeyParent, child, 0, KEY_ALL_ACCESS, &hKeyChild); 627 if (result != ERROR_SUCCESS) 628 return; 629 630 // Enumerate all of the decendents of this child 631 FILETIME time; 632 char buffer[1024]; 633 DWORD size = 1024; 634 635 while (RegEnumKeyEx(hKeyChild, 0, buffer, &size, NULL, 636 NULL, NULL, &time) == S_OK) 637 { 638 // Delete the decendents of this child 639 RecursiveDeleteKey(hKeyChild, buffer); 640 size = 256; 641 } 642 643 // Close the child 644 RegCloseKey(hKeyChild); 645 646 // Delete this child 647 RegDeleteKey(hKeyParent, child); 648 } 649 650 // Create a key and set its value 651 static void SetKeyAndValue(const char* key, const char* subkey, const char* value) 652 { 653 HKEY hKey; 654 char buffer[1024]; 655 656 strcpy(buffer, key); 657 658 // Add subkey name to buffer. 659 if (subkey) 660 { 661 strcat(buffer, "\\"); 662 strcat(buffer, subkey); 663 } 664 665 // Create and open key and subkey. 666 long result = RegCreateKeyEx(HKEY_CLASSES_ROOT, 667 buffer, 668 0, NULL, REG_OPTION_NON_VOLATILE, 669 KEY_ALL_ACCESS, NULL, 670 &hKey, NULL); 671 if (result != ERROR_SUCCESS) 672 return; 673 674 // Set the value 675 if (value) 676 RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)value, 677 (DWORD)STRLEN(value)+1); 678 679 RegCloseKey(hKey); 680 } 681 682 /***************************************************************************** 683 5. OLE Initialisation and shutdown processing 684 *****************************************************************************/ 685 extern "C" void InitOLE(int* pbDoRestart) 686 { 687 HRESULT hr; 688 689 *pbDoRestart = FALSE; 690 691 // Initialize the OLE libraries 692 hr = OleInitialize(NULL); 693 if (FAILED(hr)) 694 { 695 MessageBox(0, "Cannot initialise OLE", "Vim Initialisation", 0); 696 goto error0; 697 } 698 699 // Create the application object 700 app = CVim::Create(pbDoRestart); 701 if (app == NULL) 702 goto error1; 703 704 // Create the class factory 705 cf = CVimCF::Create(); 706 if (cf == NULL) 707 goto error1; 708 709 // Register the class factory 710 hr = CoRegisterClassObject( 711 MYCLSID, 712 cf, 713 CLSCTX_LOCAL_SERVER, 714 REGCLS_MULTIPLEUSE, 715 &cf_id); 716 717 if (FAILED(hr)) 718 { 719 MessageBox(0, "Cannot register class factory", "Vim Initialisation", 0); 720 goto error1; 721 } 722 723 // Register the application object as active 724 hr = RegisterActiveObject( 725 app, 726 MYCLSID, 727 NULL, 728 &app_id); 729 730 if (FAILED(hr)) 731 { 732 MessageBox(0, "Cannot register application object", "Vim Initialisation", 0); 733 goto error1; 734 } 735 736 return; 737 738 // Errors: tidy up as much as needed and return 739 error1: 740 UninitOLE(); 741 error0: 742 return; 743 } 744 745 extern "C" void UninitOLE() 746 { 747 // Unregister the application object 748 if (app_id) 749 { 750 RevokeActiveObject(app_id, NULL); 751 app_id = 0; 752 } 753 754 // Unregister the class factory 755 if (cf_id) 756 { 757 CoRevokeClassObject(cf_id); 758 cf_id = 0; 759 } 760 761 // Shut down the OLE libraries 762 OleUninitialize(); 763 764 // Delete the application object 765 if (app) 766 { 767 delete app; 768 app = NULL; 769 } 770 771 // Delete the class factory 772 if (cf) 773 { 774 delete cf; 775 cf = NULL; 776 } 777 } 778 #endif /* FEAT_OLE */ 779