home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / w32ole.cpp < prev    next >
C/C++ Source or Header  |  1998-10-01  |  16KB  |  675 lines

  1. /*
  2.  * w32ole.cpp:  Winvile's OLE implementation (the editor currently
  3.  *              supports only OLE Automation).
  4.  *
  5.  * Note:  A great deal of the code included in this file was copied from
  6.  * the Microsoft platform sdk samples directory, specifically from:
  7.  *
  8.  *    samples\com\oleaut\hello\hello .
  9.  *
  10.  * However, this implementation handles the Release() methods quite
  11.  * differently and so, I wouldn't use this code as a guide for writing
  12.  * any other automation servers :-) .
  13.  *
  14.  * Caveats
  15.  * =======
  16.  * - Due to a conflict between estruct.h and MS names, the Windows macros
  17.  *   "FAILED" may not be used to test an OLE return code.  Use SUCCEEDED
  18.  *   instead.
  19.  *
  20.  * $Header: /usr/build/vile/vile/RCS/w32ole.cpp,v 1.5 1998/10/01 10:31:26 cmorgan Exp $
  21.  */
  22.  
  23. #include <windows.h>
  24. #include <ole2.h>
  25. #include <assert.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28.  
  29. extern "C"
  30. {
  31.     #include "estruct.h"
  32.     #undef FAILED          /* Don't want this defn of FAILED */
  33.     #include "edef.h"
  34. }
  35. #include "w32ole.h"
  36. #include "w32reg.h"
  37.  
  38.  
  39. static size_t   ansibuf_len,   /* scaled in bytes   */
  40.                 olebuf_len;    /* scaled in wchar_t */
  41. static char     *ansibuf;
  42. static DWORD    dwRegisterCF, dwRegisterActiveObj;
  43. static vile_oa  *g_pvile_oa;
  44. static int      oleauto_server;
  45. static OLECHAR  *olebuf;
  46.  
  47. /* ------------------------ C Linkage Helpers ---------------------- */
  48.  
  49. extern "C"
  50. {
  51.  
  52. int
  53. oleauto_init(OLEAUTO_OPTIONS *opts)
  54. {
  55.     char           *dummy = NULL;
  56.     HRESULT        hr;
  57.     LPCLASSFACTORY pcf = NULL;
  58.  
  59.     olebuf_len = ansibuf_len = 512;
  60.     ansibuf    = (char *) malloc(ansibuf_len);
  61.     olebuf     = (OLECHAR *) malloc(olebuf_len * sizeof(OLECHAR));
  62.     if (! (olebuf && ansibuf))
  63.         return (FALSE);
  64.  
  65.     hr = OleInitialize(NULL);   // Intialize OLE
  66.     if (! SUCCEEDED(hr))
  67.     {
  68.         disp_win32_error(hr, NULL);
  69.         return (FALSE);
  70.     }
  71.  
  72.     oleauto_server = TRUE;
  73.  
  74.     // Create an instance of the Vile Application object. Object is
  75.     // created with refcount 0.
  76.     if (! SUCCEEDED(vile_oa::Create(&g_pvile_oa, ! opts->invisible)))
  77.         return (FALSE);
  78.  
  79.     // Expose class factory for application object.
  80.     pcf = new vile_oa_cf;
  81.     if (! pcf)
  82.         return (FALSE);
  83.     pcf->AddRef();
  84.     hr = CoRegisterClassObject(CLSID_VileAuto,
  85.                                pcf,
  86.                                CLSCTX_LOCAL_SERVER,
  87.                     (opts->multiple) ? REGCLS_SINGLEUSE : REGCLS_MULTIPLEUSE,
  88.                                &dwRegisterCF);
  89.     pcf->Release();
  90.     if (! SUCCEEDED(hr))
  91.     {
  92.         disp_win32_error(hr, NULL);
  93.         return (FALSE);
  94.     }
  95.  
  96.     /*
  97.      * Register Vile application object in the Running Object Table (ROT).
  98.      * This allows controllers to connect to a running application object
  99.      * instead of creating a new instance.  Use weak registration so that
  100.      * the ROT releases it's reference when all external references are
  101.      * released.  If strong registration is used, the ROT will not release
  102.      * it's reference until RevokeActiveObject is called and so will keep
  103.      * the object alive even after all external references have been
  104.      * released.
  105.      */
  106.     hr = RegisterActiveObject(g_pvile_oa,
  107.                               CLSID_VileAuto,
  108.                               ACTIVEOBJECT_WEAK,
  109.                               &dwRegisterActiveObj);
  110.     if (! SUCCEEDED(hr))
  111.     {
  112.         disp_win32_error(hr, NULL);
  113.         return (FALSE);
  114.     }
  115.     if (! opts->invisible)
  116.     {
  117.         hr = CoLockObjectExternal(g_pvile_oa, TRUE, TRUE);
  118.         if (! SUCCEEDED(hr))
  119.         {
  120.             disp_win32_error(hr, NULL);
  121.             return (FALSE);
  122.         }
  123.     }
  124.     return (TRUE);
  125. }
  126.  
  127. void
  128. oleauto_exit(int code)
  129. {
  130.     if (ansibuf)
  131.         free(ansibuf);
  132.     if (olebuf)
  133.         free(olebuf);
  134.     if (oleauto_server)
  135.     {
  136.         if (g_pvile_oa)
  137.         {
  138.             /*
  139.              * For a local server, CoDisconnectObject will disconnect the
  140.              * object from external connections.  So the controller will
  141.              * get an RPC error if it accesses the object after calling
  142.              * Quit and the controller will not GP fault.
  143.              */
  144.  
  145.             CoDisconnectObject(g_pvile_oa, 0);
  146.             delete g_pvile_oa;
  147.         }
  148.         if (dwRegisterCF != 0)
  149.             CoRevokeClassObject(dwRegisterCF);
  150.         if (dwRegisterActiveObj != 0)
  151.             RevokeActiveObject(dwRegisterActiveObj, NULL);
  152.         OleUninitialize();
  153.     }
  154.     exit(code);
  155. }
  156.  
  157. } /* Extern "C" */
  158.  
  159. /* ----------------------- C++ Helper Functions --------------------- */
  160.  
  161. /*
  162.  * Quick & Dirty ANSI/Unicode conversion routines.  These routines use a
  163.  * dynamic buffer to hold the converted string so it may be any arbitrary
  164.  * size.  However, the same dynamic buffer is reused when the routine is
  165.  * called a second time.  So make sure that the converted string is
  166.  * used/copied before the conversion routine is called again.
  167.  *
  168.  */
  169. #if (! defined(_UNICODE) || defined(UNICODE))
  170. char *
  171. ConvertToAnsi(OLECHAR *szW)
  172. {
  173.     size_t len;
  174.  
  175.     len = wcstombs(NULL, szW, 1) + 1;
  176.     if (len > ansibuf_len)
  177.     {
  178.         if (ansibuf)
  179.             free(ansibuf);
  180.         ansibuf_len = ansibuf_len * 2 + len;
  181.         if ((ansibuf = (char *) malloc(ansibuf_len)) == NULL)
  182.             return (ansibuf);  /* We're gonna' die */
  183.     }
  184.     wcstombs(ansibuf, szW, len);
  185.     return (ansibuf);
  186. }
  187.  
  188. OLECHAR *
  189. ConvertToUnicode(char *szA)
  190. {
  191.     size_t len;
  192.  
  193.     len = strlen(szA) + 1;
  194.     if (len > olebuf_len)
  195.     {
  196.         if (olebuf)
  197.             free(olebuf);
  198.         olebuf_len = olebuf_len * 2 + len;
  199.         if ((olebuf = (OLECHAR *) malloc(olebuf_len * sizeof(OLECHAR))) == NULL)
  200.             return (olebuf);  /* We're gonna' die */
  201.     }
  202.     mbstowcs(olebuf, szA, len);
  203.     return (olebuf);
  204. }
  205. #endif
  206.  
  207. HRESULT
  208. LoadTypeInfo(ITypeInfo **pptinfo, REFCLSID clsid)
  209. {
  210.     HRESULT hr;
  211.     LPTYPELIB ptlib = NULL;
  212.     LPTYPEINFO ptinfo = NULL;
  213.  
  214.     *pptinfo = NULL;
  215.  
  216.     hr = LoadRegTypeLib(LIBID_VileAuto, VTL_MAJOR, VTL_MINOR, 0x09, &ptlib);
  217.     if (! SUCCEEDED(hr))
  218.         return hr;
  219.  
  220.     // Get type information for interface of the object.
  221.     hr = ptlib->GetTypeInfoOfGuid(clsid, &ptinfo);
  222.     ptlib->Release();
  223.     if (! SUCCEEDED(hr))
  224.         return hr;
  225.  
  226.     *pptinfo = ptinfo;
  227.     return NOERROR;
  228. }
  229.  
  230. /* ------------------------ Class Factory -------------------------- */
  231.  
  232. vile_oa_cf::vile_oa_cf(void)
  233. {
  234.     m_cRef = 0;
  235. }
  236.  
  237. STDMETHODIMP
  238. vile_oa_cf::QueryInterface(REFIID iid, void **ppv)
  239. {
  240.     *ppv = NULL;
  241.  
  242.     if (iid == IID_IUnknown || iid == IID_IClassFactory)
  243.         *ppv = this;
  244.     else
  245.         return E_NOINTERFACE;
  246.  
  247.     AddRef();
  248.     return NOERROR;
  249. }
  250.  
  251. STDMETHODIMP_(ULONG)
  252. vile_oa_cf::AddRef(void)
  253. {
  254.     return ++m_cRef;
  255. }
  256.  
  257. STDMETHODIMP_(ULONG)
  258. vile_oa_cf::Release(void)
  259. {
  260.     if(--m_cRef == 0)
  261.     {
  262.         delete this;
  263.         return 0;
  264.     }
  265.     return m_cRef;
  266. }
  267.  
  268. STDMETHODIMP
  269. vile_oa_cf::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  270. {
  271.     HRESULT hr;
  272.  
  273.     *ppv = NULL;
  274.  
  275.     // This implementation doesn't allow aggregation
  276.     if (punkOuter)
  277.         return CLASS_E_NOAGGREGATION;
  278.  
  279.     /*
  280.      * If this is a REGCLS_SINGLEUSE class factory, CreateInstance will be
  281.      * called at most once.  The global application object has already been
  282.      * created when CreateInstance is called.  A REGCLS_MULTIPLEUSE class
  283.      * factory's CreateInstance would be called multiple times and would
  284.      * create a new object each time.
  285.      */
  286.     hr = g_pvile_oa->QueryInterface(riid, ppv);
  287.     if (!  SUCCEEDED(hr))
  288.     {
  289.         g_pvile_oa->Quit();
  290.         return hr;
  291.     }
  292.     return (NOERROR);
  293. }
  294.  
  295. STDMETHODIMP
  296. vile_oa_cf::LockServer(BOOL fLock)
  297. {
  298.     HRESULT hr;
  299.  
  300.     hr = CoLockObjectExternal(g_pvile_oa, fLock, TRUE);
  301.     if (! SUCCEEDED(hr))
  302.         disp_win32_error(hr, NULL);
  303.     return (hr);
  304. }
  305.  
  306. /* ------------------------------- vile_oa ------------------------------ */
  307.  
  308. HRESULT
  309. vile_oa::Create(vile_oa **ppvile, BOOL visible)
  310. {
  311.     HRESULT hr;
  312.     vile_oa *pvile = NULL;
  313.     OLECHAR *tmp;
  314.  
  315.     *ppvile = NULL;
  316.  
  317.     // Create Application object
  318.     pvile = new vile_oa();
  319.     if (pvile == NULL)
  320.         return E_OUTOFMEMORY;
  321.  
  322.     pvile->m_hwnd     = (HWND) winvile_hwnd();
  323.     pvile->m_bVisible = (visible) ? VARIANT_TRUE : VARIANT_FALSE;
  324.  
  325.     // Name
  326.     tmp = TO_OLE_STRING(prognam);
  327.     if (! (tmp && (pvile->m_bstrName = SysAllocString(tmp))))
  328.         return E_OUTOFMEMORY;
  329.  
  330.     // Load type information from type library.
  331.     hr = LoadTypeInfo(&pvile->m_ptinfo, IID_IVileAuto);
  332.     if (! SUCCEEDED(hr))
  333.     {
  334.         MessageBox(pvile->m_hwnd,
  335. "Cannot load type library.\r\r Register type info using winvile's '-Or' command line switch",
  336.                    prognam,
  337.                    MB_OK | MB_ICONSTOP);
  338.         return (hr);
  339.     }
  340.  
  341.     *ppvile = pvile;
  342.     return NOERROR;
  343. }
  344.  
  345. vile_oa::vile_oa()
  346. {
  347.     m_bstrFullName = NULL;
  348.     m_bstrName     = NULL;
  349.     m_ptinfo       = NULL;
  350.     m_cRef         = 0;
  351. }
  352.  
  353. vile_oa::~vile_oa()
  354. {
  355.     if (m_bstrFullName) SysFreeString(m_bstrFullName);
  356.     if (m_bstrName)     SysFreeString(m_bstrName);
  357.     if (m_ptinfo)       m_ptinfo->Release();
  358. }
  359.  
  360. STDMETHODIMP
  361. vile_oa::QueryInterface(REFIID iid, void **ppv)
  362. {
  363.     *ppv = NULL;
  364.  
  365.     if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IVileAuto)
  366.         *ppv = this;
  367.     else
  368.         return E_NOINTERFACE;
  369.  
  370.     AddRef();
  371.     return NOERROR;
  372. }
  373.  
  374.  
  375. STDMETHODIMP_(ULONG)
  376. vile_oa::AddRef(void)
  377. {
  378.     return (++m_cRef);
  379. }
  380.  
  381. STDMETHODIMP_(ULONG)
  382. vile_oa::Release(void)
  383. {
  384.     if (--m_cRef == 0)
  385.         PostQuitMessage(0);
  386.     return (m_cRef);
  387. }
  388.  
  389. STDMETHODIMP
  390. vile_oa::GetTypeInfoCount(UINT *pctinfo)
  391. {
  392.     *pctinfo = 1;
  393.     return NOERROR;
  394. }
  395.  
  396. STDMETHODIMP
  397. vile_oa::GetTypeInfo(
  398.       UINT itinfo,
  399.       LCID lcid,
  400.       ITypeInfo **pptinfo)
  401. {
  402.     *pptinfo = NULL;
  403.  
  404.     if(itinfo != 0)
  405.         return DISP_E_BADINDEX;
  406.  
  407.     m_ptinfo->AddRef();
  408.     *pptinfo = m_ptinfo;
  409.  
  410.     return NOERROR;
  411. }
  412.  
  413. STDMETHODIMP
  414. vile_oa::GetIDsOfNames(
  415.       REFIID riid,
  416.       OLECHAR **rgszNames,
  417.       UINT cNames,
  418.       LCID lcid,
  419.       DISPID *rgdispid)
  420. {
  421.     return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);
  422. }
  423.  
  424. STDMETHODIMP
  425. vile_oa::Invoke(
  426.       DISPID dispidMember,
  427.       REFIID riid,
  428.       LCID lcid,
  429.       WORD wFlags,
  430.       DISPPARAMS *pdispparams,
  431.       VARIANT *pvarResult,
  432.       EXCEPINFO *pexcepinfo,
  433.       UINT *puArgErr)
  434. {
  435.     return DispInvoke(
  436.         this, m_ptinfo,
  437.         dispidMember, wFlags, pdispparams,
  438.         pvarResult, pexcepinfo, puArgErr);
  439. }
  440.  
  441. STDMETHODIMP
  442. vile_oa::get_Application(IVileAuto **ppvile)
  443. {
  444.     HRESULT hr;
  445.  
  446.     *ppvile = NULL;
  447.  
  448.     hr = QueryInterface(IID_IDispatch, (void **)ppvile);
  449.     return ((SUCCEEDED(hr)) ? NOERROR : E_UNEXPECTED);
  450. }
  451.  
  452. STDMETHODIMP
  453. vile_oa::get_FullName(BSTR *pbstr)
  454. {
  455.     if (! m_bstrFullName)
  456.     {
  457.         char    *cp, key[NFILEN];
  458.         HKEY    hk;
  459.         long    rc;
  460.         DWORD   regtype = REG_SZ;
  461.         OLECHAR *tmp;
  462.         BYTE    value[NFILEN * 2];
  463.         ULONG   val_len;
  464.  
  465.         *pbstr  = NULL;
  466.         val_len = sizeof(value);
  467.  
  468.         /* Extract server path from registry. */
  469.         sprintf(key, "CLSID\\%s\\LocalServer32", CLSID_VILEAUTO_KEY);
  470.         if (RegOpenKeyEx(HKEY_CLASSES_ROOT,
  471.                          key,
  472.                          0,
  473.                          KEY_QUERY_VALUE,
  474.                          &hk) != ERROR_SUCCESS)
  475.         {
  476.             disp_win32_error(W32_SYS_ERROR, m_hwnd);
  477.             return (E_UNEXPECTED);
  478.         }
  479.         rc = RegQueryValueEx(hk, NULL, NULL, ®type, value, &val_len);
  480.         RegCloseKey(hk);
  481.         if (rc != ERROR_SUCCESS)
  482.         {
  483.             disp_win32_error(W32_SYS_ERROR, m_hwnd);
  484.             return (E_UNEXPECTED);
  485.         }
  486.         if ((cp = strchr((char *) value, ' ')) != NULL)
  487.             *cp = '\0';
  488.         tmp = TO_OLE_STRING((char *) value);
  489.         if (! (tmp && (m_bstrFullName = SysAllocString(tmp))))
  490.             return (E_OUTOFMEMORY);
  491.     }
  492.     *pbstr = SysAllocString(m_bstrFullName);
  493.     return ((*pbstr) ? NOERROR : E_OUTOFMEMORY);
  494. }
  495.  
  496. STDMETHODIMP
  497. vile_oa::get_Name(BSTR *pbstr)
  498. {
  499.     *pbstr = SysAllocString(m_bstrName);
  500.     return ((*pbstr) ? NOERROR : E_OUTOFMEMORY);
  501. }
  502.  
  503. STDMETHODIMP
  504. vile_oa::get_Parent(IVileAuto **ppvile)
  505. {
  506.     HRESULT hr;
  507.  
  508.     *ppvile = NULL;
  509.  
  510.     hr = QueryInterface(IID_IDispatch, (void **)ppvile);
  511.     return ((SUCCEEDED(hr)) ? NOERROR : E_UNEXPECTED);
  512. }
  513.  
  514. STDMETHODIMP
  515. vile_oa::Quit()
  516. {
  517.     PostQuitMessage(0);
  518.     return NOERROR;
  519. }
  520.  
  521. STDMETHODIMP
  522. vile_oa::VileKeys(BSTR keys)
  523. {
  524.     HRESULT hr   = NOERROR;
  525.     char    *msg = FROM_OLE_STRING(keys);
  526.  
  527.     while (*msg)
  528.     {
  529.         if (! PostMessage(m_hwnd, WM_CHAR, *msg, 0))
  530.         {
  531.             disp_win32_error(W32_SYS_ERROR, m_hwnd);
  532.             hr = E_UNEXPECTED;
  533.             break;
  534.         }
  535.         msg++;
  536.     }
  537.     return (hr);
  538. }
  539.  
  540. STDMETHODIMP
  541. vile_oa::put_Visible(VARIANT_BOOL bVisible)
  542. {
  543.     if (bVisible != m_bVisible)
  544.     {
  545.         HRESULT hr;
  546.  
  547.         m_bVisible = bVisible;
  548.         hr = CoLockObjectExternal(this, (m_bVisible) ? TRUE : FALSE, TRUE);
  549.         if (! SUCCEEDED(hr))
  550.         {
  551.             disp_win32_error(hr, m_hwnd);
  552.             return (hr);
  553.         }
  554.         ::ShowWindow(m_hwnd, bVisible ? SW_SHOW : SW_HIDE);
  555.     }
  556.     return (NOERROR);
  557. }
  558.  
  559. STDMETHODIMP
  560. vile_oa::get_Visible(VARIANT_BOOL *pbool)
  561. {
  562.     *pbool = m_bVisible;
  563.     return NOERROR;
  564. }
  565.  
  566. STDMETHODIMP
  567. vile_oa::get_IsMinimized(VARIANT_BOOL *pbool)
  568. {
  569.     WINDOWPLACEMENT wp;
  570.  
  571.     wp.length = sizeof(wp);
  572.     if (! GetWindowPlacement(m_hwnd, &wp))
  573.         return (GetLastError());
  574.     *pbool = (wp.showCmd == SW_MINIMIZE ||
  575.               wp.showCmd == SW_SHOWMINIMIZED ||
  576.               wp.showCmd == SW_SHOWMINNOACTIVE) ? VARIANT_TRUE : VARIANT_FALSE;
  577.     return NOERROR;
  578. }
  579.  
  580. STDMETHODIMP
  581. vile_oa::get_InsertMode(VARIANT_BOOL *pbool)
  582. {
  583.     *pbool = (insertmode) ? VARIANT_TRUE : VARIANT_FALSE;
  584.     return NOERROR;
  585. }
  586.  
  587. STDMETHODIMP
  588. vile_oa::ForegroundWindow()
  589. {
  590.     if (! m_bVisible)
  591.         put_Visible(TRUE);   /* Force window to be visible, first. */
  592.     ::SetForegroundWindow(m_hwnd);
  593.     return NOERROR;
  594. }
  595.  
  596. STDMETHODIMP
  597. vile_oa::Minimize()
  598. {
  599.     ::ShowWindow(m_hwnd, SW_MINIMIZE);
  600.     if (! m_bVisible)
  601.     {
  602.         /*
  603.          * Minimizing an invisible window will make it visible, so keep the
  604.          * m_bVisible bookkeeping up-to-date.
  605.          */
  606.  
  607.         put_Visible(TRUE);
  608.     }
  609.     return NOERROR;
  610. }
  611.  
  612. STDMETHODIMP
  613. vile_oa::Restore()
  614. {
  615.     ::ShowWindow(m_hwnd, SW_RESTORE);
  616.     if (! m_bVisible)
  617.     {
  618.         /*
  619.          * Restoring an invisible window will make it visible, so keep the
  620.          * m_bVisible bookkeeping up-to-date.
  621.          */
  622.  
  623.         put_Visible(TRUE);
  624.     }
  625.     return NOERROR;
  626. }
  627.  
  628. /* ----------- C Linkage To OLE-specific Editor Functions ---------------- */
  629.  
  630. extern "C"
  631. {
  632.  
  633. /*
  634.  * Wait for a file to spring into existence with > 0 bytes of data.  This
  635.  * editor function is used to work around a bug in DevStudio 5, which
  636.  * creates its build log _after_ notifying visvile that a build is complete.
  637.  */
  638. int
  639. waitfile(int f, int n)
  640. {
  641. #define SLEEP_INCR 100
  642.  
  643.     char         fname[NFILEN];  /* wait for this file */
  644.     DWORD        how_long, curr_sleep;
  645.     int          s;              /* status return */
  646.     struct _stat statdata;
  647.  
  648.     fname[0] = '\0';
  649.     how_long = (f) ? n : 2000;  /* If wait period not specified as argument,
  650.                                  * wait up to 2 seconds.
  651.                                  */
  652.     if ((s = mlreply_no_opts("Wait for file: ", fname, sizeof(fname))) == TRUE)
  653.     {
  654.         curr_sleep = 0;
  655.         for (;;)
  656.         {
  657.             if (_stat(fname, &statdata) == 0)
  658.             {
  659.                 if (statdata.st_size > 0)
  660.                     break;
  661.             }
  662.             Sleep(SLEEP_INCR);
  663.             curr_sleep += SLEEP_INCR;
  664.             if (curr_sleep > how_long)
  665.             {
  666.                 mlwrite("timed out waiting for \"%s\"", fname);
  667.                 break;
  668.             }
  669.         }
  670.     }
  671.     return (s);
  672. }
  673.  
  674. } /* Extern "C" */
  675.