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.

651 lines
16 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1995 **
  4. //*********************************************************************
  5. //
  6. // HELPERS.CPP
  7. //
  8. // HISTORY:
  9. //
  10. // 9/01/95 philco Created.
  11. //
  12. //
  13. #include <cdlpch.h>
  14. BOOL GetEXEName(LPSTR szCmdLine);
  15. ///////*********** Helper functions *********/////////////
  16. /*******************************************************************
  17. NAME: Unicode2Ansi
  18. SYNOPSIS: Converts a unicode widechar string to ansi (MBCS)
  19. NOTES: Caller must free out parameter using delete
  20. ********************************************************************/
  21. HRESULT Unicode2Ansi(const wchar_t *src, char ** dest)
  22. {
  23. if ((src == NULL) || (dest == NULL))
  24. return E_INVALIDARG;
  25. // find out required buffer size and allocate it.
  26. int len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
  27. *dest = new char [len*sizeof(char)];
  28. if (!*dest)
  29. return E_OUTOFMEMORY;
  30. // Now do the actual conversion
  31. if ((WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len*sizeof(char),
  32. NULL, NULL)) != 0)
  33. return S_OK;
  34. else
  35. return E_FAIL;
  36. }
  37. /*******************************************************************
  38. NAME: Ansi2Unicode
  39. SYNOPSIS: Converts an ansi (MBCS) string to unicode.
  40. Notes: Caller must free out parameter using delete
  41. ********************************************************************/
  42. HRESULT Ansi2Unicode(const char * src, wchar_t **dest)
  43. {
  44. if ((src == NULL) || (dest == NULL))
  45. return E_INVALIDARG;
  46. // find out required buffer size and allocate it
  47. int len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, -1, NULL, 0);
  48. *dest = new WCHAR [len*sizeof(WCHAR)];
  49. if (!*dest)
  50. return E_OUTOFMEMORY;
  51. // Do the actual conversion.
  52. if ((MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, -1, *dest,
  53. len*sizeof(wchar_t))) != 0)
  54. return S_OK;
  55. else
  56. return E_FAIL;
  57. }
  58. /*******************************************************************
  59. NAME: ConvertANSItoCLSID
  60. SYNOPSIS: Converts an ANSI string to a CLSID structure (address
  61. of which is passed by caller as an [out] parameter)
  62. ********************************************************************/
  63. HRESULT ConvertANSItoCLSID(const char *pszCLSID, CLSID * clsid)
  64. {
  65. ASSERT(pszCLSID != NULL);
  66. ASSERT(clsid != NULL);
  67. HRESULT hr = S_OK;
  68. LPOLESTR wcstr = NULL;
  69. // Since OLE is Unicode only, we need to convert pszClsid to Unicode.
  70. hr = Ansi2Unicode(pszCLSID, &wcstr);
  71. if (FAILED(hr))
  72. goto cleanup;
  73. // Get CLSID from string
  74. hr = CLSIDFromString(wcstr, clsid);
  75. if (FAILED(hr))
  76. goto cleanup;
  77. cleanup:
  78. if (wcstr != NULL)
  79. delete wcstr; // Delete unicode string. We're done.
  80. return hr;
  81. }
  82. /*******************************************************************
  83. NAME: ConvertFriendlyANSItoCLSID
  84. SYNOPSIS: Works like ConvertANSItoCLSID but allows prefix
  85. of "clsid:" CLSID is passed as [out]
  86. parameter.
  87. ********************************************************************/
  88. HRESULT ConvertFriendlyANSItoCLSID(char *pszCLSID, CLSID * clsid)
  89. {
  90. static const char *szClsid = "clsid:";
  91. ASSERT(pszCLSID != NULL);
  92. ASSERT(clsid != NULL);
  93. HRESULT hr = S_OK;
  94. // try OLE form.
  95. hr = ConvertANSItoCLSID(pszCLSID,clsid);
  96. if (SUCCEEDED(hr))
  97. goto cleanup;
  98. // try for prefix "clsid:"
  99. if (StrCmpNA(pszCLSID, szClsid, lstrlenA(szClsid)) == 0) {
  100. hr = ConvertANSItoCLSID(pszCLSID + lstrlenA(szClsid), clsid);
  101. if (SUCCEEDED(hr))
  102. goto cleanup;
  103. // construct COM form of clsid:
  104. LPSTR szTmp = NULL;
  105. szTmp = new char[lstrlenA(pszCLSID) - lstrlenA(szClsid) + 2 + 1];
  106. if (!szTmp) {
  107. hr = E_OUTOFMEMORY;
  108. goto cleanup;
  109. }
  110. lstrcpyA(szTmp,"{");
  111. lstrcatA(szTmp,pszCLSID + lstrlenA(szClsid));
  112. lstrcatA(szTmp,"}");
  113. hr = ConvertANSItoCLSID(szTmp,clsid);
  114. delete [] szTmp;
  115. if (SUCCEEDED(hr))
  116. goto cleanup;
  117. }
  118. // error code passes through
  119. cleanup:
  120. return hr;
  121. }
  122. // ---------------------------------------------------------------------------
  123. // %%Function: GetExtnAndBaseFileName
  124. //
  125. // Parameters:
  126. // in szName: a filename or URL
  127. // out update pbasefilename to point into this szName
  128. //
  129. // Returns:
  130. // out: extn
  131. // ---------------------------------------------------------------------------
  132. FILEXTN GetExtnAndBaseFileName( char *szName, char **plpBaseFileName)
  133. {
  134. char *pCur = szName;
  135. char *pExt = NULL;
  136. char szExtCopy[4];
  137. FILEXTN extn = FILEXTN_UNKNOWN;
  138. const static char *szCAB = "CAB";
  139. const static char *szINF = "INF";
  140. const static char *szDLL = "DLL";
  141. const static char *szOCX = "OCX";
  142. const static char *szEXE = "EXE";
  143. const static char *szOSD = "OSD";
  144. const static char *szCAT = "CAT";
  145. *plpBaseFileName = szName;
  146. // find location of last '.' and '/' in name
  147. for (;*pCur; *pCur++) {
  148. if (*pCur == '.')
  149. pExt = pCur+1;
  150. if ((*pCur == '/') || (*pCur == '\\'))
  151. *plpBaseFileName = pCur+1;
  152. }
  153. if (!pExt || !*pExt) { // if no '.' or as last char
  154. extn = FILEXTN_NONE;
  155. goto Exit;
  156. }
  157. StrNCpy(szExtCopy, pExt, 4);
  158. CharUpperBuff(szExtCopy, 3);
  159. if (lstrcmp(szExtCopy, szCAB) == 0) {
  160. extn = FILEXTN_CAB;
  161. goto Exit;
  162. }
  163. if (lstrcmp(szExtCopy, szOCX) == 0) {
  164. extn = FILEXTN_OCX;
  165. goto Exit;
  166. }
  167. if (lstrcmp(szExtCopy, szDLL) == 0) {
  168. extn = FILEXTN_DLL;
  169. goto Exit;
  170. }
  171. if (lstrcmp(szExtCopy, szEXE) == 0) {
  172. extn = FILEXTN_EXE;
  173. goto Exit;
  174. }
  175. if (lstrcmp(szExtCopy, szINF) == 0) {
  176. extn = FILEXTN_INF;
  177. goto Exit;
  178. }
  179. if (lstrcmp(szExtCopy, szOSD) == 0) {
  180. extn = FILEXTN_OSD;
  181. goto Exit;
  182. }
  183. if (lstrcmp(szExtCopy, szCAT) == 0) {
  184. extn = FILEXTN_CAT;
  185. goto Exit;
  186. }
  187. Exit:
  188. return extn;
  189. }
  190. // ---------------------------------------------------------------------------
  191. // %%Function: GetVersionFromString
  192. //
  193. // converts version in text format (a,b,c,d) into two dwords (a,b), (c,d)
  194. // The printed version number is of format a.b.d (but, we don't care)
  195. // ---------------------------------------------------------------------------
  196. HRESULT
  197. GetVersionFromString(const char *szBuf, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS, char cSeperator)
  198. {
  199. // cdl.h defines cSeperator as a default parameter: ','
  200. const char *pch = szBuf;
  201. char ch;
  202. char szMaxString[30];
  203. *pdwFileVersionMS = 0;
  204. *pdwFileVersionLS = 0;
  205. if (!pch) // default to zero if none provided
  206. return S_OK;
  207. wsprintf(szMaxString, "-1%c-1%c-1%c-1", cSeperator, cSeperator, cSeperator);
  208. if (lstrcmp(pch, szMaxString) == 0) {
  209. *pdwFileVersionMS = 0xffffffff;
  210. *pdwFileVersionLS = 0xffffffff;
  211. return S_OK;
  212. }
  213. USHORT n = 0;
  214. USHORT a = 0;
  215. USHORT b = 0;
  216. USHORT c = 0;
  217. USHORT d = 0;
  218. enum HAVE { HAVE_NONE, HAVE_A, HAVE_B, HAVE_C, HAVE_D } have = HAVE_NONE;
  219. for (ch = *pch++;;ch = *pch++) {
  220. if ((ch == cSeperator) || (ch == '\0')) {
  221. switch (have) {
  222. case HAVE_NONE:
  223. a = n;
  224. have = HAVE_A;
  225. break;
  226. case HAVE_A:
  227. b = n;
  228. have = HAVE_B;
  229. break;
  230. case HAVE_B:
  231. c = n;
  232. have = HAVE_C;
  233. break;
  234. case HAVE_C:
  235. d = n;
  236. have = HAVE_D;
  237. break;
  238. case HAVE_D:
  239. return E_INVALIDARG; // invalid arg
  240. }
  241. if (ch == '\0') {
  242. // all done convert a,b,c,d into two dwords of version
  243. *pdwFileVersionMS = ((a << 16)|b);
  244. *pdwFileVersionLS = ((c << 16)|d);
  245. return S_OK;
  246. }
  247. n = 0; // reset
  248. } else if ( (ch < '0') || (ch > '9'))
  249. return E_INVALIDARG; // invalid arg
  250. else
  251. n = n*10 + (ch - '0');
  252. } /* end forever */
  253. // NEVERREACHED
  254. }
  255. //************************************************************
  256. // CheckFileImplementsCLSID
  257. //
  258. // checks if a clsid is implemented by the given file
  259. // Return S_OK on success.
  260. //
  261. // pszFileName: Full path to the file whose clsid we
  262. // desire.
  263. // rClsid: clsid to check
  264. //
  265. HRESULT CheckFileImplementsCLSID(const char *pszFileName, REFCLSID rClsid)
  266. {
  267. LPTYPELIB ptlib = NULL;
  268. LPTYPEINFO lpTypeInfo = NULL;
  269. LPTYPEATTR lpTypeAttr = NULL;
  270. WCHAR puszFileName[MAX_PATH]; // unicode string
  271. HRESULT hr = S_OK;
  272. //
  273. // LoadTypeLib() needs the string in unicode.
  274. //
  275. MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, puszFileName, sizeof(puszFileName) / sizeof(wchar_t));
  276. hr = LoadTypeLib(puszFileName, &ptlib);
  277. if (FAILED(hr))
  278. return hr;
  279. hr = ptlib->GetTypeInfoOfGuid(rClsid, &lpTypeInfo);
  280. if (SUCCEEDED(hr)) {
  281. if (S_OK != (hr = lpTypeInfo->GetTypeAttr(&lpTypeAttr))) {
  282. goto Exit;
  283. }
  284. if (TKIND_COCLASS == lpTypeAttr->typekind) {
  285. Assert(IsEqualGUID( lpTypeAttr->guid, rClsid));
  286. // success
  287. goto Exit;
  288. }
  289. }
  290. Exit:
  291. if (lpTypeAttr != NULL) lpTypeInfo->ReleaseTypeAttr(lpTypeAttr);
  292. if (lpTypeInfo != NULL) lpTypeInfo->Release();
  293. if (ptlib != NULL) ptlib->Release();
  294. return hr;
  295. }
  296. HRESULT CDLDupWStr( LPWSTR *pszwstrDst, LPCWSTR szwSrc )
  297. {
  298. HRESULT hr = S_OK;
  299. *pszwstrDst = new WCHAR[lstrlenW(szwSrc)+1];
  300. if (*pszwstrDst)
  301. StrCpyW( *pszwstrDst, szwSrc );
  302. else
  303. hr = E_OUTOFMEMORY;
  304. return hr;
  305. }
  306. extern CMutexSem g_mxsCodeDownloadGlobals;
  307. HRESULT
  308. MakeUniqueTempDirectory(LPCSTR szTempDir, LPSTR szUniqueTempDir, int iLen)
  309. {
  310. int n = 1;
  311. HRESULT hr = S_OK;
  312. //execute entire function under critical section
  313. CLock lck(g_mxsCodeDownloadGlobals);
  314. do {
  315. if (n > 100) // avoid infinite loop!
  316. break;
  317. wnsprintf(szUniqueTempDir, iLen-1, "%s%s%d.tmp", szTempDir, "ICD", n++);
  318. } while (GetFileAttributes(szUniqueTempDir) != -1);
  319. if (!CreateDirectory(szUniqueTempDir, NULL)) {
  320. hr = HRESULT_FROM_WIN32(GetLastError());
  321. }
  322. return hr;
  323. }
  324. HRESULT
  325. ComposeHackClsidFromMime(LPSTR szHackMimeType, int iLen, LPCSTR szClsid)
  326. {
  327. HRESULT hr = S_OK;
  328. char szID[MAX_PATH];
  329. LPSTR pchDest = szID;
  330. for (LPCSTR pchSrc = szClsid; *pchDest = *pchSrc; pchSrc++,pchDest++) {
  331. if (*pchSrc == '/') {
  332. *pchDest++ = '_';
  333. *pchDest++ = '2';
  334. *pchDest++ = 'F';
  335. *pchDest = '_';
  336. }
  337. }
  338. wnsprintf(szHackMimeType, iLen-1, "&CLSID=%s", szID);
  339. return hr;
  340. }
  341. HRESULT
  342. RemoveDirectoryAndChildren(LPCSTR szDir)
  343. {
  344. HRESULT hr = S_OK;
  345. HANDLE hf = INVALID_HANDLE_VALUE;
  346. char szBuf[MAX_PATH];
  347. WIN32_FIND_DATA fd;
  348. if (RemoveDirectory(szDir))
  349. goto Exit;
  350. // ha! we have a case where the directory is probbaly not empty
  351. StrNCpy(szBuf, szDir, sizeof(szBuf));
  352. StrCatBuff(szBuf, "\\*", sizeof(szBuf));
  353. if ((hf = FindFirstFile(szBuf, &fd)) == INVALID_HANDLE_VALUE) {
  354. hr = HRESULT_FROM_WIN32(GetLastError());
  355. goto Exit;
  356. }
  357. do {
  358. if ( (lstrcmp(fd.cFileName, ".") == 0) ||
  359. (lstrcmp(fd.cFileName, "..") == 0))
  360. continue;
  361. wnsprintf(szBuf, sizeof(szBuf)-1, "%s\\%s", szDir, fd.cFileName);
  362. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  363. SetFileAttributes(szBuf,
  364. FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL);
  365. if (FAILED((hr=RemoveDirectoryAndChildren(szBuf)))) {
  366. goto Exit;
  367. }
  368. } else {
  369. SetFileAttributes(szBuf, FILE_ATTRIBUTE_NORMAL);
  370. if (!DeleteFile(szBuf)) {
  371. hr = HRESULT_FROM_WIN32(GetLastError());
  372. goto Exit;
  373. }
  374. }
  375. } while (FindNextFile(hf, &fd));
  376. if (GetLastError() != ERROR_NO_MORE_FILES) {
  377. hr = HRESULT_FROM_WIN32(GetLastError());
  378. goto Exit;
  379. }
  380. if (hf != INVALID_HANDLE_VALUE) {
  381. FindClose(hf);
  382. hf = INVALID_HANDLE_VALUE;
  383. }
  384. // here if all subdirs/children removed
  385. /// re-attempt to remove the main dir
  386. if (!RemoveDirectory(szDir)) {
  387. hr = HRESULT_FROM_WIN32(GetLastError());
  388. goto Exit;
  389. }
  390. Exit:
  391. if (hf != INVALID_HANDLE_VALUE)
  392. FindClose(hf);
  393. return hr;
  394. }
  395. HRESULT IsExtnHandled(LPSTR pszExt)
  396. {
  397. DEBUG_ENTER((DBG_DOWNLOAD,
  398. Hresult,
  399. "IsExtnHandled",
  400. "%.80q",
  401. pszExt
  402. ));
  403. HRESULT hr = REGDB_E_CLASSNOTREG;
  404. HKEY hkRoot = HKEY_CLASSES_ROOT;
  405. char szFileExt[MAX_PATH];
  406. DWORD cbFileExt = sizeof(szFileExt);
  407. char szCmdLine[2*MAX_PATH];
  408. char szProgID[2*MAX_PATH];
  409. LONG cbProgID = sizeof(szProgID);
  410. DWORD dwType;
  411. DWORD dwLen = sizeof(szCmdLine);
  412. HKEY hkeyCmd = 0;
  413. if (pszExt[0] == '\0')
  414. {
  415. goto Exit;
  416. }
  417. StrNCpy(szFileExt,pszExt, sizeof(szFileExt));
  418. Assert((szFileExt[0] == '.'));
  419. // the entry begins with '.' so it may be a file extension
  420. // query the value (which is the ProgID)
  421. if (RegQueryValue(hkRoot, szFileExt, szProgID, &cbProgID) == ERROR_SUCCESS)
  422. {
  423. // we got the value (ProgID), now query for the CLSID
  424. // string and convert it to a CLSID
  425. StrCatBuff(szProgID, "\\Shell\\Open\\Command", sizeof(szProgID));
  426. if ( (RegOpenKeyEx(HKEY_CLASSES_ROOT, szProgID, 0, KEY_QUERY_VALUE, &hkeyCmd) == ERROR_SUCCESS) &&
  427. (SHQueryValueEx(hkeyCmd, NULL, NULL, &dwType, &szCmdLine, &dwLen) == ERROR_SUCCESS) && dwLen)
  428. {
  429. if (GetEXEName(szCmdLine)) {
  430. hr = S_OK;
  431. }
  432. }
  433. }
  434. Exit:
  435. if (hkeyCmd)
  436. RegCloseKey(hkeyCmd);
  437. DEBUG_LEAVE(hr);
  438. return hr;
  439. }
  440. #define SZMIMESIZE_MAX 128
  441. HRESULT IsMimeHandled(LPCWSTR pwszMime)
  442. {
  443. DEBUG_ENTER((DBG_DOWNLOAD,
  444. Hresult,
  445. "IsMimeHandled",
  446. "%.80wq",
  447. pwszMime
  448. ));
  449. HRESULT hr = S_OK;
  450. HKEY hMimeKey = NULL;
  451. DWORD dwType;
  452. char szValue[MAX_PATH];
  453. DWORD dwValueLen = MAX_PATH;
  454. static char szMimeKey[] = "MIME\\Database\\Content Type\\";
  455. static char szExtension[] = "Extension";
  456. const ULONG ulMimeKeyLen = ((sizeof(szMimeKey)/sizeof(char))-1);
  457. char szKey[SZMIMESIZE_MAX + ulMimeKeyLen];
  458. LPSTR pszMime = NULL;
  459. if (SUCCEEDED((hr=::Unicode2Ansi(pwszMime, &pszMime)))) {
  460. StrNCpy(szKey, szMimeKey, sizeof(szKey));
  461. StrCatBuff(szKey, pszMime, sizeof(szKey));
  462. hr = REGDB_E_READREGDB;
  463. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_QUERY_VALUE, &hMimeKey) == ERROR_SUCCESS) {
  464. if (RegQueryValueEx(hMimeKey
  465. , szExtension
  466. , NULL
  467. , &dwType
  468. , (LPBYTE)szValue
  469. , &dwValueLen) == ERROR_SUCCESS) {
  470. hr = IsExtnHandled(szValue);
  471. }
  472. }
  473. }
  474. if (hMimeKey) {
  475. RegCloseKey(hMimeKey);
  476. }
  477. SAFEDELETE(pszMime);
  478. DEBUG_LEAVE(hr);
  479. return hr;
  480. }