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