home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap09 / linksrc / linksrc.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  14KB  |  616 lines

  1. /*
  2.  * LINKSRC.CPP
  3.  * Link Source Server Chapter 9
  4.  *
  5.  * Server of various objects that can be named with monikers.
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13.  
  14.  
  15. #define INITGUIDS
  16. #include "linksrc.h"
  17.  
  18.  
  19. //Count number of objects and number of locks.
  20. ULONG       g_cObj=0;
  21. ULONG       g_cLock=0;
  22. BOOL        g_fUser=FALSE;
  23.  
  24. //Make window handle global so other code can cause a shutdown
  25. HWND        g_hWnd=NULL;
  26.  
  27.  
  28. /*
  29.  * WinMain
  30.  *
  31.  * Purpose:
  32.  *  Main entry point of application.
  33.  */
  34.  
  35. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hInstPrev
  36.     , LPSTR pszCmdLine, int nCmdShow)
  37.     {
  38.     MSG         msg;
  39.     PAPP        pApp;
  40.  
  41.     SETMESSAGEQUEUE;
  42.  
  43.     pApp=new CApp(hInst, hInstPrev, pszCmdLine, nCmdShow);
  44.  
  45.     if (NULL==pApp)
  46.         return -1;
  47.  
  48.     if (pApp->Init())
  49.         {
  50.         while (GetMessage(&msg, NULL, 0,0 ))
  51.             {
  52.             TranslateMessage(&msg);
  53.             DispatchMessage(&msg);
  54.             }
  55.         }
  56.  
  57.     delete pApp;
  58.     return msg.wParam;
  59.     }
  60.  
  61.  
  62.  
  63. /*
  64.  * KoalaWndProc
  65.  *
  66.  * Purpose:
  67.  *  Standard window class procedure.
  68.  */
  69.  
  70. LRESULT APIENTRY LinkSrcWndProc(HWND hWnd, UINT iMsg
  71.     , WPARAM wParam, LPARAM lParam)
  72.     {
  73.     PAPP        pApp;
  74.  
  75.     pApp=(PAPP)GetWindowLong(hWnd, LINKSRCWL_STRUCTURE);
  76.  
  77.     switch (iMsg)
  78.         {
  79.         case WM_NCCREATE:
  80.             pApp=(PAPP)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  81.             SetWindowLong(hWnd, LINKSRCWL_STRUCTURE, (LONG)pApp);
  82.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  83.  
  84.         case WM_COMMAND:
  85.             switch (LOWORD(wParam))
  86.                 {
  87.                 case IDM_FILECREATEGOOP:
  88.                     pApp->CreateSampleFile(TEXT("goop.lks"));
  89.                     break;
  90.  
  91.                 case IDM_FILEEXIT:
  92.                     PostMessage(hWnd, WM_CLOSE, 0, 0L);
  93.                     break;
  94.  
  95.                 default:
  96.                     break;
  97.                 }
  98.  
  99.             break;
  100.  
  101.         case WM_CLOSE:
  102.             //Don't close with object's active
  103.             if (0==g_cObj && 0==g_cLock)
  104.                 return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  105.  
  106.             break;
  107.  
  108.         case WM_DESTROY:
  109.             PostQuitMessage(0);
  110.             break;
  111.  
  112.         default:
  113.             return (DefWindowProc(hWnd, iMsg, wParam, lParam));
  114.         }
  115.  
  116.     return 0L;
  117.     }
  118.  
  119.  
  120.  
  121.  
  122. /*
  123.  * ObjectDestroyed
  124.  *
  125.  * Purpose:
  126.  *  Function for the LinkSrc object to call when it gets destroyed.
  127.  *  We destroy the main window if the proper conditions are met
  128.  *  for shutdown.
  129.  */
  130.  
  131. void ObjectDestroyed(void)
  132.     {
  133.     g_cObj--;
  134.  
  135.     /*
  136.      * No more objects and no locks, and user is not in
  137.      * control (CApp::m_fEmbedding), then shut down.
  138.      */
  139.     if (0L==g_cObj && 0L==g_cLock && IsWindow(g_hWnd)
  140.         && !g_fUser)
  141.         PostMessage(g_hWnd, WM_CLOSE, 0, 0L);
  142.  
  143.     return;
  144.     }
  145.  
  146.  
  147.  
  148.  
  149. /*
  150.  * CApp::CApp
  151.  * CApp::~CApp
  152.  *
  153.  * Constructor Parameters:
  154.  *  hInst           HINSTANCE of the Application from WinMain
  155.  *  hInstPrev       HINSTANCE of a previous instance from WinMain
  156.  *  pszCmdLine      LPSTR of the command line.
  157.  *  nCmdShow        UINT specifying how to show the app window,
  158.  *                  from WinMain.
  159.  */
  160.  
  161. CApp::CApp(HINSTANCE hInst, HINSTANCE hInstPrev
  162.     , LPSTR pszCmdLine, UINT nCmdShow)
  163.     {
  164.     //Initialize WinMain parameter holders.
  165.     m_hInst     =hInst;
  166.     m_hInstPrev =hInstPrev;
  167.     m_pszCmdLine=pszCmdLine;
  168.     m_nCmdShow  =nCmdShow;
  169.  
  170.     m_hWnd=NULL;
  171.     m_dwRegCO=0;
  172.     m_pIClassFactory=NULL;
  173.     m_fInitialized=FALSE;
  174.  
  175.     /*
  176.      * We can run stand-alone or at OLE's request, but we
  177.      * remain hidden if run from OLE.
  178.      */
  179.     m_fEmbedding=TRUE;
  180.  
  181.     return;
  182.     }
  183.  
  184.  
  185. CApp::~CApp(void)
  186.     {
  187.     //Opposite of CoRegisterClassObject; class factory ref is now 1
  188.     if (0L!=m_dwRegCO)
  189.         CoRevokeClassObject(m_dwRegCO);
  190.  
  191.     //The last Release, which frees the class factory.
  192.     if (NULL!=m_pIClassFactory)
  193.         m_pIClassFactory->Release();
  194.  
  195.     if (m_fInitialized)
  196.         CoUninitialize();
  197.  
  198.     return;
  199.     }
  200.  
  201.  
  202.  
  203.  
  204. /*
  205.  * CApp::Init
  206.  *
  207.  * Purpose:
  208.  *  Initializes an CApp object by registering window classes,
  209.  *  creating the main window, and doing anything else prone to
  210.  *  failure.  If this function fails the caller should guarantee
  211.  *  that the destructor is called.
  212.  *
  213.  * Parameters:
  214.  *  None
  215.  *
  216.  * Return Value:
  217.  *  BOOL            TRUE if successful, FALSE otherwise.
  218.  */
  219.  
  220. BOOL CApp::Init(void)
  221.     {
  222.     WNDCLASS    wc;
  223.     HRESULT     hr;
  224.  
  225.     CHECKVER_COM;
  226.  
  227.     //Check if we're run stand-alone
  228.     if (lstrcmpiA(m_pszCmdLine, "-Embedding")
  229.         && lstrcmpiA(m_pszCmdLine, "/Embedding"))
  230.         {
  231.         m_fEmbedding=FALSE;
  232.         g_fUser=TRUE;
  233.         }
  234.  
  235.     //Call CoInitialize so we can call other Co* functions
  236.     if (FAILED(CoInitialize(NULL)))
  237.         return FALSE;
  238.  
  239.     m_fInitialized=TRUE;
  240.  
  241.     if (!m_hInstPrev)
  242.         {
  243.         wc.style          = CS_HREDRAW | CS_VREDRAW;
  244.         wc.lpfnWndProc    = LinkSrcWndProc;
  245.         wc.cbClsExtra     = 0;
  246.         wc.cbWndExtra     = CBWNDEXTRA;
  247.         wc.hInstance      = m_hInst;
  248.         wc.hIcon          = LoadIcon(m_hInst, TEXT("Icon"));
  249.         wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
  250.         wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  251.         wc.lpszMenuName   = MAKEINTRESOURCE(IDR_MENU);
  252.         wc.lpszClassName  = TEXT("LinkSrc");
  253.  
  254.         if (!RegisterClass(&wc))
  255.             return FALSE;
  256.         }
  257.  
  258.     m_hWnd=CreateWindow(TEXT("LinkSrc"), TEXT("Link Source")
  259.         , WS_OVERLAPPEDWINDOW, 450, 35, 350, 250
  260.         , NULL, NULL, m_hInst, this);
  261.  
  262.     if (NULL==m_hWnd)
  263.         return FALSE;
  264.  
  265.     //Don't show the window outside of embedding
  266.     if (!m_fEmbedding)
  267.         {
  268.         ShowWindow(m_hWnd, SW_SHOW);
  269.         UpdateWindow(m_hWnd);
  270.         }
  271.  
  272.     g_hWnd=m_hWnd;
  273.  
  274.     /*
  275.      * We only server file objects through a CLSID.  Other
  276.      * items are referenced through the File object.
  277.      */
  278.     m_pIClassFactory=new CFileObjectFactory();
  279.  
  280.     if (NULL==m_pIClassFactory)
  281.         return FALSE;
  282.  
  283.     //Since we hold on to this, we should AddRef it.
  284.     m_pIClassFactory->AddRef();
  285.  
  286.     hr=CoRegisterClassObject(CLSID_LinkedFile, m_pIClassFactory
  287.         , CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &m_dwRegCO);
  288.  
  289.     if (FAILED(hr))
  290.         return FALSE;
  291.  
  292.     return TRUE;
  293.     }
  294.  
  295.  
  296.  
  297. /*
  298.  * CApp::CreateSampleFile
  299.  *
  300.  * Purpose:
  301.  *  Creates a file with the structure we can use in binding
  302.  *  monikers.
  303.  *
  304.  * Parameters:
  305.  *  pszFile         LPTSTR to the file name to create.
  306.  *
  307.  * Return Value:
  308.  *  None
  309.  */
  310.  
  311. void CApp::CreateSampleFile(LPTSTR pszFile)
  312.     {
  313.     HRESULT     hr;
  314.     IStorage   *pIStorage;
  315.  
  316.     hr=StgCreateDocfile(pszFile, STGM_DIRECT | STGM_READWRITE
  317.         | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
  318.  
  319.     if (SUCCEEDED(hr))
  320.         {
  321.         UINT        i;
  322.         TCHAR       szTemp[40];
  323.         TCHAR       szDesc[256];
  324.  
  325.         WriteDescription(pIStorage
  326.             , TEXT("This is a sample compound file from LinkSource that demonstrates binding to a file moniker."));
  327.  
  328.         for (i=0; i < 4; i++)
  329.             {
  330.             wsprintf(szTemp, TEXT("Object %d"), i);
  331.             wsprintf(szDesc
  332.                 , TEXT("This is the first-level item named %s in the file.")
  333.                 , szTemp);
  334.  
  335.             hr=CreateStore(pIStorage, szTemp, szDesc, 5);
  336.  
  337.             if (FAILED(hr))
  338.                 break;
  339.             }
  340.         }
  341.  
  342.     pIStorage->SetClass(CLSID_LinkedFile);
  343.     pIStorage->Release();
  344.  
  345.     if (FAILED(hr))
  346.         {
  347.         MessageBox(m_hWnd, TEXT("File creation failed.")
  348.             , TEXT("Link Source"), MB_OK);
  349.         }
  350.     else
  351.         {
  352.         MessageBox(m_hWnd, TEXT("File created successfully.")
  353.             , TEXT("Link Source"), MB_OK);
  354.         }
  355.  
  356.     return;
  357.     }
  358.  
  359.  
  360.  
  361. /*
  362.  * CApp::CreateStore
  363.  *
  364.  * Purpose:
  365.  *  Creates a sub-storage below pIStorage with the given name and
  366.  *  writes a description stream using the stringtable string idsDesc.
  367.  *
  368.  * Parameters:
  369.  *  pIStorage       IStorage * in which to create the storage.
  370.  *  pszName         LPTSTR naming the storage to create.
  371.  *  pszDesc         LPTSTR holding the description.
  372.  *  cSubs           UINT number of sub-storages to create in this one
  373.  *
  374.  * Return Value:
  375.  *  HRESULT         Result of the operation.
  376.  */
  377.  
  378. HRESULT CApp::CreateStore(IStorage *pIStorage, LPTSTR pszName
  379.     , LPTSTR pszDesc, UINT cSubs)
  380.     {
  381.     HRESULT     hr;
  382.     IStorage   *pSub;
  383.     TCHAR       szTemp[40];
  384.     TCHAR       szDesc[256];
  385.     UINT        i;
  386.  
  387.    #ifdef WIN32ANSI
  388.     OLECHAR     szUNI[40];
  389.     MultiByteToWideChar(CP_ACP, 0, pszName, -1, szUNI, 40);
  390.  
  391.     hr=pIStorage->CreateStorage(szUNI, STGM_DIRECT
  392.         | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pSub);
  393.    #else
  394.     hr=pIStorage->CreateStorage(pszName, STGM_DIRECT
  395.         | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pSub);
  396.    #endif
  397.  
  398.     if (FAILED(hr))
  399.         return hr;
  400.  
  401.     hr=WriteDescription(pSub, pszDesc);
  402.  
  403.     if (cSubs > 255)
  404.         cSubs=255;
  405.  
  406.     /*
  407.      * If cSubs is zero we'll pass to the return statement
  408.      * which allows recursion in the loop below for 2nd level storages.
  409.      */
  410.     for (i=0; i < cSubs; i++)
  411.         {
  412.         wsprintf(szTemp, TEXT("Sub-Object %d"), i);
  413.         wsprintf(szDesc
  414.             , TEXT("This is the second-level item named %s inside the item named %s in the file.")
  415.             , szTemp, pszName);
  416.  
  417.         hr=CreateStore(pSub, szTemp, szDesc, 0);
  418.  
  419.         if (FAILED(hr))
  420.             break;
  421.         }
  422.  
  423.     pSub->Release();
  424.     return hr;
  425.     }
  426.  
  427.  
  428.  
  429.  
  430. /*
  431.  * CApp::WriteDescription
  432.  *
  433.  * Purpose:
  434.  *  Creates a stream with the name SZDESCRIPTION in the given
  435.  *  storage and writes into that stream the string identified
  436.  *  by idsDesc that exists in the stringtable.
  437.  *
  438.  * Parameters:
  439.  *  pIStorage       IStorage * in which to create the stream.
  440.  *  pszDesc         LPTSTR describing the storage.
  441.  *
  442.  * Return Value:
  443.  *  HRESULT         NOERROR or an error code.
  444.  */
  445.  
  446. HRESULT CApp::WriteDescription(IStorage *pIStorage, LPTSTR pszDesc)
  447.     {
  448.     HRESULT     hr;
  449.     IStream    *pIStream;
  450.  
  451.     hr=pIStorage->CreateStream(SZDESCRIPTION, STGM_DIRECT
  452.         | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStream);
  453.  
  454.     if (FAILED(hr))
  455.         return hr;
  456.  
  457.     hr=pIStream->Write(pszDesc
  458.         , (lstrlen(pszDesc)+1)*sizeof(TCHAR), NULL);
  459.     pIStream->Release();
  460.     return hr;
  461.     }
  462.  
  463.  
  464.  
  465.  
  466.  
  467. /*
  468.  * CFileObjectFactory::CFileObjectFactory
  469.  * CFileObjectFactory::~CFileObjectFactory
  470.  * CFileObjectFactory::QueryInterface
  471.  * CFileObjectFactory::AddRef
  472.  * CFileObjectFactory::Release
  473.  *
  474.  * Basic class factory members
  475.  */
  476.  
  477. CFileObjectFactory::CFileObjectFactory(void)
  478.     {
  479.     m_cRef=0L;
  480.     return;
  481.     }
  482.  
  483. CFileObjectFactory::~CFileObjectFactory(void)
  484.     {
  485.     return;
  486.     }
  487.  
  488. STDMETHODIMP CFileObjectFactory::QueryInterface(REFIID riid
  489.     , PPVOID ppv)
  490.     {
  491.     *ppv=NULL;
  492.  
  493.     if (IID_IUnknown==riid || IID_IClassFactory==riid)
  494.         *ppv=this;
  495.  
  496.     if (NULL!=*ppv)
  497.         {
  498.         ((LPUNKNOWN)*ppv)->AddRef();
  499.         return NOERROR;
  500.         }
  501.  
  502.     return ResultFromScode(E_NOINTERFACE);
  503.     }
  504.  
  505.  
  506. STDMETHODIMP_(ULONG) CFileObjectFactory::AddRef(void)
  507.     {
  508.     return ++m_cRef;
  509.     }
  510.  
  511.  
  512. STDMETHODIMP_(ULONG) CFileObjectFactory::Release(void)
  513.     {
  514.     if (0L!=--m_cRef)
  515.         return m_cRef;
  516.  
  517.     delete this;
  518.     return 0;
  519.     }
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526. /*
  527.  * CFileObjectFactory::CreateInstance
  528.  *
  529.  * Purpose:
  530.  *  Instantiates a LinkSrc object returning an interface pointer.
  531.  *
  532.  * Parameters:
  533.  *  pUnkOuter       LPUNKNOWN to the controlling IUnknown if we are
  534.  *                  being used in an aggregation.
  535.  *  riid            REFIID identifying the interface the caller
  536.  *                  desires to have for the new object.
  537.  *  ppvObj          PPVOID in which to store the desired
  538.  *                  interface pointer for the new object.
  539.  *
  540.  * Return Value:
  541.  *  HRESULT         NOERROR if successful, otherwise E_NOINTERFACE
  542.  *                  if we cannot support the requested interface.
  543.  */
  544.  
  545. STDMETHODIMP CFileObjectFactory::CreateInstance(LPUNKNOWN pUnkOuter
  546.     , REFIID riid, PPVOID ppvObj)
  547.     {
  548.     PCFileObject        pObj;
  549.     HRESULT             hr;
  550.  
  551.     *ppvObj=NULL;
  552.     hr=ResultFromScode(E_OUTOFMEMORY);
  553.  
  554.     if (NULL!=pUnkOuter && IID_IUnknown!=riid)
  555.         return ResultFromScode(CLASS_E_NOAGGREGATION);
  556.  
  557.     pObj=new CFileObject(pUnkOuter, ObjectDestroyed);
  558.  
  559.     if (NULL==pObj)
  560.         {
  561.         //This starts shutdown if there are no other objects.
  562.         g_cObj++;
  563.         ObjectDestroyed();
  564.         return hr;
  565.         }
  566.  
  567.     if (pObj->Init())
  568.         hr=pObj->QueryInterface(riid, ppvObj);
  569.  
  570.     g_cObj++;
  571.  
  572.     if (FAILED(hr))
  573.         {
  574.         delete pObj;
  575.         ObjectDestroyed();  //Handle shutdown cases.
  576.         }
  577.  
  578.     return hr;
  579.     }
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586. /*
  587.  * CFileObjectFactory::LockServer
  588.  *
  589.  * Purpose:
  590.  *  Increments or decrements the lock count of the serving
  591.  *  IClassFactory object.  When the number of locks goes to
  592.  *  zero and the number of objects is zero, we shut down the
  593.  *  application.
  594.  *
  595.  * Parameters:
  596.  *  fLock           BOOL specifying whether to increment or
  597.  *                  decrement the lock count.
  598.  *
  599.  * Return Value:
  600.  *  HRESULT         NOERROR always.
  601.  */
  602.  
  603. STDMETHODIMP CFileObjectFactory::LockServer(BOOL fLock)
  604.     {
  605.     if (fLock)
  606.         g_cLock++;
  607.     else
  608.         {
  609.         g_cLock--;
  610.         g_cObj++;
  611.         ObjectDestroyed();
  612.         }
  613.  
  614.     return NOERROR;
  615.     }
  616.