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.

1886 lines
51 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. cachapiw.cxx
  5. Abstract:
  6. contains the UNICODE version of cache mangemant APIs.
  7. Author:
  8. Madan Appiah (madana) 12-Dec-1994
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. Ahsan Kabir (akabir) Dec-1997
  13. --*/
  14. #include <cache.hxx>
  15. #include <w95wraps.h>
  16. #define NUMBER_MEMBERS 4
  17. const BYTE bOffsetTable[NUMBER_MEMBERS] =
  18. {
  19. (BYTE)&(((LPINTERNET_CACHE_ENTRY_INFOW)NULL)->lpszSourceUrlName),
  20. (BYTE)&(((LPINTERNET_CACHE_ENTRY_INFOW)NULL)->lpszLocalFileName),
  21. (BYTE)&(((LPINTERNET_CACHE_ENTRY_INFOW)NULL)->lpHeaderInfo),
  22. (BYTE)&(((LPINTERNET_CACHE_ENTRY_INFOW)NULL)->lpszFileExtension)
  23. };
  24. DWORD
  25. TransformA2W(
  26. IN LPINTERNET_CACHE_ENTRY_INFOA pCEIA,
  27. IN DWORD cbCEIA,
  28. OUT LPINTERNET_CACHE_ENTRY_INFOW pCEIW,
  29. OUT LPDWORD pcbCEIW
  30. )
  31. {
  32. DWORD cbSize = sizeof(INTERNET_CACHE_ENTRY_INFOW);
  33. DWORD cc;
  34. if (!pCEIW || (*pcbCEIW<sizeof(INTERNET_CACHE_ENTRY_INFOW)))
  35. {
  36. *pcbCEIW = 0;
  37. cc = 0;
  38. }
  39. else
  40. {
  41. //
  42. // copy fixed portion.
  43. //
  44. memcpy((PBYTE)pCEIW, (PBYTE)pCEIA, sizeof(INTERNET_CACHE_ENTRY_INFOW) );
  45. pCEIW->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOW);
  46. cc = (*pcbCEIW - sizeof(INTERNET_CACHE_ENTRY_INFOW))/sizeof(WCHAR);
  47. }
  48. // Destination for strings
  49. PWSTR pBuffer = (pCEIW ? (PWSTR)(pCEIW + 1) : NULL);
  50. // Convert strings
  51. for (int i=0; i < NUMBER_MEMBERS; i++)
  52. {
  53. PSTR *pBufferA = (PSTR*)((PBYTE)pCEIA + bOffsetTable[i]);
  54. if (*pBufferA)
  55. {
  56. DWORD dwTmp = MultiByteToWideChar(CP_ACP, 0, *pBufferA, -1, NULL, 0);
  57. if ((dwTmp<=cc) && pCEIW)
  58. {
  59. INET_ASSERT(pBuffer);
  60. PWSTR *pBufferW = (PWSTR*)((PBYTE)pCEIW + bOffsetTable[i]);
  61. *pBufferW = pBuffer;
  62. MultiByteToWideChar(CP_ACP, 0, *pBufferA, -1, *pBufferW, dwTmp);
  63. pBuffer += dwTmp;
  64. cc -= dwTmp;
  65. }
  66. cbSize += dwTmp*sizeof(WCHAR);
  67. }
  68. }
  69. DWORD dwErr = (*pcbCEIW>=cbSize) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
  70. *pcbCEIW = cbSize; // Tell how much space used/needed.
  71. return dwErr;
  72. }
  73. URLCACHEAPI_(BOOL) CreateUrlCacheEntryW(
  74. IN LPCWSTR lpszUrlName,
  75. IN DWORD dwExpectedFileSize,
  76. IN LPCWSTR lpszFileExtension,
  77. OUT LPWSTR lpszFileName,
  78. IN DWORD dwReserved
  79. )
  80. {
  81. ENTER_CACHE_API ((DBG_API, Bool, "CreateUrlCacheEntryW", "%wq, %wq, %d, %wq, %#x",
  82. lpszUrlName, lpszFileExtension, dwExpectedFileSize, lpszFileName, dwReserved));
  83. DWORD dwErr = ERROR_SUCCESS;
  84. BOOL fResult = FALSE, fStrNotSafe = FALSE;
  85. MEMORYPACKET mpUrlName, mpFileExtension, mpFileName;
  86. if (lpszUrlName)
  87. {
  88. ALLOC_MB(lpszUrlName,0,mpUrlName);
  89. if (!mpUrlName.psStr)
  90. {
  91. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  92. goto cleanup;
  93. }
  94. UNICODE_TO_ANSI_CHECKED(lpszUrlName,mpUrlName, &fStrNotSafe);
  95. if (fStrNotSafe)
  96. {
  97. dwErr = ERROR_INVALID_PARAMETER;
  98. goto cleanup;
  99. }
  100. }
  101. if (lpszFileExtension)
  102. {
  103. ALLOC_MB(lpszFileExtension,0,mpFileExtension);
  104. if (!mpFileExtension.psStr)
  105. {
  106. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  107. goto cleanup;
  108. }
  109. UNICODE_TO_ANSI_CHECKED(lpszFileExtension,mpFileExtension, &fStrNotSafe);
  110. if (fStrNotSafe)
  111. {
  112. dwErr = ERROR_INVALID_PARAMETER;
  113. goto cleanup;
  114. }
  115. }
  116. ALLOC_MB(NULL, MAX_PATH, mpFileName);
  117. if (!mpFileName.psStr)
  118. {
  119. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  120. goto cleanup;
  121. }
  122. fResult = CreateUrlCacheEntryA(
  123. mpUrlName.psStr,
  124. dwExpectedFileSize,
  125. mpFileExtension.psStr,
  126. mpFileName.psStr,
  127. dwReserved);
  128. if (fResult)
  129. {
  130. MultiByteToWideChar(CP_ACP, 0, mpFileName.psStr, -1, lpszFileName, MAX_PATH);
  131. }
  132. cleanup:
  133. if (dwErr!=ERROR_SUCCESS)
  134. {
  135. SetLastError(dwErr);
  136. DEBUG_ERROR(API, dwErr);
  137. }
  138. DEBUG_LEAVE_API(fResult);
  139. return fResult;
  140. }
  141. URLCACHEAPI_(BOOL) CommitUrlCacheEntryW(
  142. IN LPCWSTR lpszUrlName,
  143. IN LPCWSTR lpszLocalFileName,
  144. IN FILETIME ExpireTime,
  145. IN FILETIME LastModifiedTime,
  146. IN DWORD CacheEntryType,
  147. IN LPWSTR lpszHeaderInfo,
  148. IN DWORD dwHeaders,
  149. IN LPCWSTR lpszFileExtension,
  150. IN LPCWSTR lpszOriginalUrl
  151. )
  152. {
  153. ENTER_CACHE_API ((DBG_API, Bool, "CommitUrlCacheEntryW",
  154. "%wq, %wq, <expires>, <last-mod>, %d, %wq, %d, %wq, %wq",
  155. lpszUrlName,
  156. lpszLocalFileName,
  157. CacheEntryType,
  158. lpszHeaderInfo,
  159. dwHeaders,
  160. lpszFileExtension,
  161. lpszOriginalUrl
  162. ));
  163. BOOL fResult = FALSE;
  164. BOOL fStrNotSafe = FALSE;
  165. DWORD dwErr = ERROR_SUCCESS;
  166. MEMORYPACKET mpUrlName, mpLocalFileName, mpFileExtension, mpHeaders, mpOriginalUrl;
  167. if( IsBadUrlW( lpszUrlName ) ||
  168. ( lpszLocalFileName ? IsBadStringPtrW( lpszLocalFileName, MAX_PATH ) : FALSE ) )
  169. {
  170. dwErr = ERROR_INVALID_PARAMETER;
  171. goto cleanup;
  172. }
  173. ALLOC_MB(lpszUrlName,0,mpUrlName);
  174. if (!mpUrlName.psStr)
  175. {
  176. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  177. goto cleanup;
  178. }
  179. UNICODE_TO_ANSI_CHECKED(lpszUrlName,mpUrlName, &fStrNotSafe);
  180. if (fStrNotSafe)
  181. {
  182. dwErr = ERROR_INVALID_PARAMETER;
  183. goto cleanup;
  184. }
  185. if (lpszLocalFileName)
  186. {
  187. ALLOC_MB(lpszLocalFileName,0,mpLocalFileName);
  188. if (!mpLocalFileName.psStr)
  189. {
  190. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  191. goto cleanup;
  192. }
  193. UNICODE_TO_ANSI_CHECKED(lpszLocalFileName,mpLocalFileName, &fStrNotSafe);
  194. if (fStrNotSafe)
  195. {
  196. dwErr = ERROR_INVALID_PARAMETER;
  197. goto cleanup;
  198. }
  199. }
  200. if (lpszFileExtension)
  201. {
  202. ALLOC_MB(lpszFileExtension,0,mpFileExtension);
  203. if (!mpFileExtension.psStr)
  204. {
  205. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  206. goto cleanup;
  207. }
  208. UNICODE_TO_ANSI_CHECKED(lpszFileExtension,mpFileExtension, &fStrNotSafe);
  209. if (fStrNotSafe)
  210. {
  211. dwErr = ERROR_INVALID_PARAMETER;
  212. goto cleanup;
  213. }
  214. }
  215. if (lpszHeaderInfo)
  216. {
  217. ALLOC_MB(lpszHeaderInfo,0,mpHeaders);
  218. if (!mpHeaders.psStr)
  219. {
  220. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  221. goto cleanup;
  222. }
  223. UNICODE_TO_ANSI_CHECKED(lpszHeaderInfo,mpHeaders, &fStrNotSafe);
  224. if (fStrNotSafe)
  225. {
  226. dwErr = ERROR_INVALID_PARAMETER;
  227. goto cleanup;
  228. }
  229. }
  230. if (lpszOriginalUrl)
  231. {
  232. ALLOC_MB(lpszOriginalUrl,0,mpOriginalUrl);
  233. if (!mpOriginalUrl.psStr)
  234. {
  235. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  236. goto cleanup;
  237. }
  238. UNICODE_TO_ANSI_CHECKED(lpszOriginalUrl,mpOriginalUrl, &fStrNotSafe);
  239. if (fStrNotSafe)
  240. {
  241. dwErr = ERROR_INVALID_PARAMETER;
  242. goto cleanup;
  243. }
  244. }
  245. fResult = CommitUrlCacheEntryA(
  246. mpUrlName.psStr,
  247. mpLocalFileName.psStr,
  248. ExpireTime,
  249. LastModifiedTime,
  250. CacheEntryType,
  251. (LPBYTE)mpHeaders.psStr,
  252. mpHeaders.dwSize,
  253. mpFileExtension.psStr,
  254. mpOriginalUrl.psStr);
  255. cleanup:
  256. if (dwErr!=ERROR_SUCCESS)
  257. {
  258. SetLastError(dwErr);
  259. DEBUG_ERROR(API, dwErr);
  260. }
  261. DEBUG_LEAVE_API(fResult);
  262. return fResult;
  263. }
  264. BOOL
  265. RetrieveUrlCacheEntryWCore(
  266. IN LPCWSTR lpszUrlName,
  267. OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
  268. IN OUT LPDWORD lpcbCacheEntryInfo,
  269. IN DWORD dwReserved,
  270. IN DWORD dwLookupFlags,
  271. IN DWORD dwRetrievalFlags)
  272. {
  273. DWORD dwErr = ERROR_SUCCESS;
  274. BOOL fStrNotSafe = FALSE;
  275. MEMORYPACKET mpUrlName;
  276. LPINTERNET_CACHE_ENTRY_INFOA pCEIA = NULL;
  277. DWORD dwCEI = 0;
  278. if (!InitGlobals())
  279. {
  280. dwErr = ERROR_INTERNET_INTERNAL_ERROR;
  281. goto cleanup;
  282. }
  283. if (!(lpszUrlName && lpcbCacheEntryInfo))
  284. {
  285. dwErr = ERROR_INVALID_PARAMETER;
  286. goto cleanup;
  287. }
  288. ALLOC_MB(lpszUrlName, 0, mpUrlName);
  289. if (!mpUrlName.psStr)
  290. {
  291. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  292. goto cleanup;
  293. }
  294. UNICODE_TO_ANSI_CHECKED(lpszUrlName, mpUrlName, &fStrNotSafe);
  295. if (fStrNotSafe)
  296. {
  297. dwErr = ERROR_INVALID_PARAMETER;
  298. goto cleanup;
  299. }
  300. dwErr = GlobalUrlContainers->RetrieveUrl(
  301. mpUrlName.psStr,
  302. &pCEIA,
  303. &dwCEI,
  304. dwLookupFlags,
  305. dwRetrievalFlags | RETRIEVE_WITH_ALLOCATION);
  306. if (dwErr==ERROR_SUCCESS)
  307. {
  308. dwErr = TransformA2W(
  309. pCEIA,
  310. dwCEI,
  311. lpCacheEntryInfo,
  312. lpcbCacheEntryInfo);
  313. if (dwErr!=ERROR_SUCCESS)
  314. {
  315. UnlockUrlCacheEntryFileW(lpszUrlName, 0);
  316. }
  317. }
  318. cleanup:
  319. if (pCEIA)
  320. {
  321. FREE_MEMORY(pCEIA);
  322. }
  323. if (dwErr!=ERROR_SUCCESS)
  324. {
  325. SetLastError(dwErr);
  326. DEBUG_ERROR(API, dwErr);
  327. }
  328. return (dwErr == ERROR_SUCCESS);
  329. }
  330. URLCACHEAPI_(BOOL) RetrieveUrlCacheEntryFileW(
  331. IN LPCWSTR lpszUrlName,
  332. OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
  333. IN OUT LPDWORD lpcbCacheEntryInfo,
  334. IN DWORD dwReserved
  335. )
  336. {
  337. ENTER_CACHE_API ((DBG_API, Bool, "RetrieveUrlCacheEntryFileW","%wq, %#x, %#x, %#x",
  338. lpszUrlName, lpCacheEntryInfo, lpcbCacheEntryInfo, dwReserved));
  339. BOOL fResult = RetrieveUrlCacheEntryWCore(
  340. lpszUrlName,
  341. lpCacheEntryInfo,
  342. lpcbCacheEntryInfo,
  343. dwReserved,
  344. LOOKUP_URL_CREATE,
  345. RETRIEVE_WITH_CHECKS);
  346. DEBUG_LEAVE_API(fResult);
  347. return fResult;
  348. }
  349. URLCACHEAPI_(HANDLE) RetrieveUrlCacheEntryStreamW(
  350. IN LPCWSTR lpszUrlName,
  351. OUT LPCACHE_ENTRY_INFOW lpCacheEntryInfo,
  352. IN OUT LPDWORD lpcbCacheEntryInfo,
  353. IN BOOL fRandomRead,
  354. IN DWORD dwReserved
  355. )
  356. {
  357. ENTER_CACHE_API ((DBG_API, Handle, "RetrieveUrlCacheEntryStreamW",
  358. "%wq, %#x, %#x, %d, %#x",
  359. lpszUrlName,
  360. lpCacheEntryInfo,
  361. lpcbCacheEntryInfo,
  362. fRandomRead,
  363. dwReserved
  364. ));
  365. BOOL fLocked = FALSE;
  366. HANDLE hInternet = NULL;
  367. HANDLE hFile = INVALID_HANDLE_VALUE;
  368. DWORD dwErr = ERROR_SUCCESS, dwFileSize;
  369. CACHE_STREAM_CONTEXT_HANDLE* pStream;
  370. if (!RetrieveUrlCacheEntryWCore(
  371. lpszUrlName,
  372. lpCacheEntryInfo,
  373. lpcbCacheEntryInfo,
  374. dwReserved,
  375. LOOKUP_URL_NOCREATE,
  376. RETRIEVE_WITHOUT_CHECKS))
  377. {
  378. goto cleanup;
  379. }
  380. fLocked = TRUE;
  381. // Allocate a stream handle.
  382. LOCK_CACHE();
  383. hInternet = HandleMgr.Alloc (sizeof(CACHE_STREAM_CONTEXT_HANDLE));
  384. if (hInternet)
  385. {
  386. pStream = (CACHE_STREAM_CONTEXT_HANDLE*) HandleMgr.Map (hInternet);
  387. INET_ASSERT (pStream);
  388. }
  389. UNLOCK_CACHE();
  390. if (!hInternet)
  391. {
  392. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  393. goto cleanup;
  394. }
  395. // Open the file.
  396. // Does CreateFileW exist on Win9x?
  397. hFile = CreateFileW
  398. (
  399. lpCacheEntryInfo->lpszLocalFileName,
  400. GENERIC_READ,
  401. FILE_SHARE_READ,
  402. NULL,
  403. OPEN_EXISTING,
  404. FILE_ATTRIBUTE_NORMAL |
  405. (fRandomRead ? FILE_FLAG_RANDOM_ACCESS : FILE_FLAG_SEQUENTIAL_SCAN),
  406. // improves file read (cache) performance?
  407. NULL
  408. );
  409. if( hFile == INVALID_HANDLE_VALUE )
  410. {
  411. dwErr = GetLastError();
  412. goto cleanup;
  413. }
  414. dwFileSize = GetFileSize(hFile, NULL);
  415. if (dwFileSize != lpCacheEntryInfo->dwSizeLow)
  416. {
  417. dwErr = (dwFileSize==0xFFFFFFFF) ? GetLastError() : ERROR_INVALID_DATA;
  418. goto cleanup;
  419. }
  420. pStream->FileHandle = hFile;
  421. // Copy URL name storage.
  422. {
  423. MEMORYPACKET mpUrl;
  424. ALLOC_MB(lpszUrlName,0,mpUrl);
  425. if (!mpUrl.psStr)
  426. {
  427. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  428. goto cleanup;
  429. }
  430. UNICODE_TO_ANSI(lpszUrlName,mpUrl);
  431. pStream->SourceUrlName = NewString(mpUrl.psStr);
  432. if( !pStream->SourceUrlName)
  433. {
  434. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  435. goto cleanup;
  436. }
  437. }
  438. cleanup:
  439. if (dwErr!=ERROR_SUCCESS)
  440. {
  441. if (hInternet)
  442. {
  443. HandleMgr.Free(hInternet);
  444. hInternet = NULL;
  445. }
  446. if (hFile)
  447. CloseHandle (hFile);
  448. if (fLocked)
  449. {
  450. UnlockUrlCacheEntryFileW(lpszUrlName, 0);
  451. }
  452. SetLastError (dwErr);
  453. DEBUG_ERROR(API, dwErr);
  454. }
  455. DEBUG_LEAVE_API(hInternet);
  456. return hInternet;
  457. }
  458. BOOL
  459. GetUrlCacheEntryWCore(
  460. IN LPCWSTR lpszUrl,
  461. OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
  462. IN OUT LPDWORD lpcbCacheEntryInfo,
  463. DWORD dwFlags,
  464. DWORD dwLookupFlags,
  465. BOOL fConvertHeaders)
  466. {
  467. BOOL fResult = FALSE;
  468. DWORD dwErr = ERROR_SUCCESS;
  469. BOOL fStrNotSafe = FALSE;
  470. MEMORYPACKET mpUrlName;
  471. LPINTERNET_CACHE_ENTRY_INFOA pCEIA = NULL;
  472. DWORD cbCEIA;
  473. if (!InitGlobals())
  474. {
  475. dwErr = ERROR_INTERNET_INTERNAL_ERROR;
  476. goto cleanup;
  477. }
  478. if (IsBadUrlW(lpszUrl))
  479. {
  480. dwErr = ERROR_INVALID_PARAMETER;
  481. goto cleanup;
  482. }
  483. ALLOC_MB(lpszUrl,0,mpUrlName);
  484. if (!mpUrlName.psStr)
  485. {
  486. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  487. goto cleanup;
  488. }
  489. UNICODE_TO_ANSI_CHECKED(lpszUrl,mpUrlName, &fStrNotSafe);
  490. if (fStrNotSafe)
  491. {
  492. dwErr = ERROR_INVALID_PARAMETER;
  493. goto cleanup;
  494. }
  495. if (lpcbCacheEntryInfo)
  496. {
  497. dwErr = GlobalUrlContainers->GetUrlInfo(
  498. mpUrlName.psStr,
  499. &pCEIA,
  500. &cbCEIA,
  501. dwFlags,
  502. dwLookupFlags,
  503. RETRIEVE_WITH_ALLOCATION);
  504. // convert from ansi to unicode.
  505. if (dwErr==ERROR_SUCCESS)
  506. {
  507. dwErr = TransformA2W(pCEIA, cbCEIA, lpCacheEntryInfo, lpcbCacheEntryInfo);
  508. if (dwErr==ERROR_SUCCESS)
  509. {
  510. fResult = TRUE;
  511. }
  512. }
  513. }
  514. else
  515. {
  516. fResult = GetUrlCacheEntryInfoExA(
  517. mpUrlName.psStr,
  518. NULL,
  519. NULL,
  520. NULL,
  521. NULL,
  522. NULL,
  523. dwFlags);
  524. }
  525. cleanup:
  526. if (pCEIA)
  527. {
  528. FREE_MEMORY(pCEIA);
  529. }
  530. if (dwErr!=ERROR_SUCCESS)
  531. {
  532. SetLastError(dwErr);
  533. DEBUG_ERROR(API, dwErr);
  534. }
  535. return fResult;
  536. }
  537. URLCACHEAPI_(BOOL) GetUrlCacheEntryInfoW(
  538. IN LPCWSTR lpszUrlName,
  539. OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
  540. IN OUT LPDWORD lpcbCacheEntryInfo
  541. )
  542. {
  543. ENTER_CACHE_API ((DBG_API, Bool, "GetUrlCacheEntryInfoW", "%wq, %#x, %#x",
  544. lpszUrlName, lpCacheEntryInfo, lpcbCacheEntryInfo));
  545. BOOL fResult = GetUrlCacheEntryWCore(
  546. lpszUrlName,
  547. lpCacheEntryInfo,
  548. lpcbCacheEntryInfo,
  549. 0,
  550. LOOKUP_URL_NOCREATE,
  551. TRUE);
  552. DEBUG_LEAVE_API(fResult);
  553. return fResult;
  554. }
  555. BOOLAPI GetUrlCacheEntryInfoExW(
  556. IN LPCWSTR lpszUrl,
  557. OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo,
  558. IN OUT LPDWORD lpcbCacheEntryInfo,
  559. OUT LPWSTR lpszRedirectUrl,
  560. IN OUT LPDWORD lpcbRedirectUrl,
  561. LPVOID lpReserved,
  562. DWORD dwFlags
  563. )
  564. {
  565. ENTER_CACHE_API ((DBG_API, Bool, "GetUrlCacheEntryInfoExW",
  566. "%wq, %#x, %#x, %wq, %#x, %#x, %#x",
  567. lpszUrl, lpCacheEntryInfo, lpcbCacheEntryInfo, lpszRedirectUrl, lpcbRedirectUrl, lpReserved, dwFlags));
  568. DWORD dwErr = ERROR_SUCCESS;
  569. BOOL fResult = FALSE;
  570. if (lpszRedirectUrl
  571. || lpcbRedirectUrl
  572. || lpReserved
  573. )
  574. {
  575. INET_ASSERT (FALSE);
  576. dwErr = ERROR_INVALID_PARAMETER;
  577. goto cleanup;
  578. }
  579. fResult = GetUrlCacheEntryWCore(
  580. lpszUrl,
  581. lpCacheEntryInfo,
  582. lpcbCacheEntryInfo,
  583. dwFlags,
  584. LOOKUP_URL_TRANSLATE | (dwFlags & INTERNET_CACHE_FLAG_ALLOW_COLLISIONS),
  585. TRUE);
  586. cleanup:
  587. if (dwErr!=ERROR_SUCCESS)
  588. {
  589. SetLastError(dwErr);
  590. DEBUG_ERROR(API, dwErr);
  591. }
  592. DEBUG_LEAVE_API(fResult);
  593. return fResult;
  594. }
  595. URLCACHEAPI_(BOOL) SetUrlCacheEntryInfoW(
  596. IN LPCWSTR lpszUrlName,
  597. IN LPCACHE_ENTRY_INFOW lpCacheEntryInfo,
  598. IN DWORD dwFieldControl
  599. )
  600. {
  601. ENTER_CACHE_API ((DBG_API, Bool, "SetUrlCacheEntryInfoW", "%wq, %#x, %d",
  602. lpszUrlName, lpCacheEntryInfo, dwFieldControl));
  603. BOOL fResult = FALSE;
  604. BOOL fStrNotSafe = FALSE;
  605. DWORD dwErr = ERROR_SUCCESS;
  606. MEMORYPACKET mpUrlName;
  607. INTERNET_CACHE_ENTRY_INFOA CacheEntryInfoA;
  608. if (!lpszUrlName)
  609. {
  610. dwErr = ERROR_INVALID_PARAMETER;
  611. goto cleanup;
  612. }
  613. memcpy( &CacheEntryInfoA, lpCacheEntryInfo, sizeof(CacheEntryInfoA) );
  614. ALLOC_MB(lpszUrlName,0,mpUrlName);
  615. if (!mpUrlName.psStr)
  616. {
  617. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  618. goto cleanup;
  619. }
  620. UNICODE_TO_ANSI_CHECKED(lpszUrlName,mpUrlName, &fStrNotSafe);
  621. if (fStrNotSafe)
  622. {
  623. dwErr = ERROR_INVALID_PARAMETER;
  624. goto cleanup;
  625. }
  626. fResult = SetUrlCacheEntryInfoA(
  627. mpUrlName.psStr,
  628. &CacheEntryInfoA,
  629. dwFieldControl );
  630. cleanup:
  631. if (dwErr!=ERROR_SUCCESS)
  632. {
  633. SetLastError(dwErr);
  634. DEBUG_ERROR(API, dwErr);
  635. }
  636. DEBUG_LEAVE_API(fResult);
  637. return fResult;
  638. }
  639. BOOL FindUrlCacheEntryWCore(
  640. IN OUT HANDLE *phFind,
  641. IN LPCWSTR lpszUrlSearchPattern,
  642. IN DWORD dwFlags,
  643. IN DWORD dwFilter,
  644. IN GROUPID GroupId,
  645. OUT LPINTERNET_CACHE_ENTRY_INFOW pEntryInfo,
  646. IN OUT LPDWORD pcbEntryInfo,
  647. IN BOOL fConvertHeaders
  648. )
  649. {
  650. DWORD dwErr = ERROR_SUCCESS;
  651. BOOL fStrNotSafe = FALSE;
  652. MEMORYPACKET mpSearchPattern;
  653. LPINTERNET_CACHE_ENTRY_INFOA pCEIA = NULL;
  654. DWORD cbCEIA;
  655. BOOL fFindFirst = *phFind==NULL;
  656. // DebugBreak();
  657. if (!InitGlobals())
  658. {
  659. dwErr = ERROR_INTERNET_INTERNAL_ERROR;
  660. goto cleanup;
  661. }
  662. if (!pcbEntryInfo)
  663. {
  664. dwErr = ERROR_INVALID_PARAMETER;
  665. goto cleanup;
  666. }
  667. if (lpszUrlSearchPattern)
  668. {
  669. ALLOC_MB(lpszUrlSearchPattern, 0, mpSearchPattern);
  670. if (!mpSearchPattern.psStr)
  671. {
  672. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  673. goto cleanup;
  674. }
  675. UNICODE_TO_ANSI_CHECKED(lpszUrlSearchPattern, mpSearchPattern, &fStrNotSafe);
  676. if (fStrNotSafe)
  677. {
  678. dwErr = ERROR_INVALID_PARAMETER;
  679. goto cleanup;
  680. }
  681. }
  682. dwErr = GlobalUrlContainers->FindNextEntry(phFind,
  683. mpSearchPattern.psStr,
  684. &pCEIA,
  685. &cbCEIA,
  686. dwFilter,
  687. GroupId,
  688. dwFlags,
  689. RETRIEVE_WITH_ALLOCATION);
  690. // TransformA2W will convert from ansi to unicode. ERROR_SUCCESS always means that
  691. // the cache entry has been returned.
  692. if (dwErr==ERROR_SUCCESS)
  693. {
  694. dwErr = TransformA2W(pCEIA,
  695. cbCEIA,
  696. pEntryInfo,
  697. pcbEntryInfo);
  698. }
  699. cleanup:
  700. if (pCEIA)
  701. {
  702. FREE_MEMORY(pCEIA);
  703. }
  704. if (dwErr!=ERROR_SUCCESS)
  705. {
  706. if (fFindFirst && *phFind)
  707. {
  708. GlobalUrlContainers->FreeFindHandle(*phFind);
  709. *phFind = NULL;
  710. }
  711. SetLastError(dwErr);
  712. DEBUG_ERROR(API, dwErr);
  713. }
  714. return (dwErr==ERROR_SUCCESS) ;
  715. }
  716. URLCACHEAPI_(HANDLE) FindFirstUrlCacheEntryW(
  717. IN LPCWSTR lpszUrlSearchPattern,
  718. OUT LPCACHE_ENTRY_INFOW lpFirstCacheEntryInfo,
  719. IN OUT LPDWORD lpcbCacheEntryInfo
  720. )
  721. {
  722. ENTER_CACHE_API ((DBG_API, Bool, "FindFirstUrlCacheEntryW",
  723. "%wq, %#x, %#x",
  724. lpszUrlSearchPattern,
  725. lpFirstCacheEntryInfo,
  726. lpcbCacheEntryInfo
  727. ));
  728. HANDLE hInternet = FindFirstUrlCacheEntryExW(
  729. lpszUrlSearchPattern,
  730. FIND_FLAGS_OLD_SEMANTICS,
  731. URLCACHE_FIND_DEFAULT_FILTER,
  732. NULL,
  733. lpFirstCacheEntryInfo,
  734. lpcbCacheEntryInfo,
  735. NULL,
  736. NULL,
  737. NULL);
  738. DEBUG_LEAVE_API(hInternet);
  739. return hInternet;
  740. }
  741. URLCACHEAPI_(BOOL) FindNextUrlCacheEntryW(
  742. IN HANDLE hEnumHandle,
  743. OUT LPCACHE_ENTRY_INFOW pEntryInfo,
  744. IN OUT LPDWORD pcbEntryInfo
  745. )
  746. {
  747. ENTER_CACHE_API ((DBG_API, Bool, "FindNextUrlCacheEntryW",
  748. "%#x, %#x, %#x",
  749. hEnumHandle,
  750. pEntryInfo,
  751. pcbEntryInfo
  752. ));
  753. BOOL fResult = FindNextUrlCacheEntryExW(
  754. hEnumHandle,
  755. pEntryInfo,
  756. pcbEntryInfo,
  757. NULL,
  758. NULL,
  759. NULL);
  760. DEBUG_LEAVE_API(fResult);
  761. return fResult;
  762. }
  763. INTERNETAPI_(HANDLE) FindFirstUrlCacheEntryExW(
  764. IN LPCWSTR lpszUrlSearchPattern,
  765. IN DWORD dwFlags,
  766. IN DWORD dwFilter,
  767. IN GROUPID GroupId,
  768. OUT LPINTERNET_CACHE_ENTRY_INFOW pEntryInfo,
  769. IN OUT LPDWORD pcbEntryInfo,
  770. OUT LPVOID lpGroupAttributes, // must pass NULL
  771. IN OUT LPDWORD pcbGroupAttributes, // must pass NULL
  772. IN LPVOID lpReserved // must pass NULL
  773. )
  774. {
  775. ENTER_CACHE_API ((DBG_API, Bool, "FindFirstUrlCacheEntryExW",
  776. "%wq, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x",
  777. lpszUrlSearchPattern,
  778. dwFlags,
  779. dwFilter,
  780. GroupId,
  781. pEntryInfo,
  782. pcbEntryInfo,
  783. lpGroupAttributes,
  784. pcbGroupAttributes,
  785. lpReserved
  786. ));
  787. HANDLE hInternet = NULL;
  788. FindUrlCacheEntryWCore(
  789. &hInternet,
  790. lpszUrlSearchPattern,
  791. dwFlags,
  792. dwFilter,
  793. GroupId,
  794. pEntryInfo,
  795. pcbEntryInfo,
  796. TRUE);
  797. DEBUG_LEAVE_API(hInternet);
  798. return hInternet;
  799. }
  800. BOOLAPI FindNextUrlCacheEntryExW(
  801. IN HANDLE hEnumHandle,
  802. OUT LPINTERNET_CACHE_ENTRY_INFOW pEntryInfo,
  803. IN OUT LPDWORD pcbEntryInfo,
  804. OUT LPVOID lpGroupAttributes, // must pass NULL
  805. IN OUT LPDWORD pcbGroupAttributes, // must pass NULL
  806. IN LPVOID lpReserved // must pass NULL
  807. )
  808. {
  809. ENTER_CACHE_API ((DBG_API, Bool, "FindNextUrlCacheEntryExW",
  810. "%#x, %#x, %#x, %#x, %#x, %#x",
  811. hEnumHandle,
  812. pEntryInfo,
  813. pcbEntryInfo,
  814. lpGroupAttributes,
  815. pcbGroupAttributes,
  816. lpReserved
  817. ));
  818. BOOL fResult = FALSE;
  819. DWORD dwErr = ERROR_SUCCESS;
  820. if (!hEnumHandle)
  821. {
  822. dwErr = ERROR_INVALID_PARAMETER;
  823. goto cleanup;
  824. }
  825. fResult = FindUrlCacheEntryWCore(
  826. &hEnumHandle,
  827. NULL,
  828. 0,
  829. 0,
  830. 0,
  831. pEntryInfo,
  832. pcbEntryInfo,
  833. TRUE);
  834. cleanup:
  835. if (dwErr!=ERROR_SUCCESS)
  836. {
  837. SetLastError(dwErr);
  838. DEBUG_ERROR(API, dwErr);
  839. }
  840. DEBUG_LEAVE_API(fResult);
  841. return fResult;
  842. }
  843. URLCACHEAPI_(BOOL) FreeUrlCacheSpaceW(
  844. IN LPCWSTR lpszCachePath,
  845. IN DWORD dwSize,
  846. IN DWORD dwReserved
  847. )
  848. {
  849. ENTER_CACHE_API ((DBG_API, Bool, "FreeUrlCacheSpaceW",
  850. "<path>,%d, %#x", dwSize, dwReserved));
  851. BOOL fResult = FALSE;
  852. DWORD dwErr = ERROR_SUCCESS;
  853. BOOL fStrNotSafe = FALSE;
  854. MEMORYPACKET mpCachePath;
  855. if (lpszCachePath)
  856. {
  857. ALLOC_MB(lpszCachePath,0,mpCachePath);
  858. if (!mpCachePath.psStr)
  859. {
  860. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  861. goto cleanup;
  862. }
  863. UNICODE_TO_ANSI_CHECKED(lpszCachePath,mpCachePath, &fStrNotSafe);
  864. if (fStrNotSafe)
  865. {
  866. dwErr = ERROR_INVALID_PARAMETER;
  867. goto cleanup;
  868. }
  869. }
  870. fResult = FreeUrlCacheSpaceA(
  871. mpCachePath.psStr,
  872. dwSize,
  873. dwReserved );
  874. cleanup:
  875. if (dwErr!=ERROR_SUCCESS)
  876. {
  877. SetLastError(dwErr);
  878. DEBUG_ERROR(API, dwErr);
  879. }
  880. DEBUG_LEAVE_API(fResult);
  881. return fResult;
  882. }
  883. URLCACHEAPI_(BOOL) UnlockUrlCacheEntryFileW(
  884. LPCWSTR lpszUrlName,
  885. IN DWORD dwReserved
  886. )
  887. /*++
  888. Routine Description:
  889. This API checks in the file that was check out as part of
  890. RetrieveUrlFile API.
  891. Arguments:
  892. lpszUrlName : name of the URL that is being retrieved.
  893. dwReserved : reserved for future use.
  894. Return Value:
  895. Windows Error code.
  896. --*/
  897. {
  898. ENTER_CACHE_API ((DBG_API, Bool, "UnlockUrlCacheEntryFileW",
  899. "%wq, %#x", lpszUrlName, dwReserved));
  900. BOOL fResult = FALSE;
  901. BOOL fStrNotSafe = FALSE;
  902. DWORD dwErr = ERROR_SUCCESS;
  903. MEMORYPACKET mpUrl;
  904. if (!lpszUrlName)
  905. {
  906. dwErr = ERROR_INVALID_PARAMETER;
  907. goto cleanup;
  908. }
  909. ALLOC_MB(lpszUrlName,0,mpUrl);
  910. if (!mpUrl.psStr)
  911. {
  912. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  913. goto cleanup;
  914. }
  915. UNICODE_TO_ANSI_CHECKED(lpszUrlName,mpUrl, &fStrNotSafe);
  916. if (fStrNotSafe)
  917. {
  918. dwErr = ERROR_INVALID_PARAMETER;
  919. goto cleanup;
  920. }
  921. fResult = UnlockUrlCacheEntryFileA(mpUrl.psStr, dwReserved);
  922. cleanup:
  923. if (dwErr!=ERROR_SUCCESS)
  924. {
  925. SetLastError(dwErr);
  926. DEBUG_ERROR(API, dwErr);
  927. }
  928. DEBUG_LEAVE_API(fResult);
  929. return fResult;
  930. }
  931. URLCACHEAPI_(BOOL) DeleteUrlCacheEntryW(
  932. IN LPCWSTR lpszUrlName
  933. )
  934. {
  935. ENTER_CACHE_API ((DBG_API, Bool, "DeleteUrlCacheEntryW",
  936. "%wq", lpszUrlName));
  937. BOOL fResult = FALSE;
  938. BOOL fStrNotSafe = FALSE;
  939. DWORD dwErr = ERROR_SUCCESS;
  940. MEMORYPACKET mpUrl;
  941. if (!lpszUrlName)
  942. {
  943. dwErr = ERROR_INVALID_PARAMETER;
  944. goto cleanup;
  945. }
  946. ALLOC_MB(lpszUrlName,0,mpUrl);
  947. if (!mpUrl.psStr)
  948. {
  949. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  950. goto cleanup;
  951. }
  952. UNICODE_TO_ANSI_CHECKED(lpszUrlName,mpUrl, &fStrNotSafe);
  953. if (fStrNotSafe)
  954. {
  955. dwErr = ERROR_INVALID_PARAMETER;
  956. goto cleanup;
  957. }
  958. fResult = DeleteUrlCacheEntryA(mpUrl.psStr);
  959. cleanup:
  960. if (dwErr!=ERROR_SUCCESS)
  961. {
  962. SetLastError(dwErr);
  963. DEBUG_ERROR(API, dwErr);
  964. }
  965. DEBUG_LEAVE_API(fResult);
  966. return fResult;
  967. }
  968. BOOLAPI IsUrlCacheEntryExpiredW(
  969. IN LPCWSTR lpszUrlName,
  970. IN DWORD dwFlags,
  971. IN OUT FILETIME* pftLastModifiedTime
  972. )
  973. {
  974. ENTER_CACHE_API ((DBG_API, Bool, "UrlCacheEntryExpiredW",
  975. "%wq, %#x", lpszUrlName, dwFlags));
  976. BOOL fResult = FALSE;
  977. BOOL fStrNotSafe = FALSE;
  978. DWORD dwErr = ERROR_SUCCESS;
  979. MEMORYPACKET mpUrl;
  980. if (!lpszUrlName)
  981. {
  982. dwErr = ERROR_INVALID_PARAMETER;
  983. goto cleanup;
  984. }
  985. ALLOC_MB(lpszUrlName,0,mpUrl);
  986. if (!mpUrl.psStr)
  987. {
  988. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  989. goto cleanup;
  990. }
  991. UNICODE_TO_ANSI_CHECKED(lpszUrlName,mpUrl, &fStrNotSafe);
  992. if (fStrNotSafe)
  993. {
  994. dwErr = ERROR_INVALID_PARAMETER;
  995. goto cleanup;
  996. }
  997. fResult = IsUrlCacheEntryExpiredA(
  998. mpUrl.psStr,
  999. dwFlags,
  1000. pftLastModifiedTime);
  1001. cleanup:
  1002. if (dwErr!=ERROR_SUCCESS)
  1003. {
  1004. SetLastError(dwErr);
  1005. DEBUG_ERROR(API, dwErr);
  1006. }
  1007. DEBUG_LEAVE_API(fResult);
  1008. return fResult;
  1009. }
  1010. BOOL CacheGroupInfoA2W(
  1011. IN LPINTERNET_CACHE_GROUP_INFOA lpAnsiGroupInfo,
  1012. IN DWORD dwAnsiGroupInfoSize,
  1013. OUT LPINTERNET_CACHE_GROUP_INFOW lpUnicodeGroupInfo,
  1014. IN OUT LPDWORD lpdwUnicodeGroupInfoSize
  1015. )
  1016. {
  1017. INET_ASSERT( lpUnicodeGroupInfo && lpAnsiGroupInfo);
  1018. lpUnicodeGroupInfo->dwGroupSize = sizeof(INTERNET_CACHE_GROUP_INFOW);
  1019. lpUnicodeGroupInfo->dwGroupFlags = lpAnsiGroupInfo->dwGroupFlags;
  1020. lpUnicodeGroupInfo->dwGroupType = lpAnsiGroupInfo->dwGroupType;
  1021. lpUnicodeGroupInfo->dwDiskUsage = lpAnsiGroupInfo->dwDiskUsage;
  1022. lpUnicodeGroupInfo->dwDiskQuota = lpAnsiGroupInfo->dwDiskQuota;
  1023. memcpy(lpUnicodeGroupInfo->dwOwnerStorage,
  1024. lpAnsiGroupInfo->dwOwnerStorage,
  1025. GROUP_OWNER_STORAGE_SIZE * sizeof(DWORD) );
  1026. BOOL fRet = MultiByteToWideChar(
  1027. CP_ACP,
  1028. MB_PRECOMPOSED,
  1029. lpAnsiGroupInfo->szGroupName,
  1030. -1, // null terminated ansi string.
  1031. lpUnicodeGroupInfo->szGroupName,
  1032. GROUPNAME_MAX_LENGTH
  1033. );
  1034. if( fRet )
  1035. {
  1036. *lpdwUnicodeGroupInfoSize = lpUnicodeGroupInfo->dwGroupSize;
  1037. }
  1038. else
  1039. {
  1040. *lpdwUnicodeGroupInfoSize = 0;
  1041. SetLastError(ERROR_INVALID_PARAMETER);
  1042. }
  1043. return fRet;
  1044. }
  1045. BOOL CacheGroupInfoW2A(
  1046. IN LPINTERNET_CACHE_GROUP_INFOW lpUnicodeGroupInfo,
  1047. IN DWORD dwUnicodeGroupInfoSize,
  1048. OUT LPINTERNET_CACHE_GROUP_INFOA lpAnsiGroupInfo,
  1049. IN OUT LPDWORD lpdwAnsiGroupInfoSize
  1050. )
  1051. {
  1052. INET_ASSERT( lpUnicodeGroupInfo && lpAnsiGroupInfo);
  1053. BOOL fStrNotSafe = FALSE;
  1054. lpAnsiGroupInfo->dwGroupSize = sizeof(INTERNET_CACHE_GROUP_INFOA);
  1055. lpAnsiGroupInfo->dwGroupFlags = lpUnicodeGroupInfo->dwGroupFlags;
  1056. lpAnsiGroupInfo->dwGroupType = lpUnicodeGroupInfo->dwGroupType;
  1057. lpAnsiGroupInfo->dwDiskUsage = lpUnicodeGroupInfo->dwDiskUsage;
  1058. lpAnsiGroupInfo->dwDiskQuota = lpUnicodeGroupInfo->dwDiskQuota;
  1059. memcpy( lpAnsiGroupInfo->dwOwnerStorage,
  1060. lpUnicodeGroupInfo->dwOwnerStorage,
  1061. GROUP_OWNER_STORAGE_SIZE * sizeof(DWORD) );
  1062. BOOL fRet = WideCharToMultiByte(
  1063. CP_ACP,
  1064. 0, // no flags.
  1065. lpUnicodeGroupInfo->szGroupName,
  1066. -1, // null terminated unicode string.
  1067. lpAnsiGroupInfo->szGroupName,
  1068. GROUPNAME_MAX_LENGTH,
  1069. NULL, // lpDefaultChar
  1070. &fStrNotSafe // lpUseDefaultChar
  1071. );
  1072. if (fStrNotSafe)
  1073. {
  1074. fRet = FALSE;
  1075. }
  1076. if( fRet )
  1077. {
  1078. *lpdwAnsiGroupInfoSize = lpAnsiGroupInfo->dwGroupSize;
  1079. }
  1080. else
  1081. {
  1082. *lpdwAnsiGroupInfoSize = 0;
  1083. }
  1084. return fRet;
  1085. }
  1086. URLCACHEAPI_(BOOL) SetUrlCacheEntryGroupW(
  1087. IN LPCWSTR lpszUrlName,
  1088. IN DWORD dwFlags,
  1089. IN GROUPID GroupId,
  1090. IN LPBYTE pbGroupAttributes, // must pass NULL
  1091. IN DWORD cbGroupAttributes, // must pass 0
  1092. IN LPVOID lpReserved // must pass NULL
  1093. )
  1094. {
  1095. ENTER_CACHE_API ((DBG_API, Bool, "SetUrlCacheEntryGroupW",
  1096. "%wq, %#x, %#x, %#x, %#x, %#x", lpszUrlName, dwFlags, GroupId, pbGroupAttributes, cbGroupAttributes, lpReserved));
  1097. BOOL fResult = FALSE;
  1098. BOOL fStrNotSafe = FALSE;
  1099. DWORD dwErr = ERROR_SUCCESS;
  1100. MEMORYPACKET mpUrl;
  1101. if (!lpszUrlName)
  1102. {
  1103. dwErr = ERROR_INVALID_PARAMETER;
  1104. goto cleanup;
  1105. }
  1106. ALLOC_MB(lpszUrlName,0,mpUrl);
  1107. if (!mpUrl.psStr)
  1108. {
  1109. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1110. goto cleanup;
  1111. }
  1112. UNICODE_TO_ANSI_CHECKED(lpszUrlName,mpUrl, &fStrNotSafe);
  1113. if (fStrNotSafe)
  1114. {
  1115. dwErr = ERROR_INVALID_PARAMETER;
  1116. goto cleanup;
  1117. }
  1118. fResult = SetUrlCacheEntryGroupA(
  1119. mpUrl.psStr,
  1120. dwFlags,
  1121. GroupId,
  1122. pbGroupAttributes,
  1123. cbGroupAttributes,
  1124. lpReserved);
  1125. cleanup:
  1126. if (dwErr!=ERROR_SUCCESS)
  1127. {
  1128. SetLastError(dwErr);
  1129. DEBUG_ERROR(API, dwErr);
  1130. }
  1131. DEBUG_LEAVE_API(fResult);
  1132. return fResult;
  1133. }
  1134. URLCACHEAPI_(BOOL) GetUrlCacheGroupAttributeW(
  1135. IN GROUPID gid,
  1136. IN DWORD dwFlags,
  1137. IN DWORD dwAttributes,
  1138. OUT LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
  1139. IN OUT LPDWORD lpdwGroupInfo,
  1140. IN OUT LPVOID lpReserved
  1141. )
  1142. {
  1143. ENTER_CACHE_API ((DBG_API, Bool, "GetUrlCacheGroupAttributeW",
  1144. "%d, %d, %d, %#x, %#x, %#x",
  1145. gid, dwFlags, dwAttributes, lpGroupInfo, lpdwGroupInfo, lpReserved ));
  1146. BOOL fResult = FALSE;
  1147. DWORD Error = ERROR_SUCCESS;
  1148. INTERNET_CACHE_GROUP_INFOA AnsiGroupInfo;
  1149. DWORD dwAnsiGroupInfoSize = sizeof(INTERNET_CACHE_GROUP_INFOA);
  1150. if( !lpGroupInfo || !lpdwGroupInfo )
  1151. {
  1152. Error = ERROR_INVALID_PARAMETER;
  1153. goto Cleanup;
  1154. }
  1155. if( *lpdwGroupInfo < sizeof(INTERNET_CACHE_GROUP_INFOW) )
  1156. {
  1157. Error = ERROR_INSUFFICIENT_BUFFER;
  1158. goto Cleanup;
  1159. }
  1160. if( IsBadWriteUrlInfo(lpGroupInfo, *lpdwGroupInfo) )
  1161. {
  1162. Error = ERROR_INVALID_PARAMETER;
  1163. goto Cleanup;
  1164. }
  1165. if( GetUrlCacheGroupAttributeA(
  1166. gid, dwFlags, dwAttributes,
  1167. &AnsiGroupInfo, &dwAnsiGroupInfoSize, lpReserved ) )
  1168. {
  1169. fResult = CacheGroupInfoA2W( &AnsiGroupInfo,
  1170. dwAnsiGroupInfoSize,
  1171. lpGroupInfo,
  1172. lpdwGroupInfo );
  1173. }
  1174. Cleanup:
  1175. if (Error!=ERROR_SUCCESS)
  1176. {
  1177. SetLastError(Error);
  1178. DEBUG_ERROR(API, Error);
  1179. }
  1180. DEBUG_LEAVE_API(fResult);
  1181. return fResult;
  1182. }
  1183. URLCACHEAPI_(BOOL) SetUrlCacheGroupAttributeW(
  1184. IN GROUPID gid,
  1185. IN DWORD dwFlags,
  1186. IN DWORD dwAttributes,
  1187. IN LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo,
  1188. IN OUT LPVOID lpReserved
  1189. )
  1190. {
  1191. ENTER_CACHE_API ((DBG_API, Bool, "SetUrlCacheGroupAttributeA",
  1192. "%#x, %d, %d, %#x, %#x",
  1193. gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved));
  1194. BOOL fResult = FALSE;
  1195. DWORD Error = ERROR_SUCCESS;
  1196. INTERNET_CACHE_GROUP_INFOA AnsiGroupInfo;
  1197. DWORD dwAnsiGroupInfoSize = sizeof(INTERNET_CACHE_GROUP_INFOA);
  1198. if( IsBadReadPtr(lpGroupInfo, sizeof(INTERNET_CACHE_GROUP_INFOW) ) )
  1199. {
  1200. Error = ERROR_INVALID_PARAMETER;
  1201. }
  1202. else if( CacheGroupInfoW2A(
  1203. lpGroupInfo, sizeof(INTERNET_CACHE_GROUP_INFOW),
  1204. &AnsiGroupInfo, &dwAnsiGroupInfoSize ) )
  1205. {
  1206. fResult = SetUrlCacheGroupAttributeA(
  1207. gid, dwFlags, dwAttributes, &AnsiGroupInfo, lpReserved );
  1208. }
  1209. if (Error!=ERROR_SUCCESS)
  1210. {
  1211. SetLastError(Error);
  1212. DEBUG_ERROR(API, Error);
  1213. }
  1214. DEBUG_LEAVE_API(fResult);
  1215. return fResult;
  1216. }
  1217. // Convert all the ansi strings in a structure to unicode
  1218. /* How does this work?
  1219. Take this structure for example:
  1220. struct foo
  1221. {
  1222. DWORD dwA;
  1223. LPTSTR pszB;
  1224. DWORD dwC;
  1225. LPTSTR pszD;
  1226. };
  1227. where LPTSTR are embedded pointers
  1228. The memory layout is thus:
  1229. [DWORD][LPTSTR][DWORD][LPTSTR][embedded string pszB][embedded string pszD]
  1230. ^ ^
  1231. | |
  1232. |-struct beginning |-beginning of embedded strings
  1233. Assuming a 32-bit platform, we can construct pointers (relative to the struct beginning) to each element
  1234. in the structure. In this case,
  1235. { 0, sizeof(DWORD), sizeof(DWORD)+sizeof(LPTSTR), sizeof(DWORD)+sizeof(LPTSTR)+sizeof(DWORD) }
  1236. Let's say we're interested in strings only, and we know that these strings are embedded. We can create a byte table thus:
  1237. BYTE bFoo[] = { sizeof(DWORD), sizeof(DWORD)+sizeof(LPTSTR)+sizeof(DWORD) }
  1238. Alternatively:
  1239. BYTE bFoo[] =
  1240. {
  1241. (BYTE)&(((foo*)NULL)->pszB),
  1242. (BYTE)&(((foo*)NULL)->pszD)
  1243. };
  1244. This layout is the same for both Ansi and Unicode versions of a struct, UNLESS the struct contains for example
  1245. a TCHAR szWhat[256] (in which case, we can't use the bulk converter).
  1246. Pass BulkConverter the following parameters, to convert strings in one swoop.
  1247. pbSrc = casted pointer to the beginning of the ansi structure
  1248. pbDest = casted pointer to the beginning of the unicode structure
  1249. cbAvail = number of bytes available for embedded strings
  1250. wSkip = offset from the beginning of the structure, at which point embedded strings may be written
  1251. cElements = number of elements to convert from ansi to unicode
  1252. If BulkConverter succeeds, it'll return the number of bytes used.
  1253. If it fails, it will return the number of bytes needed to store all the unicode strings.
  1254. BUT HOW DOES THIS THING WORK?
  1255. Oh.
  1256. 1. Using the offset table, we figure out where the pointer to the string is in both the structures.
  1257. 2. Then using magic, we decided where to place the unicode string.
  1258. 3. Figure how much space we'll need to store the unicode string
  1259. 4. If that much is available, convert.
  1260. 5. Keep track, either way.
  1261. 6. Go to 1, if we have any other strings left.
  1262. */
  1263. LONG BulkConverter(PBYTE pbSrc, PBYTE pbDest, LONG cbAvail, WORD wSkip, CONST BYTE abTable[], WORD cElements)
  1264. {
  1265. PWSTR pBuffer = (PWSTR)(pbDest + wSkip);
  1266. PSTR *pBufferA;
  1267. PWSTR *pBufferW;
  1268. for (DWORD i=0; i < cElements; i++)
  1269. {
  1270. pBufferA = (PSTR*)((PBYTE)pbSrc + abTable[i]);
  1271. pBufferW = (PWSTR*)((PBYTE)pbDest + abTable[i]);
  1272. if (*pBufferA)
  1273. {
  1274. *pBufferW = pBuffer;
  1275. LONG dwTmp = MultiByteToWideChar(CP_ACP, 0, *pBufferA, -1,
  1276. *pBufferW, 0);
  1277. if (dwTmp<cbAvail)
  1278. {
  1279. MultiByteToWideChar(CP_ACP, 0, *pBufferA, -1,
  1280. *pBufferW, cbAvail);
  1281. pBuffer += dwTmp;
  1282. }
  1283. cbAvail -= dwTmp;
  1284. }
  1285. }
  1286. return cbAvail;
  1287. }
  1288. const BYTE bOffsetTableContainer[] =
  1289. {
  1290. (BYTE)&(((LPINTERNET_CACHE_CONTAINER_INFOW)NULL)->lpszName),
  1291. (BYTE)&(((LPINTERNET_CACHE_CONTAINER_INFOW)NULL)->lpszCachePrefix),
  1292. (BYTE)&(((LPINTERNET_CACHE_CONTAINER_INFOW)NULL)->lpszVolumeLabel),
  1293. (BYTE)&(((LPINTERNET_CACHE_CONTAINER_INFOW)NULL)->lpszVolumeTitle)
  1294. };
  1295. BOOL
  1296. TransformCacheContainerInfoToW(
  1297. IN BOOL fResult,
  1298. IN LPINTERNET_CACHE_CONTAINER_INFOA pCCIA,
  1299. IN DWORD cbCCIA,
  1300. OUT LPINTERNET_CACHE_CONTAINER_INFOW pCCIW,
  1301. OUT LPDWORD pcbCCIW
  1302. )
  1303. {
  1304. DWORD cbSize = *pcbCCIW;
  1305. if (fResult)
  1306. {
  1307. // If we have pointers, try to convert from
  1308. LONG cc = *pcbCCIW - sizeof(INTERNET_CACHE_CONTAINER_INFOW);
  1309. if (*pcbCCIW > sizeof(INTERNET_CACHE_CONTAINER_INFOW))
  1310. {
  1311. pCCIW->dwCacheVersion = pCCIA->dwCacheVersion;
  1312. }
  1313. cc /= sizeof(WCHAR);
  1314. // Convert strings
  1315. cc = BulkConverter((PBYTE)pCCIA,
  1316. (PBYTE)pCCIW,
  1317. cc,
  1318. sizeof(INTERNET_CACHE_CONTAINER_INFOW),
  1319. bOffsetTableContainer,
  1320. ARRAY_ELEMENTS(bOffsetTableContainer));
  1321. // Tell how much space was actually used.
  1322. *pcbCCIW -= cc*sizeof(WCHAR);
  1323. if (*pcbCCIW>cbSize)
  1324. {
  1325. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1326. fResult = FALSE;
  1327. }
  1328. }
  1329. else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
  1330. {
  1331. *pcbCCIW = (cbCCIA - sizeof(INTERNET_CACHE_CONTAINER_INFOA))*sizeof(WCHAR) + sizeof(INTERNET_CACHE_CONTAINER_INFOW);
  1332. }
  1333. return fResult;
  1334. }
  1335. #define USE_ORIGINAL_CODE
  1336. URLCACHEAPI_(BOOL) CreateUrlCacheContainerW(
  1337. IN LPCWSTR Name,
  1338. IN LPCWSTR CachePrefix,
  1339. IN LPCWSTR CachePath,
  1340. IN DWORD KBCacheLimit,
  1341. IN DWORD dwContainerType,
  1342. IN DWORD dwOptions,
  1343. IN OUT LPVOID pvBuffer,
  1344. IN OUT LPDWORD cbBuffer)
  1345. {
  1346. ENTER_CACHE_API ((DBG_API, Bool, "CreateUrlCacheContainerW", "%wq, %wq, %wq, %d, %d, %d, %#x, %#x",
  1347. Name, CachePrefix, CachePath, KBCacheLimit, dwContainerType, dwOptions, pvBuffer, cbBuffer));
  1348. DWORD dwErr = ERROR_SUCCESS;
  1349. BOOL fResult = FALSE;
  1350. MEMORYPACKET mpName, mpCachePrefix, mpCachePath;
  1351. BOOL fStrNotSafe = FALSE;
  1352. #ifdef USE_ORIGINAL_CODE
  1353. if (Name)
  1354. {
  1355. ALLOC_MB(Name, 0, mpName);
  1356. if (!mpName.psStr)
  1357. {
  1358. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1359. goto cleanup;
  1360. }
  1361. UNICODE_TO_ANSI_CHECKED(Name, mpName, &fStrNotSafe);
  1362. if (fStrNotSafe)
  1363. {
  1364. dwErr = ERROR_INVALID_PARAMETER;
  1365. goto cleanup;
  1366. }
  1367. }
  1368. if (CachePrefix)
  1369. {
  1370. ALLOC_MB(CachePrefix, 0, mpCachePrefix);
  1371. if (!mpCachePrefix.psStr)
  1372. {
  1373. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1374. goto cleanup;
  1375. }
  1376. UNICODE_TO_ANSI_CHECKED(CachePrefix, mpCachePrefix, &fStrNotSafe);
  1377. if (fStrNotSafe)
  1378. {
  1379. dwErr = ERROR_INVALID_PARAMETER;
  1380. goto cleanup;
  1381. }
  1382. }
  1383. if (CachePath)
  1384. {
  1385. ALLOC_MB(CachePath,0,mpCachePath);
  1386. if (!mpCachePath.psStr)
  1387. {
  1388. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1389. goto cleanup;
  1390. }
  1391. UNICODE_TO_ANSI_CHECKED(CachePath,mpCachePath, &fStrNotSafe);
  1392. if (fStrNotSafe)
  1393. {
  1394. dwErr = ERROR_INVALID_PARAMETER;
  1395. goto cleanup;
  1396. }
  1397. }
  1398. #else
  1399. // Theoretically, the following fragment should be smaller than the above fragment.
  1400. // Although the retail obj shows a function that's about 100 bytes shorter, the
  1401. // actual dll doesn't show this gain. Until I figure this out, we won't use it.
  1402. DWORD c;
  1403. do
  1404. {
  1405. MEMORYPACKET* mp;
  1406. PCWSTR psz;
  1407. switch (c)
  1408. {
  1409. case 0:
  1410. psz = Name;
  1411. mp = &mpName;
  1412. break;
  1413. case 1:
  1414. psz = CachePrefix;
  1415. mp = &mpCachePrefix;
  1416. break;
  1417. case 2:
  1418. psz = CachePath;
  1419. mp = &mpCachePath;
  1420. break;
  1421. }
  1422. ALLOC_MB(psz, 0, (*mp));
  1423. if (!mp->psStr)
  1424. {
  1425. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1426. goto cleanup;
  1427. }
  1428. UNICODE_TO_ANSI_CHECKED(psz, (*mp), &fStrNotSafe);
  1429. if (fStrNotSafe)
  1430. {
  1431. dwErr = ERROR_INVALID_PARAMETER;
  1432. goto cleanup;
  1433. }
  1434. c++;
  1435. }
  1436. while (c<3);
  1437. #endif
  1438. fResult = CreateUrlCacheContainerA(
  1439. mpName.psStr,
  1440. mpCachePrefix.psStr,
  1441. mpCachePath.psStr,
  1442. KBCacheLimit,
  1443. dwContainerType,
  1444. dwOptions,
  1445. pvBuffer,
  1446. cbBuffer);
  1447. cleanup:
  1448. if (dwErr!=ERROR_SUCCESS)
  1449. {
  1450. SetLastError(dwErr);
  1451. DEBUG_ERROR(API, dwErr);
  1452. }
  1453. DEBUG_LEAVE_API(fResult);
  1454. return fResult;
  1455. }
  1456. URLCACHEAPI_(BOOL) DeleteUrlCacheContainerW(
  1457. IN LPCWSTR Name,
  1458. IN DWORD dwOptions)
  1459. {
  1460. ENTER_CACHE_API ((DBG_API, Bool, "DeleteContainerW", "%wq, %#x", Name, dwOptions));
  1461. DWORD dwErr = ERROR_SUCCESS;
  1462. MEMORYPACKET mpName;
  1463. BOOL fResult = FALSE, fStrNotSafe = FALSE;
  1464. ALLOC_MB(Name, 0, mpName);
  1465. if (!mpName.psStr)
  1466. {
  1467. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1468. goto cleanup;
  1469. }
  1470. UNICODE_TO_ANSI_CHECKED(Name, mpName, &fStrNotSafe);
  1471. if (fStrNotSafe)
  1472. {
  1473. dwErr = ERROR_INVALID_PARAMETER;
  1474. goto cleanup;
  1475. }
  1476. fResult = DeleteUrlCacheContainerA(mpName.psStr, dwOptions);
  1477. cleanup:
  1478. if (dwErr!=ERROR_SUCCESS)
  1479. {
  1480. SetLastError(dwErr);
  1481. DEBUG_ERROR(API, dwErr);
  1482. }
  1483. DEBUG_LEAVE_API(fResult);
  1484. return fResult;
  1485. }
  1486. URLCACHEAPI_(HANDLE) FindFirstUrlCacheContainerW(
  1487. IN OUT DWORD *pdwModified,
  1488. OUT LPINTERNET_CACHE_CONTAINER_INFOW lpContainerInfo,
  1489. IN OUT LPDWORD lpcbContainerInfo,
  1490. IN DWORD dwOptions
  1491. )
  1492. {
  1493. ENTER_CACHE_API ((DBG_API, Bool, "FindFirstContainerW",
  1494. "%#x, %#x, %#x, %#x",
  1495. pdwModified,
  1496. lpContainerInfo,
  1497. lpcbContainerInfo,
  1498. dwOptions
  1499. ));
  1500. DWORD dwErr = ERROR_SUCCESS;
  1501. MEMORYPACKET mpCacheInfo;
  1502. HANDLE hInternet = NULL;
  1503. if (!(lpcbContainerInfo && lpContainerInfo))
  1504. {
  1505. dwErr = ERROR_INVALID_PARAMETER;
  1506. goto cleanup;
  1507. }
  1508. mpCacheInfo.psStr = (PSTR)ALLOC_BYTES(*lpcbContainerInfo);
  1509. if (!mpCacheInfo.psStr)
  1510. {
  1511. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1512. goto cleanup;
  1513. }
  1514. mpCacheInfo.dwSize = mpCacheInfo.dwAlloc = *lpcbContainerInfo;
  1515. hInternet = FindFirstUrlCacheContainerA(pdwModified,
  1516. (LPINTERNET_CACHE_CONTAINER_INFOA)mpCacheInfo.psStr, &mpCacheInfo.dwSize, dwOptions);
  1517. // TransformCacheContainerInfoToW takes the return value and decides if any further actions need to be taken
  1518. // (eg. if successful, then try to convert from ansi to unicode; else if the ansi api failed, should we care?)
  1519. if (!TransformCacheContainerInfoToW(
  1520. hInternet ? TRUE : FALSE,
  1521. (LPINTERNET_CACHE_CONTAINER_INFOA)mpCacheInfo.psStr,
  1522. mpCacheInfo.dwSize,
  1523. lpContainerInfo,
  1524. lpcbContainerInfo))
  1525. {
  1526. if (hInternet)
  1527. {
  1528. FindCloseUrlCache(hInternet);
  1529. hInternet = NULL;
  1530. }
  1531. }
  1532. cleanup:
  1533. if (dwErr!=ERROR_SUCCESS)
  1534. {
  1535. SetLastError(dwErr);
  1536. DEBUG_ERROR(API, dwErr);
  1537. }
  1538. DEBUG_LEAVE_API(hInternet);
  1539. return hInternet;
  1540. }
  1541. URLCACHEAPI_(BOOL) FindNextUrlCacheContainerW(
  1542. IN HANDLE hEnumHandle,
  1543. OUT LPINTERNET_CACHE_CONTAINER_INFOW lpContainerInfo,
  1544. IN OUT LPDWORD lpcbContainerInfo
  1545. )
  1546. {
  1547. ENTER_CACHE_API ((DBG_API, Bool, "FindNextContainerW",
  1548. "%#x, %#x, %#x",
  1549. hEnumHandle,
  1550. lpContainerInfo,
  1551. lpcbContainerInfo
  1552. ));
  1553. DWORD dwErr = ERROR_SUCCESS;
  1554. MEMORYPACKET mpCacheInfo;
  1555. BOOL fResult = FALSE;
  1556. if (!(lpcbContainerInfo && lpContainerInfo))
  1557. {
  1558. dwErr = ERROR_INVALID_PARAMETER;
  1559. goto cleanup;
  1560. }
  1561. mpCacheInfo.psStr = (PSTR)ALLOC_BYTES(*lpcbContainerInfo);
  1562. if (!mpCacheInfo.psStr)
  1563. {
  1564. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1565. goto cleanup;
  1566. }
  1567. mpCacheInfo.dwSize = mpCacheInfo.dwAlloc = *lpcbContainerInfo;
  1568. fResult = FindNextUrlCacheContainerA(
  1569. hEnumHandle,
  1570. (LPINTERNET_CACHE_CONTAINER_INFOA)mpCacheInfo.psStr,
  1571. &mpCacheInfo.dwSize);
  1572. // TransformCacheContainerInfoToW takes the return value and decides if any further actions need to be taken
  1573. // (eg. if successful, then try to convert from ansi to unicode; else if the ansi api failed, should we care?)
  1574. fResult = TransformCacheContainerInfoToW(
  1575. fResult,
  1576. (LPINTERNET_CACHE_CONTAINER_INFOA)mpCacheInfo.psStr,
  1577. mpCacheInfo.dwSize,
  1578. lpContainerInfo,
  1579. lpcbContainerInfo);
  1580. cleanup:
  1581. if (dwErr!=ERROR_SUCCESS)
  1582. {
  1583. SetLastError(dwErr);
  1584. DEBUG_ERROR(API, dwErr);
  1585. }
  1586. DEBUG_LEAVE_API(fResult);
  1587. return fResult;
  1588. }
  1589. /* here's the struct referred to below
  1590. typedef struct _INTERNET_CACHE_CONFIG_INFOA {
  1591. DWORD dwStructSize;
  1592. DWORD dwContainer;
  1593. DWORD dwQuota;
  1594. DWORD dwReserved4;
  1595. BOOL fPerUser;
  1596. DWORD dwSyncMode;
  1597. DWORD dwNumCachePaths;
  1598. union
  1599. {
  1600. struct
  1601. {
  1602. CHAR CachePath[MAX_PATH];
  1603. DWORD dwCacheSize;
  1604. };
  1605. INTERNET_CACHE_CONFIG_PATH_ENTRYA CachePaths[ANYSIZE_ARRAY];
  1606. };
  1607. DWORD dwNormalUsage;
  1608. DWORD dwExemptUsage;
  1609. } INTERNET_CACHE_CONFIG_INFOA, * LPINTERNET_CACHE_CONFIG_INFOA;
  1610. */
  1611. #define ICCIA_FIXED_PORTION_SIZE ((sizeof(DWORD)*6)+sizeof(BOOL))
  1612. URLCACHEAPI_(BOOL) GetUrlCacheConfigInfoW(
  1613. OUT LPINTERNET_CACHE_CONFIG_INFOW pCacheConfigInfo,
  1614. IN OUT LPDWORD pcbCacheConfigInfo,
  1615. IN DWORD dwFieldControl
  1616. )
  1617. {
  1618. ENTER_CACHE_API ((DBG_API, Bool, "GetUrlCacheConfigInfoW", "%#x, %#x, %#x",
  1619. pCacheConfigInfo, pcbCacheConfigInfo, dwFieldControl ));
  1620. INTERNET_CACHE_CONFIG_INFOA iccia;
  1621. iccia.dwContainer = pCacheConfigInfo->dwContainer;
  1622. iccia.dwStructSize = sizeof(INTERNET_CACHE_CONFIG_INFOA);
  1623. DWORD dwSize = sizeof(INTERNET_CACHE_CONFIG_INFOA);
  1624. BOOL fResult = GetUrlCacheConfigInfoA(&iccia, &dwSize, dwFieldControl);
  1625. if (fResult)
  1626. {
  1627. memcpy(pCacheConfigInfo, &iccia, ICCIA_FIXED_PORTION_SIZE);
  1628. // These are appended to the _end_ of the structure.
  1629. pCacheConfigInfo->dwNormalUsage = iccia.dwNormalUsage;
  1630. pCacheConfigInfo->dwExemptUsage = iccia.dwExemptUsage;
  1631. pCacheConfigInfo->dwStructSize = sizeof(INTERNET_CACHE_CONFIG_INFOW);
  1632. if (pCacheConfigInfo->dwContainer <= HISTORY)
  1633. {
  1634. MultiByteToWideChar(CP_ACP, 0, iccia.CachePath, -1, pCacheConfigInfo->CachePath, ARRAY_ELEMENTS(pCacheConfigInfo->CachePath));
  1635. }
  1636. }
  1637. DEBUG_LEAVE_API (fResult);
  1638. return fResult;
  1639. }
  1640. URLCACHEAPI_(BOOL) SetUrlCacheConfigInfoW(
  1641. LPCACHE_CONFIG_INFOW lpConfigConfigInfo,
  1642. DWORD dwFieldControl
  1643. )
  1644. {
  1645. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  1646. return( FALSE );
  1647. }