home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / dcom / secure / secsvr.cpp < prev    next >
C/C++ Source or Header  |  1996-06-11  |  35KB  |  1,046 lines

  1. // ===========================================================================
  2. // File: S E C S V R . C P P
  3. // 
  4. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  5. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  6. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  7. // PARTICULAR PURPOSE.
  8. //
  9. // Description:
  10. // 
  11. //  This is the server-portion of the SECURE Network OLE sample. This
  12. // application implements several different server capabilities:
  13. //   * Free-threaded server implemented as a Service. The application
  14. //     implements a "LocalService" (CLSID_SecureObjectService) class.
  15. //   * Free-threaded server implemented as a standard executable. The
  16. //     application implements a "LocalServer32" (CLSID_SecureObject) class
  17. //     and runs without user-interface.
  18. //   * Apartment-threaded server implemented as a standard executable. The
  19. //     application implements a "LocalServer32" (CLSID_SecureObject) class
  20. //     and runs with a dialog-box user-interface showing the status of the
  21. //     objects that it has handed out to clients.
  22. // 
  23. //  The purpose of this sample is to demonstrate the different packaging
  24. // options available to server writers, and to demonstrate call-security
  25. // capabilities.
  26. // 
  27. // Instructions:
  28. // 
  29. //  To use this sample:
  30. //   * build the samples using the NMAKE command. NMAKE will create SECCLNT.EXE,
  31. //     SECSVR.EXE, and PSMYPROP.DLL. PSMYPROP.DLL is the remoting proxies and
  32. //     stubs for the custom interface used between the client and the server.
  33. //   * install the server on the current machine or on a remote machine
  34. //     by running INSTALL.BAT in the same directory with SECSVR.EXE and
  35. //     PSMYPROP.DLL. This program registers the proxy-stub DLL using the
  36. //     REGSVR32 tool (included in the \mstools\bin directory of the SDK) and
  37. //     runs the SECSVR.EXE program with "-AutoRegister" on the command-line,
  38. //     which forces it to install itself.
  39. //   * to run the apartment-threaded server, use "SECSVR -Interactive" to launch
  40. //     the server from the command-line. the application will present UI allowing
  41. //     you to choose how to initialize security for the server process, and
  42. //     to view objects currently being used by clients.
  43. //   * In Section 1, choose the security parameters to CoInitializeSecurity from
  44. //     the two drop-down lists, and press the Initialize button.
  45. //   * next, run SECCLNT.EXE from the same machine or from a remote machine. Follow
  46. //     the instructions listed in SECCLNT.CPP to connect to this instance of the
  47. //     SECSVR.EXE application.
  48. //   * once a client has created an instance of the CLSID_SecureObject class, the
  49. //     object will be listed in the drop-down list in Section 2 of the SECSVR.EXE
  50. //     UI. Select the object to be viewed from this list. The current color and
  51. //     "name" established by the client will be displayed in Section 2.
  52. //   * use the "Lock" button to prevent the client from setting the color or "UserName"
  53. //     of the object. the client will display an "access-denied" message if it
  54. //     fails to set the color or "UserName". in the future this sample will include
  55. //     the ability to establish a security-descriptor on the color and Name, and
  56. //     will demonstrate impersonating the client and performing an AccessCheck()
  57. //     during the PutColor and PutUserName methods.
  58. //   * Push the "Exit" button in Section 1 to shut the server down.
  59. // 
  60. // Copyright 1996 Microsoft Corporation. All Rights Reserved.
  61. // ===========================================================================
  62.  
  63. // %%Includes: ---------------------------------------------------------------
  64. #define INC_OLE2
  65. #define STRICT
  66. #define UNICODE
  67. #include <windows.h>
  68. #include <initguid.h>
  69. #include "myprop.h"
  70. #include "secsvr.h"
  71.  
  72. // %%Macros: -----------------------------------------------------------------
  73. #define ENTRY(sz, val)      { sz, val }
  74. #define RGSIZEOF(rg)        (sizeof(rg)/sizeof((rg)[0]))
  75.  
  76. // %%Constants: --------------------------------------------------------------
  77. const TCHAR szServiceName[] = TEXT("SecSvr");
  78. const TCHAR szDescription[] = TEXT("Network OLE Security Sample");
  79. #define cAuthnLevelEntries  RGSIZEOF(rgAuthnLevelEntries)
  80. #define cImpLevelEntries    RGSIZEOF(rgImpLevelEntries)
  81.  
  82. // %%Types: ------------------------------------------------------------------
  83. typedef struct tagENTRY{
  84.     TCHAR   *szName;
  85.     DWORD   dwVal;
  86. } ENTRY, *PENTRY;
  87.  
  88. // %%Classes: ----------------------------------------------------------------
  89. class CClassFactory : public IClassFactory
  90.     {
  91.   // IClassFactory
  92.     STDMETHODIMP            QueryInterface(REFIID iid, void **ppv);
  93.     STDMETHODIMP_(ULONG)    AddRef(void)    { return 1; }
  94.     STDMETHODIMP_(ULONG)    Release(void)   { return 1; }
  95.     STDMETHODIMP            CreateInstance(LPUNKNOWN punkOuter, REFIID iid, LPVOID FAR *ppv);
  96.     STDMETHODIMP            LockServer(BOOL fLock);
  97.     };
  98.  
  99. class CSecureObject : public IMyProperties
  100.     {
  101.   // IUnknown
  102.     STDMETHODIMP    QueryInterface(REFIID iid, void **ppv);
  103.     STDMETHODIMP_(ULONG) AddRef(void)    { return InterlockedIncrement(&m_cRef); }
  104.     STDMETHODIMP_(ULONG) Release(void)   { if (InterlockedDecrement(&m_cRef) == 0) { delete this; return 0; } return 1; }
  105.  
  106.   // IMyProperties
  107.     STDMETHODIMP    GetColor(COLORREF* pcr);
  108.     STDMETHODIMP    PutColor(COLORREF cr);
  109.     STDMETHODIMP    GetUserName(WCHAR szUserName[20]);
  110.     STDMETHODIMP    PutUserName(WCHAR szUserName[20]);
  111.  
  112.   // data members
  113.     LONG        m_cRef;
  114.   public:
  115.     COLORREF    m_crColor;
  116.     BOOL        m_fDenyPutColor;
  117.     WCHAR       m_rgchUserName[20];
  118.     BOOL        m_fDenyPutUserName;
  119.  
  120.   // constructors/destructors
  121.     CSecureObject();
  122.     ~CSecureObject();
  123.     };
  124.  
  125. // %%Prototypes: -------------------------------------------------------------
  126. void    MyServiceMain(DWORD cArg, LPTSTR *rgszArg);
  127. void    MyServiceHandler(DWORD dwControl);
  128. void    ErrorMessage(HWND hwnd, LPTSTR szFunction, HRESULT hr);
  129.  
  130. // %%Globals: ----------------------------------------------------------------
  131. CClassFactory   s_ClassFactory;
  132. struct {
  133.     SERVICE_STATUS          Status;
  134.     SERVICE_STATUS_HANDLE   hStatus;
  135.     DWORD                   dwRegister;
  136.     } s_Service;
  137. SERVICE_TABLE_ENTRY     s_rgsteServices[2] = { { (TCHAR*)szServiceName, MyServiceMain },
  138.                           { NULL, NULL } };
  139. HWND            s_hwndDlg;
  140. UINT            s_cInstances;
  141. HANDLE          s_hevtDone;
  142. CRITICAL_SECTION s_csDone;
  143. BOOL            s_fDone, s_fServer, s_fService;
  144. ENTRY   rgAuthnLevelEntries[] = {
  145.     ENTRY(TEXT("Default    "), RPC_C_AUTHN_DEFAULT),
  146.     ENTRY(TEXT("None       "), RPC_C_AUTHN_LEVEL_NONE),
  147.     ENTRY(TEXT("Connect    "), RPC_C_AUTHN_LEVEL_CONNECT),
  148.     ENTRY(TEXT("Call       "), RPC_C_AUTHN_LEVEL_CALL),
  149.     ENTRY(TEXT("Packet     "), RPC_C_AUTHN_LEVEL_PKT),
  150.     ENTRY(TEXT("Integrity  "), RPC_C_AUTHN_LEVEL_PKT_INTEGRITY),
  151.     ENTRY(TEXT("Privacy    "), RPC_C_AUTHN_LEVEL_PKT_PRIVACY),
  152.     };
  153.  
  154. ENTRY   rgImpLevelEntries[] = {
  155.     ENTRY(TEXT("Anonymous  "), RPC_C_IMP_LEVEL_ANONYMOUS),
  156.     ENTRY(TEXT("Identify   "), RPC_C_IMP_LEVEL_IDENTIFY),
  157.     ENTRY(TEXT("Impersonate"), RPC_C_IMP_LEVEL_IMPERSONATE),
  158.     ENTRY(TEXT("Delegate   "), RPC_C_IMP_LEVEL_DELEGATE),
  159.     };
  160.  
  161.  
  162. // ===========================================================================
  163. //                          C C L A S S F A C T O R Y
  164. // ===========================================================================
  165.  
  166. // ---------------------------------------------------------------------------
  167. // %%Function: CClassFactory::QueryInterface
  168. // ---------------------------------------------------------------------------
  169.  STDMETHODIMP
  170. CClassFactory::QueryInterface(REFIID iid, void **ppv)
  171. {
  172.     if (iid == IID_IClassFactory || iid == IID_IUnknown)
  173.     {
  174.     *ppv = (IClassFactory *)this;
  175.     AddRef();
  176.     return S_OK;
  177.     }
  178.     *ppv = NULL;
  179.     return E_NOINTERFACE;
  180. }  // CClassFactory::QueryInterface
  181.  
  182. // ---------------------------------------------------------------------------
  183. // %%Function: CClassFactory::CreateInstance
  184. // ---------------------------------------------------------------------------
  185.  STDMETHODIMP
  186. CClassFactory::CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppv)
  187. {
  188.     LPUNKNOWN   punk;
  189.     HRESULT     hr;
  190.  
  191.     *ppv = NULL;
  192.  
  193.     if (punkOuter != NULL)
  194.     return CLASS_E_NOAGGREGATION;
  195.  
  196.     if (s_fServer)
  197.     {
  198.     EnterCriticalSection(&s_csDone);
  199.     if (s_fDone == TRUE)
  200.         {
  201.         LeaveCriticalSection(&s_csDone);
  202.         return E_FAIL;
  203.         }
  204.     LeaveCriticalSection(&s_csDone);
  205.     }
  206.  
  207.     punk = new CSecureObject;
  208.     if (punk == NULL)
  209.     return E_OUTOFMEMORY;
  210.  
  211.     hr = punk->QueryInterface(riid, ppv);
  212.     punk->Release();
  213.     return hr;
  214. }  // CClassFactory::CreateInstance
  215.  
  216. // ---------------------------------------------------------------------------
  217. // %%Function: CClassFactory::LockServer
  218. // ---------------------------------------------------------------------------
  219.  STDMETHODIMP
  220. CClassFactory::LockServer(BOOL fLock)
  221. {
  222.     // LockServer not supported by the GUI server -- shutdown is
  223.     // completely controlled by the UI's Exit command
  224.     if (!s_fServer)
  225.     return E_FAIL;
  226.  
  227.     // LockServer acts like having an artificial object outstanding:
  228.     // this code mimics the lifetime management found in the constructor
  229.     // and destructor of CSecureObject
  230.     EnterCriticalSection(&s_csDone);
  231.     if (fLock)
  232.     s_cInstances++;
  233.     else
  234.     {
  235.     if (!--s_cInstances && !s_fService) /* could perform other shutdown management here */
  236.         {
  237.         s_fDone = TRUE;
  238.         SetEvent(s_hevtDone);
  239.         }
  240.     }
  241.     LeaveCriticalSection(&s_csDone);
  242.     return S_OK;
  243. }  // CClassFactory::LockServer
  244.  
  245.  
  246. // ===========================================================================
  247. //                        C S e c u r e O b j e c t
  248. // ===========================================================================
  249.  
  250. // ---------------------------------------------------------------------------
  251. // %%Function: CSecureObject::CSecureObject
  252. // ---------------------------------------------------------------------------
  253. CSecureObject::CSecureObject()
  254. {
  255.     static int s_ID = 0;
  256.  
  257.     // initialize the object's state
  258.     m_cRef = 1;
  259.     m_crColor = 0;
  260.     m_fDenyPutColor = FALSE;
  261.     lstrcpyW(m_rgchUserName, L"Default");
  262.     m_fDenyPutUserName = FALSE;
  263.  
  264.     if (!s_fServer)
  265.     {
  266.     TCHAR   rgchName[20];
  267.     HWND    hwnd;
  268.     int     iPos;
  269.  
  270.     // insert the object into the server UI. put our this-pointer into the item
  271.     // data field of the entry so that we can remove the entry in our destructor
  272.     wsprintf(rgchName, TEXT("Object %d"), s_ID++);
  273.     hwnd = GetDlgItem(s_hwndDlg, IDC_OBJECTS);
  274.     iPos = SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)rgchName);
  275.     SendMessage(hwnd, CB_SETITEMDATA, iPos, (LPARAM)this);
  276.     }
  277.     else
  278.     {
  279.     EnterCriticalSection(&s_csDone);
  280.     s_cInstances++;
  281.     LeaveCriticalSection(&s_csDone);
  282.     }
  283. }  // CSecureObject::CSecureObject
  284.  
  285. CSecureObject::~CSecureObject()
  286. {
  287.     if (!s_fServer)
  288.     {
  289.     HWND    hwnd;
  290.     int     i, iSel, iMac;
  291.  
  292.     // remove the reference to us from the server UI. our this-pointer is in
  293.     // the item-data field of the entry -- find it.
  294.     hwnd = GetDlgItem(s_hwndDlg, IDC_OBJECTS);
  295.     iSel = SendMessage(hwnd, CB_GETCURSEL, 0, 0);
  296.     iMac = SendMessage(hwnd, CB_GETCOUNT, 0, 0);
  297.     for (i=0; i<iMac; i++)
  298.         {
  299.         if ((LRESULT)this == SendMessage(hwnd, CB_GETITEMDATA, i, 0))
  300.         {
  301.         SendMessage(hwnd, CB_DELETESTRING, i, 0);
  302.  
  303.         // if the item being deleted is the current selection,
  304.         // change the selection
  305.         if (i == iSel)
  306.             {
  307.             SendMessage(hwnd, CB_SETCURSEL, 0, 0);
  308.             PostMessage(s_hwndDlg, WM_COMMAND, MAKELONG(IDC_OBJECTS, CBN_SELCHANGE),
  309.             (LPARAM)hwnd);
  310.             }
  311.         break;
  312.         }
  313.         }
  314.     }
  315.     else
  316.     {
  317.     EnterCriticalSection(&s_csDone);
  318.     if (!--s_cInstances && !s_fService) /* could perform other shutdown management here */
  319.         {
  320.         s_fDone = TRUE;
  321.         SetEvent(s_hevtDone);
  322.         }
  323.     LeaveCriticalSection(&s_csDone);
  324.     }
  325. }  // CSecureObject::~CSecureObject
  326.  
  327. // ---------------------------------------------------------------------------
  328. // %%Function: CSecureObject::QueryInterface
  329. // ---------------------------------------------------------------------------
  330.  STDMETHODIMP
  331. CSecureObject::QueryInterface(REFIID iid, void **ppv)
  332. {
  333.     if (iid == IID_IMyProperties || iid == IID_IUnknown)
  334.     {
  335.     *ppv = (IMyProperties *)this;
  336.     AddRef();
  337.     return S_OK;
  338.     }
  339.     *ppv = NULL;
  340.     return E_NOINTERFACE;
  341. }  // CSecureObject::QueryInterface
  342.  
  343. // ---------------------------------------------------------------------------
  344. // %%Function: CSecureObject::GetColor
  345. // ---------------------------------------------------------------------------
  346.  STDMETHODIMP
  347. CSecureObject::GetColor(COLORREF* pcr)
  348. {
  349.     *pcr = m_crColor;
  350.     return S_OK;
  351. }  // CSecureObject::GetColor
  352.  
  353. // ---------------------------------------------------------------------------
  354. // %%Function: CSecureObject::PutColor
  355. // ---------------------------------------------------------------------------
  356.  STDMETHODIMP
  357. CSecureObject::PutColor(COLORREF cr)
  358. {
  359.     // a naive security check under control of the local-server's UI
  360.     if (m_fDenyPutColor == TRUE)
  361.     return E_ACCESSDENIED;
  362.  
  363.     m_crColor = cr;
  364.  
  365.     // update the UI to reflect a valid PutColor occurred
  366.     if (!s_fServer)
  367.     PostMessage(s_hwndDlg, WM_COMMAND, MAKELONG(IDC_OBJECTS,CBN_SELCHANGE),
  368.         (LPARAM)GetDlgItem(s_hwndDlg, IDC_OBJECTS));
  369.  
  370.     return S_OK;
  371. }  // CSecureObject::PutColor
  372.  
  373. // ---------------------------------------------------------------------------
  374. // %%Function: CSecureObject::GetUserName
  375. // ---------------------------------------------------------------------------
  376.  STDMETHODIMP
  377. CSecureObject::GetUserName(WCHAR szUserName[20])
  378. {
  379.     lstrcpynW(szUserName, m_rgchUserName, 20);
  380.     return S_OK;
  381. }  // CSecureObject::GetUserName
  382.  
  383. // ---------------------------------------------------------------------------
  384. // %%Function: CSecureObject::PutUserName
  385. // ---------------------------------------------------------------------------
  386.  STDMETHODIMP
  387. CSecureObject::PutUserName(WCHAR szUserName[20])
  388. {
  389.     // a naive security check under control of the local-server's UI
  390.     if (m_fDenyPutUserName == TRUE)
  391.     return E_ACCESSDENIED;
  392.  
  393.     lstrcpynW(m_rgchUserName, szUserName, 20);
  394.  
  395.     // update the UI to reflect a valid PutUserName occurred
  396.     if (!s_fServer)
  397.     PostMessage(s_hwndDlg, WM_COMMAND, MAKELONG(IDC_OBJECTS,CBN_SELCHANGE),
  398.         (LPARAM)GetDlgItem(s_hwndDlg, IDC_OBJECTS));
  399.  
  400.     return S_OK;
  401. }  // CSecureObject::PutUserName
  402.  
  403.  
  404. // ---------------------------------------------------------------------------
  405. // %%Function: FAutoRegister
  406. // ---------------------------------------------------------------------------
  407.  BOOL
  408. FAutoRegister(HINSTANCE hinst)
  409. {
  410.     static const TCHAR szCLSIDEntryServer[]     = TEXT("CLSID\\{28f64ee0-4656-11cf-8110-00aa00389b71}");
  411.     static const TCHAR szLocalServer32[]        = TEXT("LocalServer32");
  412.     static const TCHAR szAllowRemoteActivation[] = TEXT("AllowRemoteActivation");
  413.     static const TCHAR szCLSIDEntryService[]    = TEXT("CLSID\\{28f64ee2-4656-11cf-8110-00aa00389b71}");
  414.     static const TCHAR szLocalService[]         = TEXT("LocalService");
  415.     static const TCHAR szServiceParameters[]    = TEXT("ServiceParameters");
  416.     static const TCHAR szParameters[]           = TEXT("-Service");
  417.     static const TCHAR szEmpty[]                = TEXT("");
  418.     SC_HANDLE   hManager = NULL, hService = NULL;
  419.     TCHAR       szPath[MAX_PATH], *szError = TEXT("Registry Manipulation");
  420.     HKEY        hkeyT = NULL, hkey2;
  421.  
  422.     // install the CLSID_SecureObject key and get the FQP to this executable
  423.     if ((RegSetValue(HKEY_CLASSES_ROOT, szCLSIDEntryServer, REG_SZ, szDescription,
  424.         lstrlen(szDescription)) != ERROR_SUCCESS) ||
  425.     (RegCreateKey(HKEY_CLASSES_ROOT, szCLSIDEntryServer, &hkeyT) != ERROR_SUCCESS) ||
  426.     !GetModuleFileName(hinst, szPath, sizeof(szPath)/sizeof(TCHAR)))
  427.     goto LErrExit;
  428.  
  429.     // install the LocalServer32 key and the AllowRemoteActivation key
  430.     if ((RegSetValue(hkeyT, szLocalServer32, REG_SZ, szPath, lstrlen(szPath))
  431.         != ERROR_SUCCESS) ||
  432.     (RegSetValue(hkeyT, szAllowRemoteActivation, REG_SZ, szEmpty, lstrlen(szEmpty))
  433.         != ERROR_SUCCESS))
  434.     goto LErrExit;
  435.     RegCloseKey(hkeyT);
  436.     hkeyT = NULL;
  437.  
  438.     // install the CLSID_SecureObjectService key
  439.     if ((RegSetValue(HKEY_CLASSES_ROOT, szCLSIDEntryService, REG_SZ, szDescription,
  440.         lstrlen(szDescription)) != ERROR_SUCCESS) ||
  441.     (RegCreateKey(HKEY_CLASSES_ROOT, szCLSIDEntryService, &hkeyT) != ERROR_SUCCESS))
  442.     goto LErrExit;
  443.  
  444.     // install the LocalService key and the ServiceParameters named-value
  445.     if ((RegSetValue(hkeyT, szLocalService, REG_SZ, szServiceName, lstrlen(szServiceName))
  446.         != ERROR_SUCCESS) ||
  447.     (RegOpenKey(hkeyT, szLocalService, &hkey2) != ERROR_SUCCESS))
  448.     goto LErrExit;
  449.     RegCloseKey(hkeyT);
  450.     hkeyT = hkey2;
  451.     if (RegSetValueEx(hkeyT, szServiceParameters, 0, REG_SZ, (const BYTE*)szParameters,
  452.         (lstrlen(szParameters)+1) * sizeof(TCHAR)) != ERROR_SUCCESS)
  453.     goto LErrExit;
  454.  
  455.     RegCloseKey(hkeyT);
  456.     hkeyT = NULL;
  457.  
  458.     // install the application to run as a service
  459.     hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  460.     if (hManager == NULL)
  461.     {
  462.     szError = TEXT("OpenSCManager");
  463.     goto LErrExit;
  464.     }
  465.  
  466.     hService = OpenService(hManager, szServiceName, SERVICE_ALL_ACCESS);
  467.     if (hService != NULL)
  468.     {
  469.     if (!ChangeServiceConfig(hService,
  470.         SERVICE_WIN32_OWN_PROCESS,
  471.         SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szPath,
  472.         NULL, NULL, NULL, NULL, NULL, szDescription))
  473.         {
  474.         szError = TEXT("ChangeServiceConfig");
  475.         goto LErrExit;
  476.         }
  477.     return TRUE;
  478.     }
  479.  
  480.     hService = CreateService(hManager, szServiceName, szDescription,
  481.     SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
  482.     SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szPath,
  483.     NULL, NULL, NULL,  NULL, NULL);
  484.     if (hService == NULL)
  485.     {
  486.     szError = TEXT("CreateService");
  487.     goto LErrExit;
  488.     }
  489.  
  490.     CloseServiceHandle(hService);
  491.     CloseServiceHandle(hManager);
  492.     return TRUE;
  493.  
  494. LErrExit:
  495.     ErrorMessage(GetDesktopWindow(), szError, GetLastError());
  496.     if (hkeyT != NULL)
  497.     RegCloseKey(hkeyT);
  498.     if (hService != NULL)
  499.     CloseServiceHandle(hService);
  500.     if (hManager != NULL)
  501.     CloseServiceHandle(hManager);
  502.     return FALSE;
  503. }  // FAutoRegister
  504.  
  505. // ---------------------------------------------------------------------------
  506. // %%Function: ErrorMessage
  507. // ---------------------------------------------------------------------------
  508.  void
  509. ErrorMessage(HWND hwnd, LPTSTR szFunction, HRESULT hr)
  510. {
  511.     LPTSTR   szMessage;
  512.  
  513.     if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS)
  514.     hr = HRESULT_CODE(hr);
  515.  
  516.     if (!FormatMessage(
  517.     FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  518.     NULL, hr,
  519.     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
  520.     (LPTSTR)&szMessage, 0, NULL))
  521.     return;
  522.  
  523.     if (hwnd == NULL)
  524.     {
  525.     OutputDebugString(szFunction);
  526.     OutputDebugString(TEXT(": "));
  527.     OutputDebugString(szMessage);
  528.     OutputDebugString(TEXT("\n"));
  529.     }
  530.     else
  531.     MessageBox(hwnd, szMessage, szFunction, MB_OK);
  532.     
  533.     LocalFree(szMessage);
  534. }  // ErrorMessage
  535.  
  536. // ---------------------------------------------------------------------------
  537. // %%Function: SelectEntry
  538. // ---------------------------------------------------------------------------
  539.  void
  540. SelectEntry(HWND hwnd, ENTRY* rgEntries, int cEntries, DWORD dwVal)
  541. {
  542.     for (int i=0; i<cEntries; i++)
  543.     {
  544.     if (rgEntries[i].dwVal == dwVal)
  545.         {
  546.         SendMessage(hwnd, CB_SETCURSEL, i, 0);
  547.         return;
  548.         }
  549.     }
  550. }  // SelectEntry
  551.  
  552. // ---------------------------------------------------------------------------
  553. // %%Function: GetField
  554. // ---------------------------------------------------------------------------
  555.  DWORD
  556. GetField(HWND hwndDlg, UINT idItem)
  557. {
  558.     HWND    hwnd;
  559.     int     iCur;
  560.  
  561.     hwnd = GetDlgItem(hwndDlg, idItem);
  562.     iCur = SendMessage(hwnd, CB_GETCURSEL, 0, 0);
  563.     return SendMessage(hwnd, CB_GETITEMDATA, iCur, 0);
  564. }  // GetField
  565.  
  566. // ---------------------------------------------------------------------------
  567. // %%Function: ServerDialogProc
  568. // ---------------------------------------------------------------------------
  569.  BOOL CALLBACK
  570. ServerDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
  571. {
  572.     static DWORD    s_dwRegister = 0;
  573.     static BOOL     s_fInitialized = FALSE;
  574.     static CSecureObject* s_pcso = NULL;
  575.     static COLORREF s_rgcrCustom[16];
  576.     static HBRUSH   s_hbrCurrent = NULL;
  577.     HRESULT hr;
  578.  
  579.     switch (message)
  580.     {
  581.     case WM_INITDIALOG:
  582.         {
  583.         HWND    hwnd;
  584.         int     cxScreen, cyScreen, i;
  585.         RECT    rcDlg;
  586.  
  587.         // save the hwndDlg into a global
  588.         s_hwndDlg = hwndDlg;
  589.  
  590.         // Center the UI on screen
  591.         cxScreen = GetSystemMetrics(SM_CXFULLSCREEN);
  592.         cyScreen = GetSystemMetrics(SM_CYFULLSCREEN);
  593.         GetWindowRect(hwndDlg, &rcDlg);
  594.         OffsetRect(&rcDlg,
  595.         (cxScreen - rcDlg.right - rcDlg.left)/2,
  596.         (cyScreen - rcDlg.bottom - rcDlg.top)/2);
  597.         MoveWindow(hwndDlg, rcDlg.left, rcDlg.top,
  598.         rcDlg.right-rcDlg.left, rcDlg.bottom-rcDlg.top, TRUE);
  599.  
  600.         // build the lists of authentication levels. choose None for the
  601.         // process default.
  602.         hwnd = GetDlgItem(hwndDlg, IDC_SERVER_AUTHNLEVEL);
  603.         for (i=0; i<cAuthnLevelEntries; i++)
  604.         {
  605.         SendMessage(hwnd, CB_INSERTSTRING, i, (LPARAM)rgAuthnLevelEntries[i].szName);
  606.         SendMessage(hwnd, CB_SETITEMDATA, i, rgAuthnLevelEntries[i].dwVal);
  607.         }
  608.         SelectEntry(hwnd, rgAuthnLevelEntries, cAuthnLevelEntries, RPC_C_AUTHN_LEVEL_NONE);
  609.  
  610.         // build the lists of impersonation levels. choose Anonymous for the
  611.         // process default.
  612.         hwnd = GetDlgItem(hwndDlg, IDC_SERVER_IMPLEVEL);
  613.         for (i=0; i<cImpLevelEntries; i++)
  614.         {
  615.         SendMessage(hwnd, CB_INSERTSTRING, i, (LPARAM)rgImpLevelEntries[i].szName);
  616.         SendMessage(hwnd, CB_SETITEMDATA, i, rgImpLevelEntries[i].dwVal);
  617.         }
  618.         SelectEntry(hwnd, rgImpLevelEntries, cImpLevelEntries, RPC_C_IMP_LEVEL_ANONYMOUS);
  619.         return 1;
  620.         }
  621.  
  622.     case WM_SYSCOMMAND:
  623.         if (wParam == SC_CLOSE)
  624.         goto LClose;
  625.         break;
  626.  
  627.     case WM_COMMAND:
  628.         switch (LOWORD(wParam))
  629.         {
  630.         case IDCANCEL:
  631. LClose:
  632.             if (s_hbrCurrent != NULL)
  633.             {
  634.             DeleteObject(s_hbrCurrent);
  635.             s_hbrCurrent = NULL;
  636.             }
  637.             if (s_dwRegister != 0)
  638.             {
  639.             CoRevokeClassObject(s_dwRegister);
  640.             s_dwRegister = 0;
  641.             }
  642.             if (s_fInitialized == TRUE)
  643.             {
  644.             CoUninitialize();
  645.             s_fInitialized = FALSE;
  646.             }
  647.             EndDialog(hwndDlg, 0);
  648.             break;
  649.  
  650.         case IDC_INITIALIZE:
  651.             // initialize as apartment-threaded to synchronize the UI
  652.             // with calls to the objects
  653.             hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  654.             if (FAILED(hr))
  655.             {
  656.             ErrorMessage(hwndDlg, TEXT("CoInitialize"), hr);
  657.             break;
  658.             }
  659.  
  660.                     // initialize security layer with our choices
  661.             hr = CoInitializeSecurity(NULL,
  662.                         -1,
  663.                         NULL,
  664.                         NULL,
  665.             GetField(hwndDlg, IDC_SERVER_AUTHNLEVEL),
  666.             GetField(hwndDlg, IDC_SERVER_IMPLEVEL),
  667.                         NULL,
  668.                         0,
  669.             NULL);
  670.             if (FAILED(hr))
  671.             {
  672.             ErrorMessage(hwndDlg, TEXT("CoInitializeSecurity"), hr);
  673.             break;
  674.             }
  675.  
  676.             hr = CoRegisterClassObject(CLSID_SecureObject, &s_ClassFactory, 
  677.             CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &s_dwRegister);
  678.             if (FAILED(hr))
  679.             {
  680.             ErrorMessage(hwndDlg, TEXT("CoRegisterClassObject"), hr);
  681.             CoUninitialize();
  682.             break;
  683.             }
  684.             
  685.             // Disable Initialization Step (#1)
  686.             EnableWindow(GetDlgItem(hwndDlg, IDC_INITIALIZE), FALSE);
  687.             EnableWindow(GetDlgItem(hwndDlg, IDC_SERVER_AUTHNLEVEL), FALSE);
  688.             EnableWindow(GetDlgItem(hwndDlg, IDC_SERVER_IMPLEVEL), FALSE);
  689.  
  690.             // Enable Object Viewing Steps (#2)
  691.             // (choosing a valid object in the list box will enable the
  692.             //  other controls)
  693.             EnableWindow(GetDlgItem(hwndDlg, IDC_OBJECTS), TRUE);
  694.  
  695.             s_fInitialized = TRUE;
  696.             break;
  697.  
  698.         case IDC_OBJECTS:
  699.             {
  700.             int     iCur;
  701.  
  702.             if (HIWORD(wParam) != CBN_SELCHANGE)
  703.             break;
  704.  
  705.             // a different object was chosen, or a property has changed.
  706.             // retrieve the object's pointer from the item-data of the
  707.             // current list-box item and update the UI.
  708.             iCur = SendMessage(GetDlgItem(hwndDlg, IDC_OBJECTS),
  709.             CB_GETCURSEL, 0, 0);
  710.             if (iCur == CB_ERR)
  711.             s_pcso = NULL;
  712.             else
  713.             {
  714.             s_pcso = (CSecureObject*)SendMessage(GetDlgItem(hwndDlg, IDC_OBJECTS),
  715.                 CB_GETITEMDATA, iCur, 0);
  716.             if (s_pcso == (LPVOID)CB_ERR)
  717.                 s_pcso = NULL;
  718.             }
  719.  
  720.             if (s_hbrCurrent != NULL)
  721.             {
  722.             DeleteObject(s_hbrCurrent);
  723.             s_hbrCurrent = NULL;
  724.             }
  725.             SetWindowText(GetDlgItem(hwndDlg, IDC_USERNAME), TEXT(""));
  726.             InvalidateRect(GetDlgItem(hwndDlg, IDC_CHOOSECOLOR), NULL, TRUE);
  727.             InvalidateRect(GetDlgItem(hwndDlg, IDC_COLOR), NULL, TRUE);
  728.             InvalidateRect(GetDlgItem(hwndDlg, IDC_USERNAME), NULL, TRUE);
  729.             InvalidateRect(GetDlgItem(hwndDlg, IDC_NOPUTCOLOR), NULL, TRUE);
  730.             InvalidateRect(GetDlgItem(hwndDlg, IDC_NOPUTUSERNAME), NULL, TRUE);
  731.  
  732.             if (s_pcso != NULL)
  733.             {
  734.             SetWindowTextW(GetDlgItem(hwndDlg, IDC_USERNAME), s_pcso->m_rgchUserName);
  735.             s_hbrCurrent = CreateSolidBrush(s_pcso->m_crColor);
  736.             }
  737.  
  738.             // enable/disable the object-specific windows
  739.             EnableWindow(GetDlgItem(hwndDlg, IDC_CHOOSECOLOR), s_pcso != NULL);
  740.             EnableWindow(GetDlgItem(hwndDlg, IDC_COLOR), s_pcso != NULL);
  741.             EnableWindow(GetDlgItem(hwndDlg, IDC_USERNAME), s_pcso != NULL);
  742.             EnableWindow(GetDlgItem(hwndDlg, IDC_NOPUTCOLOR), s_pcso != NULL);
  743.             EnableWindow(GetDlgItem(hwndDlg, IDC_NOPUTUSERNAME), s_pcso != NULL);
  744.             break;
  745.             }
  746.  
  747.         case IDC_NOPUTCOLOR:
  748.             s_pcso->m_fDenyPutColor = SendMessage(
  749.             GetDlgItem(hwndDlg, IDC_NOPUTCOLOR), BM_GETCHECK, 0, 0);
  750.             break;
  751.  
  752.         case IDC_NOPUTUSERNAME:
  753.             s_pcso->m_fDenyPutUserName = SendMessage(
  754.             GetDlgItem(hwndDlg, IDC_NOPUTUSERNAME), BM_GETCHECK, 0, 0);
  755.             break;
  756.  
  757.         case IDC_CHOOSECOLOR:
  758.             {
  759.             CHOOSECOLOR cc;
  760.  
  761.             cc.lStructSize = sizeof(CHOOSECOLOR);
  762.             cc.hwndOwner = hwndDlg;
  763.             cc.rgbResult = s_pcso->m_crColor;
  764.             cc.lpCustColors = s_rgcrCustom;
  765.             cc.Flags = CC_RGBINIT | CC_SHOWHELP;
  766.  
  767.             if (ChooseColor(&cc))
  768.             {
  769.             s_pcso->m_crColor = cc.rgbResult;
  770.             if (s_hbrCurrent != NULL)
  771.                 DeleteObject(s_hbrCurrent);
  772.             s_hbrCurrent = CreateSolidBrush(cc.rgbResult);
  773.             InvalidateRect((HWND)lParam, NULL, TRUE);
  774.             }
  775.             break;
  776.             }
  777.  
  778.         case IDC_USERNAME:
  779.             {
  780.             static s_fDirty = FALSE;
  781.  
  782.             if (HIWORD(wParam) == EN_CHANGE)
  783.             {
  784.             s_fDirty = TRUE;
  785.             }
  786.             else if (HIWORD(wParam) == EN_KILLFOCUS && s_fDirty)
  787.             {
  788.             GetWindowTextW(GetDlgItem(hwndDlg, IDC_USERNAME),
  789.                 s_pcso->m_rgchUserName, 20);
  790.             s_fDirty = FALSE;
  791.             }
  792.             break;
  793.             }
  794.         }
  795.         break;
  796.  
  797.     case WM_DRAWITEM:
  798.         {
  799.         LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
  800.  
  801.         FillRect(lpdis->hDC, &lpdis->rcItem,
  802.         s_hbrCurrent != NULL ? s_hbrCurrent : (HBRUSH)GetStockObject(WHITE_BRUSH));
  803.         FrameRect(lpdis->hDC, &lpdis->rcItem, (HBRUSH)GetStockObject(BLACK_BRUSH));
  804.         if (lpdis->itemState & ODS_SELECTED)
  805.         InvertRect(lpdis->hDC, (LPRECT)&lpdis->rcItem);
  806.         if (lpdis->itemState & ODS_FOCUS)
  807.         DrawFocusRect(lpdis->hDC, (LPRECT) &lpdis->rcItem);
  808.         return TRUE;
  809.         }
  810.     }
  811.     return FALSE;
  812. }  // ServerDialogProc
  813.  
  814. // ---------------------------------------------------------------------------
  815. // %%Function: MyServiceMain
  816. // ---------------------------------------------------------------------------
  817.  void
  818. MyServiceMain(DWORD dwArgc, LPTSTR *pszArgv)
  819. {
  820.     HRESULT hr;
  821.  
  822.     s_Service.Status.dwServiceType        = SERVICE_WIN32_OWN_PROCESS;
  823.     s_Service.Status.dwCurrentState       = SERVICE_START_PENDING;
  824.     s_Service.Status.dwControlsAccepted   = SERVICE_ACCEPT_STOP;
  825.     s_Service.Status.dwWin32ExitCode      = 0;
  826.     s_Service.Status.dwServiceSpecificExitCode = 0;
  827.     s_Service.Status.dwCheckPoint         = 0;
  828.     s_Service.Status.dwWaitHint           = 0;
  829.  
  830.     s_Service.hStatus = RegisterServiceCtrlHandler(szServiceName, MyServiceHandler);
  831.  
  832.     if (s_Service.hStatus == NULL)
  833.     return;
  834.  
  835.     // used to gaurd the s_fDone variable that prevents new instances
  836.     // from being created in IClassFactory::CreateInstance during shutdown
  837.     InitializeCriticalSection(&s_csDone);
  838.  
  839.     // event used to signal the service has stopped
  840.     s_hevtDone = CreateEvent(NULL, FALSE, FALSE, NULL);
  841.     if (s_hevtDone == NULL)
  842.     {
  843.     ErrorMessage(NULL, TEXT("CreateEvent"), GetLastError());
  844.     goto LErrExit;
  845.     }
  846.  
  847.     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  848.     if (FAILED(hr))
  849.     {
  850.     ErrorMessage(NULL, TEXT("CoInitialize"), hr);
  851.     goto LErrExit;
  852.     }
  853.  
  854.     // the Service CLSID is used here, different from the LocalServer case
  855.     hr = CoRegisterClassObject(CLSID_SecureObjectService, &s_ClassFactory, 
  856.     CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &s_Service.dwRegister);
  857.     
  858.     if (FAILED(hr))
  859.     {
  860.     ErrorMessage(NULL, TEXT("CoRegisterClassObject"), hr);
  861.     CoUninitialize();
  862.     goto LErrExit;
  863.     }
  864.  
  865.     // Initialization complete - report running status 
  866.     s_Service.Status.dwCurrentState       = SERVICE_RUNNING; 
  867.     s_Service.Status.dwCheckPoint         = 0; 
  868.     s_Service.Status.dwWaitHint           = 0; 
  869.  
  870.     // notify the service-manager that the service is running
  871.     if (!SetServiceStatus(s_Service.hStatus, &s_Service.Status))
  872.     ErrorMessage(NULL, TEXT("SetServiceStatus(SERVICE_RUNNING)"), GetLastError());
  873.  
  874.     // wait for the signal from MyServiceHandler:SERVICE_CONTROL_STOP
  875.     WaitForSingleObject(s_hevtDone, INFINITE);
  876.  
  877.     CloseHandle(s_hevtDone);
  878.     s_hevtDone = NULL;
  879.  
  880.     CoRevokeClassObject(s_Service.dwRegister);
  881.     CoUninitialize();
  882.  
  883.     // notify the service-manager that the service has totally stopped
  884.     s_Service.Status.dwCurrentState = SERVICE_STOPPED;
  885.     if (!SetServiceStatus(s_Service.hStatus, &s_Service.Status))
  886.     ErrorMessage(NULL, TEXT("SetServiceStatus(SERVICE_STOPPED)"), GetLastError());
  887.     return;
  888.  
  889. LErrExit:
  890.     if (s_hevtDone != NULL)
  891.     {
  892.     CloseHandle(s_hevtDone);
  893.     s_hevtDone = NULL;
  894.     }
  895.     s_Service.Status.dwCurrentState       = SERVICE_STOPPED;
  896.     s_Service.Status.dwCheckPoint         = 0;
  897.     s_Service.Status.dwWaitHint           = 0;
  898.     s_Service.Status.dwWin32ExitCode      = hr;
  899.     s_Service.Status.dwServiceSpecificExitCode = hr;
  900.     SetServiceStatus(s_Service.hStatus, &s_Service.Status); 
  901.     return;
  902. }  // MyServiceMain
  903.  
  904. // ---------------------------------------------------------------------------
  905. // %%Function: MyServiceHandler
  906. // ---------------------------------------------------------------------------
  907.  void
  908. MyServiceHandler(DWORD dwControl)
  909. {
  910.     switch (dwControl)
  911.     {
  912.     case SERVICE_CONTROL_STOP:
  913.         s_Service.Status.dwWin32ExitCode = 0;
  914.         s_Service.Status.dwCurrentState  = SERVICE_STOP_PENDING;
  915.         s_Service.Status.dwCheckPoint    = 0;
  916.         s_Service.Status.dwWaitHint      = 0;
  917.         if (!SetServiceStatus (s_Service.hStatus, &s_Service.Status))
  918.         ErrorMessage(NULL, TEXT("SetServiceStatus"), GetLastError());
  919.  
  920.         EnterCriticalSection(&s_csDone);
  921.  
  922.         // prevent further instances from being created in IClassFactory::CreateInstance
  923.         s_fDone = TRUE;
  924.  
  925.         // restart the waiting MyServiceMain thread and allow it to uninitialize and exit.
  926.         SetEvent(s_hevtDone);
  927.  
  928.         LeaveCriticalSection(&s_csDone);
  929.         return;
  930.  
  931.     case SERVICE_CONTROL_INTERROGATE:
  932.         // fall out and send the current status of s_Service.Status
  933.         break;
  934.  
  935.     default:
  936.         break;
  937.     }
  938.  
  939.     // send current status.
  940.     if (!SetServiceStatus(s_Service.hStatus,  &s_Service.Status))
  941.     ErrorMessage(NULL, TEXT("SetServiceStatus"), GetLastError());
  942.  
  943.     return; 
  944. }  // MyServiceHandler
  945.  
  946. // ---------------------------------------------------------------------------
  947. // %%Function: WinMain
  948. // ---------------------------------------------------------------------------
  949.  int WINAPI
  950. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow)
  951. {
  952.     HRESULT hr;
  953.  
  954.     // DebugBreak();
  955.  
  956.     // parse the command-line
  957.     if (szCmdLine)
  958.     {
  959.     char    *sz = strtok(szCmdLine, " \t");
  960.     if (sz)
  961.         {
  962.         if (!strcmpi(sz, "-Embedding"))
  963.         s_fServer = TRUE;
  964.  
  965.         // Auto-register, display success or failure, and exit
  966.         else if (!strcmpi(sz, "-AutoRegister"))
  967.         {
  968.         if (FAutoRegister(hInstance))
  969.             MessageBox(GetDesktopWindow(),
  970.             TEXT("Registered Successfully!"),
  971.             szDescription,
  972.             MB_OK);
  973.         return S_OK;
  974.         }
  975.  
  976.         // any other argument besides interactive causes help to be displayed
  977.         else if (strcmpi(sz, "-Interactive"))
  978.         {
  979.         // MessageBox some help here
  980.         }
  981.         }
  982.     else
  983.         {
  984.         s_fService = TRUE;
  985.         s_fServer = TRUE;
  986.         }
  987.     }
  988.  
  989.     // when launched without command-line args, run as a service, without any UI
  990.     // and running multi-threaded
  991.     if (s_fService)
  992.     return StartServiceCtrlDispatcher(s_rgsteServices) ? 0 : GetLastError();
  993.  
  994.     // when launched with -Embedding, come up
  995.     // without any UI and run multi-threaded
  996.     else if (s_fServer)
  997.     {
  998.     DWORD   dwRegister;
  999.  
  1000.     InitializeCriticalSection(&s_csDone);
  1001.  
  1002.     s_hevtDone = CreateEvent(NULL, FALSE, FALSE, NULL);
  1003.     if (s_hevtDone == NULL)
  1004.         return HRESULT_FROM_WIN32(GetLastError());
  1005.  
  1006.     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1007.     if (FAILED(hr))
  1008.         return hr;
  1009.  
  1010.     hr = CoRegisterClassObject(CLSID_SecureObject, &s_ClassFactory, 
  1011.         CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &dwRegister);
  1012.     if (FAILED(hr))
  1013.         goto LServerExit;
  1014.  
  1015.     // wait for all open connections to the server to go away
  1016.     WaitForSingleObject(s_hevtDone, INFINITE);
  1017.  
  1018.     // Destroy the event handle
  1019.     CloseHandle(s_hevtDone);
  1020.     s_hevtDone = NULL;
  1021.  
  1022.     // destroy the critsec used to determine when we're done
  1023.     DeleteCriticalSection(&s_csDone);
  1024.  
  1025.     CoRevokeClassObject(dwRegister);
  1026.  
  1027. LServerExit:
  1028.     CoUninitialize();
  1029.     return hr;
  1030.     }
  1031.  
  1032.     // when launched with -Interactive, run with UI.
  1033.     // this allows the user to adjust the exact security parameters of the
  1034.     // process and to monitor individual client objects. in this case, we will
  1035.     // eventually initialize COM (once the user selects security parameters
  1036.     // and hits the Initialize button) to use the apartment model in order
  1037.     // to synchronize calls with our UI.
  1038.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_SECSVR), GetDesktopWindow(),
  1039.     (DLGPROC)ServerDialogProc);
  1040.  
  1041.     return 0;
  1042. } // WinMain
  1043.  
  1044. // EOF =======================================================================
  1045.  
  1046.