home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / DIConfig / privcom.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  13.9 KB  |  512 lines

  1. #include "common.hpp"
  2.  
  3.  
  4. /*****************************************************************************
  5.  *
  6.  *  privcom.c
  7.  *
  8.  *  Copyright (c) 2000 Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  *  Abstract:
  11.  *
  12.  *      Functions that sort-of duplicate what OLE does.
  13.  *
  14.  *        Adapted from dinput\dx8\dll\dioledup.c
  15.  *
  16.  *****************************************************************************/
  17.  
  18.  
  19.     typedef LPUNKNOWN PUNK;
  20.     typedef LPVOID PV, *PPV;
  21.     typedef CONST VOID *PCV;
  22.     typedef REFIID RIID;
  23.     typedef CONST GUID *PCGUID;
  24.  
  25.     /*
  26.      * Convert an object (X) to a count of bytes (cb).
  27.      */
  28. #define cbX(X) sizeof(X)
  29.  
  30.     /*
  31.      * Convert an array name (A) to a generic count (c).
  32.      */
  33. #define cA(a) (cbX(a)/cbX(a[0]))
  34.  
  35.     /*
  36.      * Convert a count of X's (cx) into a count of bytes
  37.      * and vice versa.
  38.      */
  39. #define  cbCxX(cx, X) ((cx) * cbX(X))
  40. #define  cxCbX(cb, X) ((cb) / cbX(X))
  41.  
  42.     /*
  43.      * Convert a count of chars (cch), tchars (ctch), wchars (cwch),
  44.      * or dwords (cdw) into a count of bytes, and vice versa.
  45.      */
  46. #define  cbCch(cch)  cbCxX( cch,  CHAR)
  47. #define cbCwch(cwch) cbCxX(cwch, WCHAR)
  48. #define cbCtch(ctch) cbCxX(ctch, TCHAR)
  49. #define  cbCdw(cdw)  cbCxX( cdw, DWORD)
  50.  
  51. #define  cchCb(cb) cxCbX(cb,  CHAR)
  52. #define cwchCb(cb) cxCbX(cb, WCHAR)
  53. #define ctchCb(cb) cxCbX(cb, TCHAR)
  54. #define  cdwCb(cb) cxCbX(cb, DWORD)
  55.  
  56. // yay
  57. #define ctchGuid    (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
  58.  
  59. /*****************************************************************************
  60.  *
  61.  *  _ParseHex
  62.  *
  63.  *      Parse a hex string encoding cb bytes (at most 4), then
  64.  *      expect the tchDelim to appear afterwards.  If chDelim is 0,
  65.  *      then no delimiter is expected.
  66.  *
  67.  *      Store the result into the indicated LPBYTE (using only the
  68.  *      size requested), updating it, and return a pointer to the
  69.  *      next unparsed character, or 0 on error.
  70.  *
  71.  *      If the incoming pointer is also 0, then return 0 immediately.
  72.  *
  73.  *****************************************************************************/
  74.  
  75. LPCTSTR 
  76.     _ParseHex(LPCTSTR ptsz, LPBYTE *ppb, int cb, TCHAR tchDelim)
  77. {
  78.     if(ptsz)
  79.     {
  80.         int i = cb * 2;
  81.         DWORD dwParse = 0;
  82.  
  83.         do
  84.         {
  85.             DWORD uch;
  86.             uch = (TBYTE)*ptsz - TEXT('0');
  87.             if(uch < 10)
  88.             {             /* a decimal digit */
  89.             } else
  90.             {
  91.                 uch = (*ptsz | 0x20) - TEXT('a');
  92.                 if(uch < 6)
  93.                 {          /* a hex digit */
  94.                     uch += 10;
  95.                 } else
  96.                 {
  97.                     return 0;           /* Parse error */
  98.                 }
  99.             }
  100.             dwParse = (dwParse << 4) + uch;
  101.             ptsz++;
  102.         } while(--i);
  103.  
  104.         if(tchDelim && *ptsz++ != tchDelim) return 0; /* Parse error */
  105.  
  106.         for(i = 0; i < cb; i++)
  107.         {
  108.             (*ppb)[i] = ((LPBYTE)&dwParse)[i];
  109.         }
  110.         *ppb += cb;
  111.     }
  112.     return ptsz;
  113. }
  114.  
  115. /*****************************************************************************
  116.  *
  117.  *  @doc    INTERNAL
  118.  *
  119.  *  @func   BOOL | ParseGUID |
  120.  *
  121.  *          Take a string and convert it into a GUID, return success/failure.
  122.  *
  123.  *  @parm   OUT LPGUID | lpGUID |
  124.  *
  125.  *          Receives the parsed GUID on success.
  126.  *
  127.  *  @parm   IN LPCTSTR | ptsz |
  128.  *
  129.  *          The string to parse.  The format is
  130.  *
  131.  *      { <lt>dword<gt> - <lt>word<gt> - <lt>word<gt>
  132.  *                      - <lt>byte<gt> <lt>byte<gt>
  133.  *                      - <lt>byte<gt> <lt>byte<gt> <lt>byte<gt>
  134.  *                        <lt>byte<gt> <lt>byte<gt> <lt>byte<gt> }
  135.  *
  136.  *  @returns
  137.  *
  138.  *          Returns zero if <p ptszGUID> is not a valid GUID.
  139.  *
  140.  *
  141.  *  @comm
  142.  *
  143.  *          Stolen from TweakUI.
  144.  *
  145.  *****************************************************************************/
  146.  
  147. BOOL 
  148.     ParseGUID(LPGUID pguid, LPCTSTR ptsz)
  149. {
  150.     if(lstrlen(ptsz) == ctchGuid - 1 && *ptsz == TEXT('{'))
  151.     {
  152.         ptsz++;
  153.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 4, TEXT('-'));
  154.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  155.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
  156.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  157.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('-'));
  158.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  159.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  160.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  161.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  162.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1,       0  );
  163.         ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('}'));
  164.         return (BOOL)(UINT_PTR)ptsz;
  165.     } else
  166.     {
  167.         return 0;
  168.     }
  169. }
  170.  
  171. /*****************************************************************************
  172.  *
  173.  *  @doc    INTERNAL
  174.  *
  175.  *  @func   LONG | RegQueryString |
  176.  *
  177.  *          Wrapper for <f RegQueryValueEx> that reads a
  178.  *          string value from the registry.  An annoying quirk
  179.  *          is that on Windows NT, the returned string might
  180.  *          not end in a null terminator, so we might need to add
  181.  *          one manually.
  182.  *
  183.  *  @parm   IN HKEY | hk |
  184.  *
  185.  *          Parent registry key.
  186.  *
  187.  *  @parm   LPCTSTR | ptszValue |
  188.  *
  189.  *          Value name.
  190.  *
  191.  *  @parm   LPTSTR | ptsz |
  192.  *
  193.  *          Output buffer.
  194.  *
  195.  *  @parm   DWORD | ctchBuf |
  196.  *
  197.  *          Size of output buffer.
  198.  *
  199.  *  @returns
  200.  *
  201.  *          Registry error code.
  202.  *
  203.  *****************************************************************************/
  204.  
  205. LONG 
  206.     RegQueryString(HKEY hk, LPCTSTR ptszValue, LPTSTR ptszBuf, DWORD ctchBuf)
  207. {
  208.     LONG lRc;
  209.     DWORD reg;
  210.  
  211.     #ifdef UNICODE
  212.     DWORD cb;
  213.  
  214.     /*
  215.      *  NT quirk: Non-null terminated strings can exist.
  216.      */
  217.     cb = cbCtch(ctchBuf);
  218.     lRc = RegQueryValueEx(hk, ptszValue, 0, ®, (LPBYTE)(PV)ptszBuf, &cb);
  219.     if(lRc == ERROR_SUCCESS)
  220.     {
  221.         if(reg == REG_SZ)
  222.         {
  223.             /*
  224.              *  Check the last character.  If it is not NULL, then
  225.              *  append a NULL if there is room.
  226.              */
  227.             DWORD ctch = ctchCb(cb);
  228.             if(ctch == 0)
  229.             {
  230.                 ptszBuf[ctch] = TEXT('\0');
  231.             } else if(ptszBuf[ctch-1] != TEXT('\0'))
  232.             {
  233.                 if(ctch < ctchBuf)
  234.                 {
  235.                     ptszBuf[ctch] = TEXT('\0');
  236.                 } else
  237.                 {
  238.                     lRc = ERROR_MORE_DATA;
  239.                 }
  240.             }
  241.         } else
  242.         {
  243.             lRc = ERROR_INVALID_DATA;
  244.         }
  245.     }
  246.  
  247.  
  248.     #else
  249.  
  250.     /*
  251.      *  This code is executed only on Win95, so we don't have to worry
  252.      *  about the NT quirk.
  253.      */
  254.  
  255.     lRc = RegQueryValueEx(hk, ptszValue, 0, ®, (LPBYTE)(PV)ptszBuf, &ctchBuf);
  256.  
  257.     if(lRc == ERROR_SUCCESS && reg != REG_SZ)
  258.     {
  259.         lRc = ERROR_INVALID_DATA;
  260.     }
  261.  
  262.  
  263.     #endif
  264.  
  265.     return lRc;
  266. }
  267.  
  268. /*****************************************************************************
  269.  *
  270.  *  @doc    INTERNAL
  271.  *
  272.  *  @func   HRESULT | _CreateInstance |
  273.  *
  274.  *          Worker function for <f DICoCreateInstance>.
  275.  *
  276.  *  @parm   REFCLSID | rclsid |
  277.  *
  278.  *          The <t CLSID> to create.
  279.  *
  280.  *  @parm   LPCTSTR | ptszDll |
  281.  *
  282.  *          The name of the DLL to load.
  283.  *
  284.  *  @parm   LPUNKNOWN | punkOuter |
  285.  *
  286.  *          Controlling unknown for aggregation.
  287.  *
  288.  *  @parm   RIID | riid |
  289.  *
  290.  *          Interface to obtain.
  291.  *
  292.  *  @parm   PPV | ppvOut |
  293.  *
  294.  *          Receives a pointer to the created object if successful.
  295.  *
  296.  *  @parm   HINSTANCE * | phinst |
  297.  *
  298.  *          Receives the instance handle of the in-proc DLL that was
  299.  *          loaded.  <f FreeLibrary> this DLL when you are finished
  300.  *          with the object.
  301.  *
  302.  *          Note that since we don't implement a binder, this means
  303.  *          that you cannot give the returned pointer away to anybody
  304.  *          you don't control; otherwise, you won't know when to
  305.  *          free the DLL.
  306.  *
  307.  *  @returns
  308.  *
  309.  *          Standard OLE status code.
  310.  *
  311.  *****************************************************************************/
  312.  
  313. HRESULT
  314. _CreateInprocObject(BOOL bInstance, REFCLSID rclsid, LPCTSTR ptszDll, LPUNKNOWN punkOuter,
  315.                 REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  316. {
  317.     HRESULT hres;
  318.     HINSTANCE hinst;
  319.  
  320.     hinst = LoadLibrary(ptszDll);
  321.     if (hinst) {
  322.         LPFNGETCLASSOBJECT DllGetClassObject;
  323.  
  324.         DllGetClassObject = (LPFNGETCLASSOBJECT)
  325.                             GetProcAddress(hinst, "DllGetClassObject");
  326.  
  327.         if (DllGetClassObject) {
  328.             IClassFactory *pcf;
  329.  
  330.             if (bInstance)
  331.                 hres = DllGetClassObject(rclsid, IID_IClassFactory, (LPVOID *)&pcf);
  332.             else
  333.             {
  334.                 hres = DllGetClassObject(rclsid, riid, ppvOut);
  335.                 if (FAILED(hres))
  336.                     *ppvOut = NULL;
  337.             }
  338.             if (SUCCEEDED(hres) && bInstance) {
  339.                 hres = pcf->CreateInstance(punkOuter, riid, ppvOut);
  340.                 pcf->Release();
  341.  
  342.                 /*
  343.                  *  People forget to adhere to
  344.                  *  the OLE spec, which requires that *ppvOut be
  345.                  *  set to zero on failure.
  346.                  */
  347.                 if (FAILED(hres)) {
  348. /*                    if (*ppvOut) {
  349.                         RPF("ERROR! CoCreateInstance: %s forgot to zero "
  350.                             "out *ppvOut on failure path", ptszDll);
  351.                     }*/
  352.                     *ppvOut = 0;
  353.                 }
  354.  
  355.             }
  356.         } else {
  357.             /*
  358.              *  DLL does not export GetClassObject.
  359.              */
  360.             hres = REGDB_E_CLASSNOTREG;
  361.         }
  362.  
  363.         if (SUCCEEDED(hres)) {
  364.             *phinst = hinst;
  365.         } else {
  366.             FreeLibrary(hinst);
  367.         }
  368.     } else {
  369.         /*
  370.          *  DLL does not exist.
  371.          */
  372.         hres = REGDB_E_CLASSNOTREG;
  373.     }
  374.  
  375.     return hres;
  376. }
  377.  
  378.  
  379. /*****************************************************************************
  380.  *
  381.  *  @doc    INTERNAL
  382.  *
  383.  *  @func   HRESULT | DICoCreateInstance |
  384.  *
  385.  *          Private version of CoCreateInstance that doesn't use OLE.
  386.  *
  387.  *  @parm   LPTSTR | ptszClsid |
  388.  *
  389.  *          The string version of the <t CLSID> to create.
  390.  *
  391.  *  @parm   LPUNKNOWN | punkOuter |
  392.  *
  393.  *          Controlling unknown for aggregation.
  394.  *
  395.  *  @parm   RIID | riid |
  396.  *
  397.  *          Interface to obtain.
  398.  *
  399.  *  @parm   PPV | ppvOut |
  400.  *
  401.  *          Receives a pointer to the created object if successful.
  402.  *
  403.  *  @parm   HINSTANCE * | phinst |
  404.  *
  405.  *          Receives the instance handle of the in-proc DLL that was
  406.  *          loaded.  <f FreeLibrary> this DLL when you are finished
  407.  *          with the object.
  408.  *
  409.  *          Note that since we don't implement a binder, this means
  410.  *          that you cannot give the returned pointer away to anybody
  411.  *          you don't control; otherwise, you won't know when to
  412.  *          free the DLL.
  413.  *
  414.  *  @returns
  415.  *
  416.  *          Standard OLE status code.
  417.  *
  418.  *****************************************************************************/
  419.  
  420. STDMETHODIMP
  421. CreateInprocObject(BOOL bInstance, LPCTSTR ptszClsid, LPUNKNOWN punkOuter,
  422.                    REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  423. {
  424.     HRESULT hres;
  425.     CLSID clsid;
  426.  
  427.     *ppvOut = 0;
  428.     *phinst = 0;
  429.  
  430.     if (ParseGUID(&clsid, ptszClsid)) {
  431.         HKEY hk;
  432.         LONG lRc;
  433.         TCHAR tszKey[ctchGuid + 40];    /* 40 is more than enough */
  434.  
  435.         /*
  436.          *  Look up the CLSID in HKEY_CLASSES_ROOT.
  437.          */
  438.         wsprintf(tszKey, TEXT("CLSID\\%s\\InProcServer32"), ptszClsid);
  439.  
  440.         lRc = RegOpenKeyEx(HKEY_CLASSES_ROOT, tszKey, 0,
  441.                            KEY_QUERY_VALUE, &hk);
  442.         if (lRc == ERROR_SUCCESS) {
  443.             TCHAR tszDll[MAX_PATH];
  444.             DWORD cb;
  445.  
  446.             cb = cbX(tszDll);
  447.             lRc = RegQueryValue(hk, 0, tszDll, (PLONG)&cb);
  448.  
  449.             if (lRc == ERROR_SUCCESS) {
  450.                 TCHAR tszModel[20];     /* more than enough */
  451.  
  452.                 lRc = RegQueryString(hk, TEXT("ThreadingModel"),
  453.                                      tszModel, cA(tszModel));
  454.                 if (lRc == ERROR_SUCCESS &&
  455.                     ((lstrcmpi(tszModel, TEXT("Both"))==0x0) ||
  456.                      (lstrcmpi(tszModel, TEXT("Free"))==0x0))) {
  457.  
  458.                     hres = _CreateInprocObject(bInstance, clsid, tszDll, punkOuter,
  459.                                            riid, ppvOut, phinst);
  460.  
  461.                 } else {
  462.                     /*
  463.                      *  No threading model or bad threading model.
  464.                      */
  465.                     hres = REGDB_E_CLASSNOTREG;
  466.                 }
  467.             } else {
  468.                 /*
  469.                  *  No InprocServer32.
  470.                  */
  471.                 hres = REGDB_E_CLASSNOTREG;
  472.             }
  473.  
  474.             RegCloseKey(hk);
  475.  
  476.         } else {
  477.             /*
  478.              *  CLSID not registered.
  479.              */
  480.             hres = REGDB_E_CLASSNOTREG;
  481.         }
  482.     } else {
  483.         /*
  484.          *  Invalid CLSID string.
  485.          */
  486.         hres = REGDB_E_CLASSNOTREG;
  487.     }
  488.  
  489.     return hres;
  490. }
  491.  
  492.  
  493. HRESULT
  494. PrivCreateInstance(REFCLSID ptszClsid, LPUNKNOWN punkOuter, DWORD dwClsContext, 
  495.                    REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  496. {
  497.     if (dwClsContext != CLSCTX_INPROC_SERVER || phinst == NULL)
  498.         return E_INVALIDARG;
  499.  
  500.     return CreateInprocObject(TRUE, GUIDSTR(ptszClsid), punkOuter, riid, ppvOut, phinst);
  501. }
  502.  
  503. HRESULT
  504. PrivGetClassObject(REFCLSID ptszClsid, DWORD dwClsContext, LPVOID pReserved,
  505.                    REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
  506. {
  507.     if (dwClsContext != CLSCTX_INPROC_SERVER || pReserved != NULL || phinst == NULL)
  508.         return E_INVALIDARG;
  509.  
  510.     return CreateInprocObject(FALSE, GUIDSTR(ptszClsid), NULL, riid, ppvOut, phinst);
  511. }
  512.