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