home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winui / shell / dropext / dropext.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  16.4 KB  |  575 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1994-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. //---------------------------------------------------------------------------
  13. //
  14. // File: dropext.c
  15. //
  16. //  This file contains a sample source code of context menu extension handler.
  17. //
  18. //---------------------------------------------------------------------------
  19.  
  20. #include "priv.h"
  21.  
  22. //
  23. // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
  24. //
  25. #pragma data_seg(".text")
  26. #define INITGUID
  27. #include <initguid.h>
  28. #include "dropext.h"
  29. #pragma data_seg()
  30.  
  31. //
  32. // Function prototypes
  33. //
  34. HRESULT CALLBACK DropExt_CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR*);
  35.  
  36. //
  37. // Global variables
  38. //
  39. UINT g_cRefThisDll = 0;        // Reference count of this DLL.
  40. UINT g_cfNetResource = 0;    // Clipboard format
  41.  
  42. //---------------------------------------------------------------------------
  43. // LibMain
  44. //---------------------------------------------------------------------------
  45. BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
  46. {
  47.     switch(dwReason)
  48.     {
  49.     case DLL_PROCESS_ATTACH:
  50.         break;
  51.     case DLL_PROCESS_DETACH:
  52.         break;
  53.  
  54.     case DLL_THREAD_DETACH:
  55.         break;
  56.  
  57.     case DLL_THREAD_ATTACH:
  58.     default:
  59.         break;
  60.     } // end switch()
  61.  
  62.     return TRUE;
  63. }
  64.  
  65. //---------------------------------------------------------------------------
  66. // DllCanUnloadNow
  67. //---------------------------------------------------------------------------
  68.  
  69. STDAPI DllCanUnloadNow(void)
  70. {
  71.     return ResultFromScode((g_cRefThisDll==0) ? S_OK : S_FALSE);
  72. }
  73.  
  74. //---------------------------------------------------------------------------
  75. //
  76. // DllGetClassObject
  77. //
  78. //  This is the entry of this DLL, which all the In-Proc server DLLs should
  79. // export. See the description of "DllGetClassObject" of OLE 2.0 reference
  80. // manual for detail.
  81. //
  82. //---------------------------------------------------------------------------
  83.  
  84. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppvOut)
  85. {
  86.     //
  87.     //  This DLL has only one class (CLSID_SampleDropExt). If a DLL supports
  88.     // multiple classes, it should have either multiple if-statements or
  89.     // efficient table lookup code.
  90.     //
  91.     if (IsEqualIID(rclsid, &CLSID_SampleDropExt))
  92.     {
  93.     //
  94.     //  We are supposed return the class object for this class. Instead
  95.     // of fully implementing it in this DLL, we just call a helper
  96.     // function in the shell DLL which creates a default class factory
  97.     // object for us. When its CreateInstance member is called, it
  98.     // will call back our create instance function (DropExt_CreateInstance).
  99.     //
  100.     return SHCreateDefClassObject(
  101.             riid,            //
  102.             ppvOut,            //
  103.             DropExt_CreateInstance, // callback function
  104.             &g_cRefThisDll,        // reference count of this DLL
  105.             &IID_IShellExtInit        // init interface
  106.             );
  107.     }
  108.  
  109.     return ResultFromScode(E_FAIL);
  110. }
  111.  
  112.  
  113. //---------------------------------------------------------------------------
  114. //
  115. // CSampleDropExt class
  116. //
  117. // In C++:
  118. //  class CSampleDropExt : protected IContextMenu, protected IShellExtInit
  119. //  {
  120. //  protected:
  121. //      UINT         _cRef;
  122. //      LPDATAOBJECT _pdtobj;
  123. //    HKEY         _hkeyProgID;
  124. //  public:
  125. //      CSampleDropExt() _cRef(1), _pdtobj(NULL), _hkeyProgID(NULL) {};
  126. //      ...
  127. //  };
  128. //
  129. //---------------------------------------------------------------------------
  130. typedef struct _CSampleDropExt    // smx
  131. {
  132.     IContextMenu    _ctm;           // 1st base class
  133.     IShellExtInit   _sxi;        // 2nd base class
  134.     UINT            _cRef;          // reference count
  135.     LPDATAOBJECT    _pdtobj;        // data object
  136.     HKEY        _hkeyProgID;    // reg. database key to ProgID
  137.     char        _szTargetFolder[MAX_PATH];
  138. } CSampleDropExt, * PSAMPLEDROPEXT;
  139.  
  140. #define SMX_OFFSETOF(x)            ((UINT)(&((PSAMPLEDROPEXT)0)->x))
  141. #define PVOID2PSMX(pv,offset)   ((PSAMPLEDROPEXT)(((LPBYTE)pv)-offset))
  142. #define PCTM2PSMX(pctm)            PVOID2PSMX(pctm, SMX_OFFSETOF(_ctm))
  143. #define PSXI2PSMX(psxi)            PVOID2PSMX(psxi, SMX_OFFSETOF(_sxi))
  144.  
  145. //
  146. // Vtable prototype
  147. //
  148. extern IContextMenuVtbl     c_SampleDropExt_CTMVtbl;
  149. extern IShellExtInitVtbl    c_SampleDropExt_SXIVtbl;
  150.  
  151. //---------------------------------------------------------------------------
  152. //
  153. // DropExt_CreateInstance
  154. //
  155. //  This function is called back from within IClassFactory::CreateInstance()
  156. // of the default class factory object, which is created by SHCreateClassObject.
  157. //
  158. //---------------------------------------------------------------------------
  159.  
  160. HRESULT CALLBACK DropExt_CreateInstance(LPUNKNOWN punkOuter,
  161.                         REFIID riid, LPVOID FAR* ppvOut)
  162. {
  163.     HRESULT hres;
  164.     PSAMPLEDROPEXT psmx;
  165.  
  166.     //
  167.     // Shell extentions typically does not support aggregation.
  168.     //
  169.     if (punkOuter) {
  170.     return ResultFromScode(CLASS_E_NOAGGREGATION);
  171.     }
  172.  
  173.     //
  174.     // in C++:
  175.     //  psmx = new CSampleDropExt();
  176.     //
  177.     psmx = LocalAlloc(LPTR, sizeof(CSampleDropExt));
  178.     if (!psmx) {
  179.     return ResultFromScode(E_OUTOFMEMORY);
  180.     }
  181.     psmx->_ctm.lpVtbl = &c_SampleDropExt_CTMVtbl;
  182.     psmx->_sxi.lpVtbl = &c_SampleDropExt_SXIVtbl;
  183.     psmx->_cRef = 1;
  184.     psmx->_pdtobj = NULL;
  185.     psmx->_hkeyProgID = NULL;
  186.     g_cRefThisDll++;
  187.  
  188.     //
  189.     // in C++:
  190.     //  hres = psmx->QueryInterface(riid, ppvOut);
  191.     //  psmx->Release();
  192.     //
  193.     // Note that the Release member will free the object, if QueryInterface
  194.     // failed.
  195.     //
  196.     hres = c_SampleDropExt_CTMVtbl.QueryInterface(&psmx->_ctm, riid, ppvOut);
  197.     c_SampleDropExt_CTMVtbl.Release(&psmx->_ctm);
  198.  
  199.     return hres;    // S_OK or E_NOINTERFACE
  200. }
  201.  
  202.  
  203. //---------------------------------------------------------------------------
  204. // CSampleDropExt::Initialize (IShellExtInit override)
  205. //---------------------------------------------------------------------------
  206. STDMETHODIMP DropExt_Initialize(LPSHELLEXTINIT psxi,
  207.         LPCITEMIDLIST pidlFolder,
  208.         LPDATAOBJECT pdtobj,
  209.         HKEY hkeyProgID)
  210. {
  211.     PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  212.  
  213.     // Initialize can be called more than once.
  214.     if (this->_pdtobj) {
  215.     this->_pdtobj->lpVtbl->Release(this->_pdtobj);
  216.     }
  217.  
  218.     if (this->_hkeyProgID) {
  219.     RegCloseKey(this->_hkeyProgID);
  220.     }
  221.  
  222.     // Duplicate the pdtobj pointer
  223.     if (pdtobj) {
  224.     this->_pdtobj = pdtobj;
  225.     pdtobj->lpVtbl->AddRef(pdtobj);
  226.     }
  227.  
  228.     // Duplicate the handle
  229.     if (hkeyProgID) {
  230.     RegOpenKeyEx(hkeyProgID, NULL, 0L, MAXIMUM_ALLOWED, &this->_hkeyProgID);
  231.     }
  232.  
  233.     // Get the path to the drop target folder
  234.     if (pidlFolder) {
  235.     SHGetPathFromIDList(pidlFolder, this->_szTargetFolder);
  236.     }
  237.  
  238.     return NOERROR;
  239. }
  240.  
  241. STDMETHODIMP DropExt_QueryContextMenu(LPCONTEXTMENU pctm,
  242.                                                HMENU hmenu,
  243.                                                UINT indexMenu,
  244.                                                UINT idCmdFirst,
  245.                                                UINT idCmdLast,
  246.                            UINT uFlags)
  247. {
  248.     UINT idCmd = idCmdFirst;
  249.     InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, "Check H&DROP (dropext)");
  250.     InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, "Check H&NRES (dropext)");
  251.     return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)2));
  252. }
  253.  
  254. //
  255. // Converts an offset to a string to a string pointer.
  256. //
  257. LPCSTR _Offset2Ptr(LPSTR pszBase, UINT offset, UINT * pcb)
  258. {
  259.     LPSTR pszRet;
  260.     if (offset==0) {
  261.     pszRet = NULL;
  262.     *pcb = 0;
  263.     } else {
  264.     pszRet = pszBase + offset;
  265.     *pcb = lstrlen(pszRet) + 1;
  266.     }
  267.     return pszRet;
  268. }
  269.  
  270. //
  271. // This is a helper routine which extracts a specified NETRESOURCE from hnres.
  272. //
  273. UINT DropExt_GetNetResource(HGLOBAL hnres, UINT iItem, LPNETRESOURCE pnresOut, UINT cbMax)
  274. {
  275.     LPNRESARRAY panr = GlobalLock(hnres);
  276.     UINT iRet = 0;    // assume error
  277.     if (hnres)
  278.     {
  279.     if (iItem==(UINT)-1)
  280.     {
  281.         iRet = panr->cItems;
  282.     }
  283.     else if (iItem < panr->cItems)
  284.     {
  285.         UINT cbProvider, cbRemoteName;
  286.         LPCSTR pszProvider = _Offset2Ptr((LPSTR)panr, (UINT)panr->nr[iItem].lpProvider, &cbProvider);
  287.         LPCSTR pszRemoteName = _Offset2Ptr((LPSTR)panr, (UINT)panr->nr[iItem].lpRemoteName, &cbRemoteName);
  288.         iRet = sizeof(NETRESOURCE) + cbProvider + cbRemoteName;
  289.         if (iRet <= cbMax)
  290.         {
  291.         LPSTR psz = (LPSTR)(pnresOut+1);
  292.         *pnresOut = panr->nr[iItem];
  293.         if (pnresOut->lpProvider) {
  294.             pnresOut->lpProvider = psz;
  295.             lstrcpy(psz, pszProvider);
  296.             psz += cbProvider;
  297.         }
  298.         if (pnresOut->lpRemoteName) {
  299.             pnresOut->lpRemoteName = psz;
  300.             lstrcpy(psz, pszRemoteName);
  301.         }
  302.         }
  303.     }
  304.     GlobalUnlock(hnres);
  305.     }
  306.     return iRet;
  307. }
  308.  
  309. HRESULT DropExt_CheckForHDROP(PSAMPLEDROPEXT this, HWND hwnd)
  310. {
  311.     FORMATETC fmte = {
  312.             CF_HDROP,
  313.             (DVTARGETDEVICE FAR *)NULL,
  314.             DVASPECT_CONTENT,
  315.             -1,
  316.             TYMED_HGLOBAL };
  317.     STGMEDIUM medium;
  318.     HRESULT hres = this->_pdtobj->lpVtbl->GetData(this->_pdtobj, &fmte, &medium);
  319.  
  320.     if (SUCCEEDED(hres))
  321.     {
  322.     HDROP hdrop = medium.hGlobal;
  323.     UINT cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
  324.     char szFile[MAX_PATH];
  325.     char szBuf[MAX_PATH*2+64];
  326.  
  327.     DragQueryFile(hdrop, 0, szFile, sizeof(szFile));
  328.     wsprintf(szBuf,
  329.          "The drop target is %s.\n"
  330.           "%d files/directories in HDROP\n"
  331.          "The path to the first object is\n"
  332.             "\t%s.",
  333.          this->_szTargetFolder,
  334.          cFiles,
  335.          szFile);
  336.  
  337.     MessageBox(hwnd, szBuf, "DropExt", MB_OK);
  338.  
  339.     //
  340.     // HACK: We are supposed to call ReleaseStgMedium. This is a temporary
  341.     //  hack until OLE 2.01 for Windows 95 is released.
  342.     //
  343.     if (medium.pUnkForRelease)
  344.     {
  345.         medium.pUnkForRelease->lpVtbl->Release(medium.pUnkForRelease);
  346.     }
  347.     else
  348.     {
  349.         GlobalFree(medium.hGlobal);
  350.     }
  351.     }
  352.     else
  353.     {
  354.     MessageBox(hwnd, "No file system object in the selection", "DropExt", MB_OK);
  355.     }
  356.  
  357.     return hres;
  358. }
  359.  
  360. HRESULT DropExt_CheckForHNRES(PSAMPLEDROPEXT this, HWND hwnd)
  361. {
  362.     FORMATETC fmte = {
  363.             g_cfNetResource ? g_cfNetResource
  364.             : (g_cfNetResource=RegisterClipboardFormat("Net Resource")),
  365.             (DVTARGETDEVICE FAR *)NULL,
  366.             DVASPECT_CONTENT,
  367.             -1,
  368.             TYMED_HGLOBAL };
  369.     STGMEDIUM medium;
  370.     HRESULT hres = this->_pdtobj->lpVtbl->GetData(this->_pdtobj, &fmte, &medium);
  371.     if (SUCCEEDED(hres))
  372.     {
  373.     HGLOBAL hnres = medium.hGlobal;
  374.     LPNETRESOURCE pnr = (LPNETRESOURCE)LocalAlloc(LPTR, 1024);
  375.  
  376.     if (pnr)
  377.     {
  378.         char szBuf[512];
  379.         UINT cItems = DropExt_GetNetResource(hnres, (UINT)-1, NULL, 0);
  380.  
  381.         // Get the NETRESOURCE of the first item
  382.         DropExt_GetNetResource(hnres, 0, pnr, 1024);
  383.  
  384.         wsprintf(szBuf,
  385.              "%d network resource objects in HNRES\n"
  386.              "The attributes of the first object are\n"
  387.              "\tProvider      = %s\n"
  388.              "\tRemoteName    = %s\n"
  389.              "\tdwDisplayType = %x\n"
  390.              "\tdwType        = %x\n"
  391.              "\tdwUsage       = %x\n",
  392.              cItems,
  393.              pnr->lpProvider,
  394.              pnr->lpRemoteName ? pnr->lpRemoteName : "N/A",
  395.              pnr->dwDisplayType,
  396.              pnr->dwType,
  397.              pnr->dwUsage);
  398.  
  399.         MessageBox(hwnd, szBuf, "DropExt", MB_OK);
  400.  
  401.         LocalFree(pnr);
  402.     }
  403.     else
  404.     {
  405.         hres = ResultFromScode(E_OUTOFMEMORY);
  406.     }
  407.  
  408.     //
  409.     // HACK: We are supposed to call ReleaseStgMedium. This is a temporary
  410.     //  hack until OLE 2.01 for Windows 95 is released.
  411.     //
  412.     if (medium.pUnkForRelease)
  413.     {
  414.         medium.pUnkForRelease->lpVtbl->Release(medium.pUnkForRelease);
  415.     }
  416.     else
  417.     {
  418.         GlobalFree(medium.hGlobal);
  419.     }
  420.     }
  421.     else
  422.     {
  423.     MessageBox(hwnd, "No network objects in the selection", "DropExt", MB_OK);
  424.     }
  425.     return hres;
  426. }
  427.  
  428. STDMETHODIMP DropExt_InvokeCommand(LPCONTEXTMENU pctm,
  429.                    LPCMINVOKECOMMANDINFO lpici)
  430. {
  431.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  432.     HRESULT hres = ResultFromScode(E_INVALIDARG);    // assume error
  433.     //
  434.     // No need to support string based command.
  435.     //
  436.     if (!HIWORD(lpici->lpVerb))
  437.     {
  438.     UINT idCmd = LOWORD(lpici->lpVerb);
  439.  
  440.     switch(idCmd)
  441.     {
  442.     case 0:
  443.         hres = DropExt_CheckForHDROP(this, lpici->hwnd);
  444.         break;
  445.  
  446.     case 1:
  447.         hres = DropExt_CheckForHNRES(this, lpici->hwnd);
  448.         break;
  449.     }
  450.     }
  451.     return hres;
  452. }
  453.  
  454. STDMETHODIMP DropExt_GetCommandString(
  455.                                         LPCONTEXTMENU pctm,
  456.                                         UINT        idCmd,
  457.                                         UINT        wReserved,
  458.                                         UINT FAR *  pwReserved,
  459.                                         LPSTR       pszName,
  460.                                         UINT        cchMax)
  461. {
  462.     return NOERROR;
  463. }
  464.  
  465. //---------------------------------------------------------------------------
  466. // CSampleDropExt::AddRef (IContextMenu override)
  467. //---------------------------------------------------------------------------
  468.  
  469. STDMETHODIMP_(UINT) DropExt_CTM_AddRef(LPCONTEXTMENU pctm)
  470. {
  471.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  472.     return ++this->_cRef;
  473. }
  474.  
  475.  
  476. //---------------------------------------------------------------------------
  477. // CSampleDropExt::AddRef (IShellExtInit override)
  478. //---------------------------------------------------------------------------
  479.  
  480. STDMETHODIMP_(UINT) DropExt_SXI_AddRef(LPSHELLEXTINIT psxi)
  481. {
  482.     PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  483.     return ++this->_cRef;
  484. }
  485.  
  486. //---------------------------------------------------------------------------
  487. // CSampleDropExt::Release (IContextMenu override)
  488. //---------------------------------------------------------------------------
  489.  
  490. STDMETHODIMP_(UINT) DropExt_CTM_Release(LPCONTEXTMENU pctm)
  491. {
  492.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  493.     if (--this->_cRef) {
  494.     return this->_cRef;
  495.     }
  496.  
  497.     if (this->_pdtobj) {
  498.     this->_pdtobj->lpVtbl->Release(this->_pdtobj);
  499.     }
  500.  
  501.     if (this->_hkeyProgID) {
  502.     RegCloseKey(this->_hkeyProgID);
  503.     }
  504.  
  505.     LocalFree((HLOCAL)this);
  506.     g_cRefThisDll--;
  507.  
  508.     return 0;
  509. }
  510.  
  511. //---------------------------------------------------------------------------
  512. // CSampleDropExt::Release (IShellExtInit thunk)
  513. //---------------------------------------------------------------------------
  514.  
  515. STDMETHODIMP_(UINT) DropExt_SXI_Release(LPSHELLEXTINIT psxi)
  516. {
  517.     PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  518.     return DropExt_CTM_Release(&this->_ctm);
  519. }
  520.  
  521. //---------------------------------------------------------------------------
  522. // CSampleDropExt::QueryInterface (IContextMenu override)
  523. //---------------------------------------------------------------------------
  524.  
  525. STDMETHODIMP DropExt_CTM_QueryInterface(LPCONTEXTMENU pctm, REFIID riid, LPVOID FAR* ppvOut)
  526. {
  527.     PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
  528.     if (IsEqualIID(riid, &IID_IContextMenu) || IsEqualIID(riid, &IID_IUnknown))
  529.     {
  530.         (LPCONTEXTMENU)*ppvOut=pctm;
  531.         this->_cRef++;
  532.         return NOERROR;
  533.     }
  534.     if (IsEqualIID(riid, &IID_IShellExtInit))
  535.     {
  536.         (LPSHELLEXTINIT)*ppvOut=&this->_sxi;
  537.         this->_cRef++;
  538.         return NOERROR;
  539.     }
  540.     return ResultFromScode(E_NOINTERFACE);
  541. }
  542.  
  543. //---------------------------------------------------------------------------
  544. // CSampleDropExt::QueryInterface (IShellExtInit thunk)
  545. //---------------------------------------------------------------------------
  546.  
  547. STDMETHODIMP DropExt_SXI_QueryInterface(LPSHELLEXTINIT psxi, REFIID riid, LPVOID FAR* ppv)
  548. {
  549.     PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
  550.     return DropExt_CTM_QueryInterface(&this->_ctm, riid, ppv);
  551. }
  552.  
  553.  
  554. //---------------------------------------------------------------------------
  555. // CSampleDropExt class : Vtables
  556. //---------------------------------------------------------------------------
  557.  
  558. #pragma data_seg(".text")
  559. IContextMenuVtbl c_SampleDropExt_CTMVtbl = {
  560.     DropExt_CTM_QueryInterface,
  561.     DropExt_CTM_AddRef,
  562.     DropExt_CTM_Release,
  563.     DropExt_QueryContextMenu,
  564.     DropExt_InvokeCommand,
  565.     DropExt_GetCommandString,
  566. };
  567.  
  568. IShellExtInitVtbl c_SampleDropExt_SXIVtbl = {
  569.     DropExt_SXI_QueryInterface,
  570.     DropExt_SXI_AddRef,
  571.     DropExt_SXI_Release,
  572.     DropExt_Initialize
  573. };
  574. #pragma data_seg()
  575.