ui.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 15k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*----------------------------------------------------------------------------
  2. / Title;
  3. /   ui.cpp
  4. /
  5. / Authors;
  6. /   David De Vorchik (daviddv)
  7. /
  8. / Notes;
  9. /   Misc UI bits that are exploited by the namespace
  10. /----------------------------------------------------------------------------*/
  11. #include "pch.h"
  12. #pragma hdrstop
  13. //
  14. // This function is supposed to ultimately shutdown COM 
  15. // regardless of how many times CoInitialize(NULL) has
  16. // been called.
  17. //
  18. void ShutdownCOM()
  19. {
  20.     for( ;; )
  21.     {
  22.         //
  23.         // Call CoUninitialze() twice
  24.         //
  25.         CoUninitialize();
  26.         CoUninitialize();
  27.         //
  28.         // Call CoInitialize(NULL) to see whether this will be the first
  29.         // COM initialization. S_OK means COM is initialized successfully,
  30.         // S_FALSE means it has been initialized already.
  31.         //
  32.         HRESULT hr = CoInitialize(NULL);
  33.         if (SUCCEEDED(hr))
  34.         {
  35.             // S_OK, S_FALSE case
  36.             if (S_OK == hr)
  37.             {
  38.                 CoUninitialize();
  39.                 break;
  40.             }
  41.             else
  42.             {
  43.                 // The internal COM ref count
  44.                 // still hasn't reached zero
  45.                 continue;
  46.             }
  47.         }
  48.         else
  49.         {
  50.             // RPC_E_CHANGED_MODE case
  51.             if (RPC_E_CHANGED_MODE == hr)
  52.             {
  53.                 continue;
  54.             }
  55.             else
  56.             {
  57.                 // Some other failure
  58.                 // E_OUTOFMEMORY for example
  59.                 break;
  60.             }
  61.         }
  62.     }
  63. }
  64. /*-----------------------------------------------------------------------------
  65. / Globals etc used for icon extraction
  66. /----------------------------------------------------------------------------*/
  67. /*-----------------------------------------------------------------------------
  68. / GetKeysForIdList
  69. / ----------------
  70. /   Given an IDLIST (packed or unpacked) attempt to get return the registry
  71. /   keys that reflect that class of object.
  72. /
  73. / In:
  74. /   pidl / pData = packed/unpacked DS object information
  75. /   cKeys = number of keys to fetch
  76. /   aKeys = array to be filled
  77. /
  78. / Out:
  79. /   HRESULT
  80. /----------------------------------------------------------------------------*/
  81. HRESULT GetKeysForIdList(LPCITEMIDLIST pidl, LPIDLISTDATA pData, INT cKeys, HKEY* aKeys)
  82. {
  83.     HRESULT hres;
  84.     IDLISTDATA data;
  85.     TraceEnter(TRACE_UI, "GetKeysForIdList");
  86.     if ( !pData )
  87.     {
  88.         if ( !pidl )
  89.             ExitGracefully(hres, E_FAIL, "Must had IDLIST to expand");
  90.         hres = UnpackIdList(ILFindLastID(pidl), DSIDL_HASCLASS, &data);
  91.         FailGracefully(hres, "Failed to unpack IDLIST to a data structure");
  92.         pData = &data;
  93.     }
  94.     hres = GetKeysForClass(pData->pObjectClass, (pData->dwFlags & DSIDL_ISCONTAINER), cKeys, aKeys);
  95.     FailGracefully(hres, "GetKeysForClass failed");
  96.     //hres = S_OK;          // success
  97. exit_gracefully:
  98.     TraceLeaveResult(hres);
  99. }
  100. /*-----------------------------------------------------------------------------
  101. / GetKeysForClass
  102. / ---------------
  103. /   Given a class and the flags assocaited with that extract the keys that
  104. /   represent it.
  105. /
  106. / In:
  107. /   pObjectClass = class name to fetch keys for
  108. /   fIsConatiner = object is a container
  109. /   cKeys = number of keys to fetch
  110. /   aKeys = array to be filled with keys
  111. /
  112. / Out:
  113. /   HRESULT
  114. /----------------------------------------------------------------------------*/
  115. HRESULT GetKeysForClass(LPWSTR pObjectClass, BOOL fIsContainer, INT cKeys, HKEY* aKeys)
  116. {
  117.     HRESULT hres;
  118.     HKEY hkClasses = NULL;
  119.     CLSID clsidBase;
  120.     LPTSTR pMappedClass = NULL;
  121.     USES_CONVERSION;
  122.     TraceEnter(TRACE_UI, "GetKeysForClass");
  123.     if ( cKeys < UIKEY_MAX )
  124.         ExitGracefully(hres, E_INVALIDARG, "cKeys < UIKEY_MAX");
  125.     ZeroMemory(aKeys, SIZEOF(HKEY)*cKeys);
  126.     hres = GetKeyForCLSID(CLSID_MicrosoftDS, c_szClasses, &hkClasses);
  127.     FailGracefully(hres, "Failed to get Classes key from registry");
  128.     //
  129.     // Attempt to look up the class name in the registery under the namespaces "classes"
  130.     // sub key.  A class can also be mapped onto another one, if this happens then we have
  131.     // a base CLASS key which we indirect via
  132.     // 
  133.     if ( pObjectClass )
  134.     {
  135.         if ( ERROR_SUCCESS == RegOpenKeyEx(hkClasses, W2T(pObjectClass), NULL, KEY_READ, &aKeys[UIKEY_CLASS]) )
  136.         {
  137.             if ( SUCCEEDED(LocalQueryString(&pMappedClass, aKeys[UIKEY_CLASS], c_szClass)) )
  138.             {
  139.                 if ( ERROR_SUCCESS != RegOpenKeyEx(hkClasses, pMappedClass, NULL, KEY_READ, &aKeys[UIKEY_BASECLASS]) )
  140.                 {
  141.                     aKeys[UIKEY_BASECLASS] = NULL;
  142.                 }
  143.             }
  144.         }
  145.     }
  146.     //
  147.     // Finally we need the root class (container or object)
  148.     //
  149.     hres =  GetKeyForCLSID(CLSID_MicrosoftDS, (fIsContainer) ? c_szAllContainers:c_szAllObjects, &aKeys[UIKEY_ROOT]);
  150.     FailGracefully(hres, "Failed to get root key");
  151.     // hres = S_OK;          // success
  152. exit_gracefully:
  153.     LocalFreeString(&pMappedClass);
  154.     if ( hkClasses )
  155.         RegCloseKey(hkClasses);
  156.     TraceLeaveResult(hres);
  157. }
  158. /*-----------------------------------------------------------------------------
  159. / TidyKeys
  160. / --------
  161. /   Given an array of keys release them and set them back to zero.
  162. /
  163. / In:
  164. /   cKeys = number of keys in array
  165. /   aKeys = keys to be released
  166. /
  167. / Out:
  168. /   void
  169. /----------------------------------------------------------------------------*/
  170. void TidyKeys(INT cKeys, HKEY* aKeys)
  171. {
  172.     TraceEnter(TRACE_UI, "TidyKeys");
  173.     while ( --cKeys >= 0 )
  174.     {
  175.         if ( aKeys[cKeys] )
  176.         {
  177.             RegCloseKey(aKeys[cKeys]);
  178.             aKeys[cKeys] = NULL;            // key now closed
  179.         }
  180.     }
  181.     TraceLeaveVoid();
  182. }
  183. /*-----------------------------------------------------------------------------
  184. / ShowObjectProperties
  185. / --------------------
  186. /   Display properties for the given objects.  This we do by invoking
  187. /   the tab collector for the given IDataObject.  First however we
  188. /   look inside the object and see if we can find out what objects
  189. /   were selected, having done that we can then find the HKEYs
  190. /
  191. / In:
  192. /   hwndParent = parent dialog
  193. /   pDataObject = data object that we must use
  194. /
  195. / Out:
  196. /   HRESULT
  197. /----------------------------------------------------------------------------*/
  198. HRESULT _OverrideProperties(HWND hwndParent, LPDATAOBJECT pDataObject, HKEY* aKeys, INT cKeys, LPCWSTR pPrefix)
  199. {
  200.     HRESULT hres;
  201.     LPTSTR pPropertiesGUID = NULL;
  202.     GUID guidProperties;
  203.     IDsFolderProperties* pDsFolderProperties = NULL;
  204.     TCHAR szBuffer[MAX_PATH];
  205.     INT i;
  206.     USES_CONVERSION;
  207.     TraceEnter(TRACE_UI, "_OverrideProperties");
  208.     // walk all the keys we were given, some will be NULL so ignore those
  209.     StrCpy(szBuffer, W2CT(pPrefix));
  210.     StrCat(szBuffer, c_szDsPropertyUI);
  211.     Trace(TEXT("Prefixed property handler value: %s"), szBuffer);
  212.     for ( i = 0 ; i < cKeys ; i++ )
  213.     {
  214.         LocalFreeString(&pPropertiesGUID);
  215.         if ( aKeys[i] )
  216.         {
  217.             // if we have a handle attempt to get the GUID string from the registry
  218.             // and convert it to a GUID so that we can call CoCreateInstance for the
  219.             // IDsFolderProperites interface.
  220.             if ( FAILED(LocalQueryString(&pPropertiesGUID, aKeys[i], szBuffer)) )
  221.             {
  222.                 TraceMsg("Trying non-prefixed property handler");
  223.                 if ( FAILED(LocalQueryString(&pPropertiesGUID, aKeys[i], c_szDsPropertyUI)) )
  224.                     continue;
  225.             }
  226.             Trace(TEXT("GUID is: %s"), pPropertiesGUID);
  227.             if ( !GetGUIDFromString(pPropertiesGUID, &guidProperties) )
  228.             {
  229.                 TraceMsg("Failed to parse GUID");
  230.                 continue;
  231.             }
  232.             if ( SUCCEEDED(CoCreateInstance(guidProperties, NULL, CLSCTX_INPROC_SERVER, 
  233.                                             IID_IDsFolderProperties, (LPVOID*)&pDsFolderProperties)) )
  234.             {
  235.                 TraceMsg("Calling IDsFolderProperties::ShowProperties");                    
  236.                 hres = pDsFolderProperties->ShowProperties(hwndParent, pDataObject);
  237.                 FailGracefully(hres, "Failed when calling ShowProperties");            
  238.                 goto exit_gracefully;
  239.             }
  240.         }   
  241.     }
  242.     hres = S_FALSE;               // S_FALSE indicates that the caller should display properties
  243. exit_gracefully:
  244.     LocalFreeString(&pPropertiesGUID);
  245.     DoRelease(pDsFolderProperties);
  246.     TraceLeaveResult(hres);
  247. }
  248. typedef struct
  249. {
  250.     HWND hwndParent;
  251.     IStream* pStream;
  252. } PROPERTIESTHREADDATA;
  253. DWORD WINAPI _ShowObjectPropertiesThread(LPVOID lpParam)
  254. {
  255.     HRESULT hres;
  256.     PROPERTIESTHREADDATA* pThreadData = (PROPERTIESTHREADDATA*)lpParam;
  257.     IADsPathname* pPathname = NULL;
  258.     IDataObject* pDataObject = NULL;
  259.     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  260.     STGMEDIUM mediumNames = { TYMED_NULL, NULL, NULL };
  261.     STGMEDIUM mediumOptions = { TYMED_NULL, NULL, NULL };
  262.     LPDSOBJECTNAMES pDsObjects;
  263.     LPDSDISPLAYSPECOPTIONS pDispSpecOptions;
  264.     HKEY hKeys[3] = { NULL, NULL, NULL };
  265.     LPTSTR pTitle = NULL;
  266.     LPCWSTR pPrefix = DS_PROP_SHELL_PREFIX;
  267.     BSTR bstrName = NULL;
  268.     INT i;
  269.     USES_CONVERSION;
  270.     TraceEnter(TRACE_UI, "ShowObjectPropertiesThread");
  271.     CoInitialize(NULL);
  272.     RegisterDsClipboardFormats();
  273.     hres = CoGetInterfaceAndReleaseStream(pThreadData->pStream, IID_IDataObject, (void**)&pDataObject);
  274.     FailGracefully(hres, "Failed to get data object from stream");       
  275.    
  276.     // get the object names that we are showing properites on
  277.     fmte.cfFormat = g_cfDsObjectNames;          
  278.     hres = pDataObject->GetData(&fmte, &mediumNames);
  279.     FailGracefully(hres, "Failed to get selected objects");
  280.     pDsObjects = (LPDSOBJECTNAMES)mediumNames.hGlobal;
  281.     // get the attribute prefix, use this to key information from the registry
  282.     fmte.cfFormat = g_cfDsDispSpecOptions;
  283.     if ( SUCCEEDED(pDataObject->GetData(&fmte, &mediumOptions)) )
  284.     {
  285.         pDispSpecOptions = (LPDSDISPLAYSPECOPTIONS)mediumOptions.hGlobal;
  286.         pPrefix = (LPCWSTR)ByteOffset(pDispSpecOptions, pDispSpecOptions->offsetAttribPrefix);
  287.     }
  288.     Trace(TEXT("Attribute prefix is: %s"), W2CT(pPrefix));
  289.     if ( pDsObjects && (pDsObjects->cItems >= 1) )
  290.     {
  291.         LPWSTR pPath = (LPWSTR)ByteOffset(pDsObjects, pDsObjects->aObjects[0].offsetName);
  292.         LPWSTR pObjectClass = (LPWSTR)ByteOffset(pDsObjects, pDsObjects->aObjects[0].offsetClass);
  293.         BOOL fSelection = ( pDsObjects->cItems > 1 );
  294.         Trace(TEXT("Items %d, 1st object: %s, 1st Class: %s"), pDsObjects->cItems, W2T(pPath), W2T(pObjectClass));
  295.         // attempt to pick up the keys for the first element in the selection and get
  296.         // the keys that map to that object
  297.         hres = GetKeysForClass(pObjectClass,
  298.                              (pDsObjects->aObjects[0].dwFlags & DSOBJECT_ISCONTAINER), 
  299.                              ARRAYSIZE(hKeys), hKeys);
  300.         FailGracefully(hres, "Failed to get keys for class");       
  301.         hres = _OverrideProperties(pThreadData->hwndParent, pDataObject, hKeys, ARRAYSIZE(hKeys), pPrefix);
  302.         FailGracefully(hres, "Failed when trying to call out for properties");
  303.         // if the caller returns S_FALSE then we assume that they want us to display 
  304.         // the property pages for the given selection, so do so.
  305.         if ( hres == S_FALSE )
  306.         {
  307.             hres = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (LPVOID*)&pPathname);
  308.             FailGracefully(hres, "Failed to get the IADsPathname interface");
  309.             hres = pPathname->Set(pPath, ADS_SETTYPE_FULL);
  310.             FailGracefully(hres, "Failed to set the path of the name");
  311.             pPathname->SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  312.             hres = pPathname->Retrieve(ADS_FORMAT_LEAF, &bstrName);
  313.             FailGracefully(hres, "Failed to get the leaf element");
  314.             hres = FormatMsgResource(&pTitle, 
  315.                                     GLOBAL_HINSTANCE, (fSelection) ? IDS_LARGESEL:IDS_SINGLESEL, 
  316.                                     W2T(bstrName));
  317.             
  318.             FailGracefully(hres, "Failed to format dialog title");
  319.             if ( !SHOpenPropSheet(pTitle, hKeys, ARRAYSIZE(hKeys), NULL, pDataObject, NULL, NULL) )
  320.                 ExitGracefully(hres, E_FAIL, "Failed to open property pages");
  321.         }
  322.     }
  323.     hres = S_OK;
  324. exit_gracefully:
  325.     ReleaseStgMedium(&mediumNames);
  326.     ReleaseStgMedium(&mediumOptions);
  327.     TidyKeys(ARRAYSIZE(hKeys), hKeys);
  328.     LocalFreeString(&pTitle);
  329.     SysFreeString(bstrName);
  330.     DoRelease(pPathname);
  331.     DoRelease(pDataObject);
  332.     LocalFree(pThreadData);
  333. #ifdef WINNT
  334.     //
  335.     // We need to shutdwn COM ultimately here as we don't 
  336.     // know how many times CoInitialize(NULL) has been called.
  337.     // Otherwise COM is trying to shutdown itself inside compobj!DllMain,
  338.     // while holding the loader lock which  is causing a very bad deadlock.
  339.     // For more information see bug #395293.
  340.     //
  341.     // However we need to brace this code as NT specific code because 
  342.     // otherwise it may cause problems with the Win9x DSUI client for
  343.     // some weird reason.
  344.     //
  345.     ShutdownCOM();
  346. #endif // WINNT
  347.     TraceLeave();
  348.     InterlockedDecrement(&GLOBAL_REFCOUNT);
  349.     ExitThread(0);
  350.     return 0;
  351. }
  352. HRESULT ShowObjectProperties(HWND hwndParent, LPDATAOBJECT pDataObject)
  353. {
  354.     HRESULT hres;
  355.     PROPERTIESTHREADDATA* pThreadData;
  356.     DWORD dwId;
  357.     HANDLE hThread;
  358.     TraceEnter(TRACE_UI, "ShowObjectProperties");
  359.     // Allocate thread data for the new object we are launching
  360.     pThreadData = (PROPERTIESTHREADDATA*)LocalAlloc(LPTR, SIZEOF(PROPERTIESTHREADDATA));
  361.     TraceAssert(pThreadData);
  362.     if ( !pThreadData )
  363.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate thread data");
  364.     // we have thread data lets fill it and spin the properties thread.
  365.     pThreadData->hwndParent = hwndParent;
  366.     hres = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &(pThreadData->pStream));
  367.     FailGracefully(hres, "Failed to create marshaling object");
  368.     InterlockedIncrement(&GLOBAL_REFCOUNT);
  369.     hThread = CreateThread(NULL, 0, _ShowObjectPropertiesThread, (LPVOID)pThreadData, 0, &dwId);
  370.     TraceAssert(hThread);
  371.     if ( !hThread )
  372.     {
  373.         LocalFree(pThreadData);
  374.         InterlockedDecrement(&GLOBAL_REFCOUNT);
  375.         ExitGracefully(hres, E_UNEXPECTED, "Failed to kick off the thread");
  376.     }
  377.     CloseHandle(hThread);
  378.     hres = S_OK;
  379. exit_gracefully:
  380.     
  381.     TraceLeaveResult(hres);
  382. }