Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

433 lines
11 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: MetaUtil object
  6. File: Utility.h
  7. Owner: t-BrianM
  8. This file contains implementation of the utility functions.
  9. ===================================================================*/
  10. #include "stdafx.h"
  11. #include "MetaUtil.h"
  12. #include "MUtilObj.h"
  13. /*------------------------------------------------------------------
  14. * U t i l i t i e s
  15. */
  16. /*===================================================================
  17. Report Error
  18. Sets up IErrorInfo. Does a simple FormatMessage and returns the
  19. correct HRESULT. Ripped from a-georgr's stuff.
  20. Parameters:
  21. hr HRESULT to return to caller
  22. dwErr Win32 error code to format message for
  23. Returns:
  24. hr
  25. ===================================================================*/
  26. HRESULT ReportError(HRESULT hr, DWORD dwErr)
  27. {
  28. HLOCAL pMsgBuf = NULL;
  29. // If there's a message associated with this error, report that
  30. if (::FormatMessage(
  31. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  32. NULL, dwErr,
  33. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  34. (LPTSTR) &pMsgBuf, 0, NULL)
  35. > 0)
  36. {
  37. AtlReportError(CLSID_MetaUtil, (LPCTSTR) pMsgBuf,
  38. IID_IMetaUtil, hr);
  39. }
  40. // TODO: add some error messages to the string resources and
  41. // return those, if FormatMessage doesn't return anything (not
  42. // all system errors have associated error messages).
  43. // Free the buffer, which was allocated by FormatMessage
  44. if (pMsgBuf != NULL)
  45. ::LocalFree(pMsgBuf);
  46. return hr;
  47. }
  48. // Report a Win32 error code
  49. HRESULT ReportError(DWORD dwErr)
  50. {
  51. return ::ReportError(HRESULT_FROM_WIN32(dwErr), dwErr);
  52. }
  53. // Report an HRESULT error
  54. HRESULT ReportError(HRESULT hr)
  55. {
  56. return ::ReportError(hr, (DWORD) hr);
  57. }
  58. /*===================================================================
  59. Cannonize Key
  60. Converts a key into cannonical form. To do this it does the following:
  61. o Removes leading slashes
  62. o Converts back-slashes to forward-slashes
  63. CONSIDER: Resolve . and ..
  64. CONSIDER: Case conversion
  65. Parameters:
  66. tszKey [in, out] Key to cannonize
  67. Returns:
  68. Nothing
  69. ===================================================================*/
  70. LPTSTR CannonizeKey(LPTSTR tszKey) {
  71. LPTSTR tszSrc;
  72. LPTSTR tszDest;
  73. tszSrc = tszKey;
  74. tszDest = tszKey;
  75. // Remove leading slashes
  76. while ((*tszSrc == _T('/')) || (*tszSrc == _T('\\'))) {
  77. tszSrc++;
  78. }
  79. // Convert slashes
  80. while (*tszSrc) {
  81. if (*tszSrc == _T('\\')) {
  82. *tszDest = _T('/');
  83. }
  84. else {
  85. *tszDest = *tszSrc;
  86. }
  87. tszSrc++;
  88. tszDest++;
  89. }
  90. *tszDest = '\0';
  91. return tszKey;
  92. }
  93. /*===================================================================
  94. Split Key
  95. Splits a key path into parent and child parts. For example:
  96. tszKey = "/LM/Root/Path1/Path2/Path3"
  97. tszParent = "/LM/Root/Path1/Path2"
  98. tszChild = "Path3"
  99. Parameters:
  100. tszKey [in] Key to split
  101. tszParent [out] Parent part of key (allocated for ADMINDATA_MAX_NAME_LEN)
  102. tszChild [out] Child part of key (allocated for ADMINDATA_MAX_NAME_LEN)
  103. Returns:
  104. Nothing
  105. ===================================================================*/
  106. void SplitKey(LPCTSTR tszKey, LPTSTR tszParent, LPTSTR tszChild) {
  107. ASSERT_STRING(tszKey);
  108. ASSERT(IsValidAddress(tszParent,ADMINDATA_MAX_NAME_LEN * sizeof(TCHAR), TRUE));
  109. ASSERT(IsValidAddress(tszChild,ADMINDATA_MAX_NAME_LEN * sizeof(TCHAR), TRUE));
  110. LPTSTR tszWork;
  111. // Copy the key to the parent
  112. _tcscpy(tszParent, tszKey);
  113. // Find the end of the parent
  114. tszWork = tszParent;
  115. while (*tszWork != _T('\0')) {
  116. tszWork++;
  117. }
  118. // Find the start of the child
  119. while ( (tszWork != tszParent) && (*tszWork != _T('/')) ) {
  120. tszWork--;
  121. }
  122. // Cut off and copy the child
  123. if (*tszWork == _T('/')) {
  124. // Multiple parts
  125. *tszWork = _T('\0');
  126. tszWork++;
  127. _tcscpy(tszChild, tszWork);
  128. }
  129. else if (*tszWork != _T('\0')) {
  130. // One part
  131. _tcscpy(tszChild, tszWork);
  132. *tszWork = _T('\0');
  133. }
  134. else {
  135. // No parts
  136. tszChild[0] = _T('\0');
  137. }
  138. }
  139. /*===================================================================
  140. Get Machine From Key
  141. Gets the machine name part of a full key path. Assumes that the machine
  142. name is the first component of the path. For example:
  143. tszKey = "/LM/Root/Path1/Path2/Path3"
  144. tszMachine = "LM"
  145. Parameters:
  146. tszKey [in] Full Key to get machine name of
  147. tszMachine [out] Machine name part of path (allocated for ADMINDATA_MAX_NAME_LEN)
  148. Returns:
  149. Nothing
  150. ===================================================================*/
  151. void GetMachineFromKey(LPCTSTR tszFullKey, LPTSTR tszMachine) {
  152. ASSERT_STRING(tszFullKey);
  153. ASSERT(IsValidAddress(tszMachine, ADMINDATA_MAX_NAME_LEN * sizeof(TCHAR), TRUE));
  154. int iSource;
  155. int iDest;
  156. iSource = 0;
  157. // Copy the machine name
  158. iDest = 0;
  159. while ((tszFullKey[iSource] != _T('/')) &&
  160. (tszFullKey[iSource] != _T('\0'))) {
  161. tszMachine[iDest] = tszFullKey[iSource];
  162. iSource++;
  163. iDest++;
  164. }
  165. // Cap it off with NULL
  166. tszMachine[iDest] = _T('\0');
  167. }
  168. /*===================================================================
  169. Key Is In Schema
  170. Determines if a full key path is or is part of the schema.
  171. For Example:
  172. TRUE
  173. "/Schema"
  174. "/Schema/Properties"
  175. "/Schema/Properties/Words"
  176. FALSE
  177. ""
  178. "/LM"
  179. "/LM/ROOT/Schema"
  180. "/LM/ROOT/Path/Schema"
  181. "/LM/ROOT/Path1/Path2"
  182. Parameters:
  183. tszKey [in] Key to evaluate
  184. Returns:
  185. TRUE if key is in the schema
  186. ===================================================================*/
  187. BOOL KeyIsInSchema(LPCTSTR tszFullKey) {
  188. ASSERT_STRING(tszFullKey);
  189. LPTSTR tszWork;
  190. // Remove the const so I can play with the read pointer
  191. tszWork = const_cast <LPTSTR> (tszFullKey);
  192. // Skip the slash
  193. if (*tszWork != _T('\0') && *tszWork == _T('/')) {
  194. tszWork++;
  195. }
  196. // Check for "schema\0" or "schema/"
  197. if ((_tcsicmp(tszWork, _T("schema")) == 0) ||
  198. (_tcsnicmp(tszWork, _T("schema/"), 7) == 0)) {
  199. return TRUE;
  200. }
  201. else {
  202. return FALSE;
  203. }
  204. }
  205. /*===================================================================
  206. Key Is In IISAdmin
  207. Determines if a full key path is or is part of IISAdmin.
  208. For Example:
  209. TRUE
  210. "/LM/IISAdmin"
  211. "/SomeMachine/IISAdmin"
  212. "/LM/IISAdmin/Extensions"
  213. "/LM/IISAdmin/Extensions/DCOMCLSIDs"
  214. FALSE
  215. ""
  216. "/LM"
  217. "/LM/ROOT/IISAdmin"
  218. "/LM/ROOT/Path/IISAdmin"
  219. "/LM/ROOT/Path1/Path2"
  220. Parameters:
  221. tszKey [in] Key to evaluate
  222. Returns:
  223. TRUE if key is in IISAdmin
  224. ===================================================================*/
  225. BOOL KeyIsInIISAdmin(LPCTSTR tszFullKey) {
  226. ASSERT_STRING(tszFullKey);
  227. LPTSTR tszWork;
  228. // Remove the const so I can play with the read pointer
  229. tszWork = const_cast <LPTSTR> (tszFullKey);
  230. // Skip leading slashes
  231. while (*tszWork == _T('/')) {
  232. tszWork++;
  233. }
  234. // Skip the machine name
  235. while ((*tszWork != _T('/')) && (*tszWork != _T('\0'))) {
  236. tszWork++;
  237. }
  238. // Skip the slash after the machine name
  239. if (*tszWork != '\0') {
  240. tszWork++;
  241. }
  242. // Check for "iisadmin\0" or "iisadmin/"
  243. if ((_tcsicmp(tszWork, _T("iisadmin")) == 0) ||
  244. (_tcsnicmp(tszWork, _T("iisadmin/"), 8) == 0)) {
  245. return TRUE;
  246. }
  247. else {
  248. return FALSE;
  249. }
  250. }
  251. //
  252. // VariantResolveDispatch
  253. // Convert an IDispatch VARIANT to a (non-Dispatch) VARIANT by
  254. // invoking its default property until the object that remains
  255. // is not an IDispatch. If the original VARIANT is not an IDispatch
  256. // then the behavior is identical to VariantCopyInd(), with the
  257. // exception that arrays are copied.
  258. //
  259. // Parameters:
  260. // pVarOut - if successful, the return value is placed here
  261. // pVarIn - the variant to copy
  262. // GUID& riidObj - the calling interface (for error reporting)
  263. // nObjID - the Object's name from the resource file
  264. //
  265. // pVarOut need not be initialized. Since pVarOut is a new
  266. // variant, the caller must VariantClear this object.
  267. //
  268. // Returns:
  269. // The result of calling IDispatch::Invoke. (either NOERROR or
  270. // the error resulting from the call to Invoke) may also return
  271. // E_OUTOFMEMORY if an allocation fails
  272. //
  273. // This function always calls Exception() if an error occurs -
  274. // this is because we need to call Exception() if an IDispatch
  275. // method raises an exception. Instead of having the client
  276. // worry about whether we called Exception() on its behalf or
  277. // not, we always raise the exception.
  278. //
  279. HRESULT
  280. VariantResolveDispatch(
  281. VARIANT* pVarIn,
  282. VARIANT* pVarOut)
  283. {
  284. ASSERT(pVarIn != NULL && pVarOut != NULL);
  285. VariantInit(pVarOut);
  286. HRESULT hrCopy;
  287. if (V_VT(pVarIn) & VT_BYREF)
  288. hrCopy = VariantCopyInd(pVarOut, pVarIn);
  289. else
  290. hrCopy = VariantCopy(pVarOut, pVarIn);
  291. if (FAILED(hrCopy))
  292. return ::ReportError(hrCopy);
  293. // Follow the IDispatch chain.
  294. while (V_VT(pVarOut) == VT_DISPATCH)
  295. {
  296. VARIANT varResolved; // value of IDispatch::Invoke
  297. DISPPARAMS dispParamsNoArgs = {NULL, NULL, 0, 0};
  298. EXCEPINFO ExcepInfo;
  299. HRESULT hrInvoke;
  300. // If the variant is equal to Nothing, then it can be argued
  301. // with certainty that it does not have a default property!
  302. // hence we return DISP_E_MEMBERNOTFOUND for this case.
  303. if (V_DISPATCH(pVarOut) == NULL)
  304. hrInvoke = DISP_E_MEMBERNOTFOUND;
  305. else
  306. {
  307. VariantInit(&varResolved);
  308. hrInvoke = V_DISPATCH(pVarOut)->Invoke(
  309. DISPID_VALUE,
  310. IID_NULL,
  311. LOCALE_SYSTEM_DEFAULT,
  312. DISPATCH_PROPERTYGET | DISPATCH_METHOD,
  313. &dispParamsNoArgs,
  314. &varResolved,
  315. &ExcepInfo,
  316. NULL);
  317. }
  318. if (FAILED(hrInvoke))
  319. {
  320. if (hrInvoke != DISP_E_EXCEPTION)
  321. hrInvoke = ::ReportError(hrInvoke);
  322. // for DISP_E_EXCEPTION, SetErrorInfo has already been called
  323. VariantClear(pVarOut);
  324. return hrInvoke;
  325. }
  326. // The correct code to restart the loop is:
  327. //
  328. // VariantClear(pVar)
  329. // VariantCopy(pVar, &varResolved);
  330. // VariantClear(&varResolved);
  331. //
  332. // however, the same affect can be achieved by:
  333. //
  334. // VariantClear(pVar)
  335. // *pVar = varResolved;
  336. // VariantInit(&varResolved)
  337. //
  338. // this avoids a copy. The equivalence rests in the fact that
  339. // *pVar will contain the pointers of varResolved, after we
  340. // trash varResolved (WITHOUT releasing strings or dispatch
  341. // pointers), so the net ref count is unchanged. For strings,
  342. // there is still only one pointer to the string.
  343. //
  344. // NOTE: the next iteration of the loop will do the VariantInit.
  345. VariantClear(pVarOut);
  346. *pVarOut = varResolved;
  347. }
  348. return S_OK;
  349. }