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.

616 lines
22 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1994 **
  4. //*********************************************************************
  5. #include "pre.h"
  6. #include "perhist.h"
  7. #include "shlobj.h"
  8. const VARIANT c_vaEmpty = {0};
  9. const LARGE_INTEGER c_li0 = { 0, 0 };
  10. CHAR szTempBuffer[TEMP_BUFFER_LENGTH];
  11. #define ReadVerifyDW(x) if (!ReadDW(&(x),pcCSVFile)) \
  12. { \
  13. AssertMsg(0,"Invalid DWORD in CSV file"); \
  14. goto ReadOneLineError; \
  15. }
  16. #define ReadVerifyW(x) if (!ReadW(&(x),pcCSVFile)) \
  17. { \
  18. AssertMsg(0,"Invalid WORD in CSV file"); \
  19. goto ReadOneLineError; \
  20. }
  21. //Accepts -1 as a valid number. currently this is used for LCID, since all langs has a LDID == -1
  22. #define ReadVerifyWEx(x) if (!ReadWEx(&(x),pcCSVFile)) \
  23. { \
  24. AssertMsg(0,"Invalid WORD in CSV file"); \
  25. goto ReadOneLineError; \
  26. }
  27. #define ReadVerifyB(x) if (!ReadB(&(x),pcCSVFile)) \
  28. { \
  29. AssertMsg(0,"Invalid BYTE in CSV file"); \
  30. goto ReadOneLineError; \
  31. }
  32. #define ReadVerifyBOOL(x) if (!ReadBOOL(&(x),pcCSVFile)) \
  33. { \
  34. AssertMsg(0,"Invalid BOOL in CSV file"); \
  35. goto ReadOneLineError; \
  36. }
  37. #define ReadVerifySPECIAL(x, y, z) if (!ReadSPECIAL(&(x), &(y), &(z), pcCSVFile)) \
  38. { \
  39. AssertMsg(0,"Invalid SPECIAL in CSV file"); \
  40. goto ReadOneLineError; \
  41. }
  42. #define ReadVerifySZ(x,y) if (!ReadSZ(&x[0],y+sizeof('\0'),pcCSVFile)) \
  43. { \
  44. AssertMsg(0,"Invalid STRING in CSV file"); \
  45. goto ReadOneLineError; \
  46. }
  47. CISPCSV::~CISPCSV(void)
  48. {
  49. if(m_lpStgHistory)
  50. {
  51. // Release the storage
  52. m_lpStgHistory->Release();
  53. m_lpStgHistory = NULL;
  54. }
  55. if (hbmTierIcon)
  56. DeleteObject(hbmTierIcon);
  57. CleanupISPPageCache(TRUE);
  58. }
  59. // Do an strip of Single Quotes from a source string. The source is formatted as:
  60. // 'some text', and the dest string ends up being
  61. // some text
  62. void CISPCSV::StripQuotes
  63. (
  64. LPSTR lpszDst,
  65. LPSTR lpszSrc
  66. )
  67. {
  68. //strcpy(lpszDst, lpszSrc + 1, strlen(lpszSrc) - 1);
  69. strcpy(lpszDst, lpszSrc + 1);
  70. lpszDst[strlen(lpszDst) - 1] = '\0';
  71. }
  72. BOOL CISPCSV::ValidateFile(TCHAR* pszFile)
  73. {
  74. ASSERT(pszFile);
  75. if (!lstrlen(pszFile))
  76. return FALSE;
  77. if (GetFileAttributes(pszFile) == 0xFFFFFFFF)
  78. return FALSE;
  79. return TRUE;
  80. }
  81. // ############################################################################
  82. BOOL CISPCSV::ReadDW(DWORD far *pdw, CCSVFile far *pcCSVFile)
  83. {
  84. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  85. return FALSE;
  86. return (FSz2Dw(szTempBuffer,pdw));
  87. }
  88. // ############################################################################
  89. BOOL CISPCSV::ReadW(WORD far *pw, CCSVFile far *pcCSVFile)
  90. {
  91. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  92. return FALSE;
  93. return (FSz2W(szTempBuffer,pw));
  94. }
  95. // ############################################################################
  96. //Accepts -1 as a valid number. currently this is used for LCID, since all langs has a LDID == -1
  97. BOOL CISPCSV::ReadWEx(WORD far *pw, CCSVFile far *pcCSVFile)
  98. {
  99. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  100. return FALSE;
  101. return (FSz2WEx(szTempBuffer,pw));
  102. }
  103. // ############################################################################
  104. BOOL CISPCSV::ReadB(BYTE far *pb, CCSVFile far *pcCSVFile)
  105. {
  106. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  107. return FALSE;
  108. return (FSz2B(szTempBuffer,pb));
  109. }
  110. // ############################################################################
  111. BOOL CISPCSV::ReadBOOL(BOOL far *pbool, CCSVFile far *pcCSVFile)
  112. {
  113. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  114. return FALSE;
  115. return (FSz2BOOL(szTempBuffer,pbool));
  116. }
  117. // ############################################################################
  118. // A special int can be either a BOOL (TRUE,FALSE) or a int, 0 or -1
  119. // if the value is 0 or -1, then the pbIsSpecial bool is set to TRUE
  120. BOOL CISPCSV::ReadSPECIAL(BOOL far *pbool, BOOL far *pbIsSpecial, int far *pInt, CCSVFile far *pcCSVFile)
  121. {
  122. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  123. return FALSE;
  124. return (FSz2SPECIAL(szTempBuffer,pbool, pbIsSpecial, pInt));
  125. }
  126. // ############################################################################
  127. BOOL CISPCSV::ReadSZ(LPSTR psz, DWORD dwSize, CCSVFile far *pcCSVFile)
  128. {
  129. if (!pcCSVFile->ReadToken(psz,dwSize))
  130. return FALSE;
  131. return TRUE;
  132. }
  133. // ############################################################################
  134. BOOL CISPCSV::ReadToEOL(CCSVFile far *pcCSVFile)
  135. {
  136. return pcCSVFile->SkipTillEOL();
  137. }
  138. HRESULT CISPCSV::ReadOneLine
  139. (
  140. CCSVFile far *pcCSVFile
  141. )
  142. {
  143. HRESULT hr = ERROR_SUCCESS;
  144. CHAR szTemp [MAX_ISP_NAME];
  145. CHAR szISPLogoPath [MAX_PATH] = "\0";
  146. CHAR szISPTierLogoPath [MAX_PATH];
  147. CHAR szISPTeaserPath [MAX_PATH];
  148. CHAR szISPMarketingHTMPath [MAX_PATH];
  149. CHAR szISPFilePath [MAX_PATH];
  150. CHAR szISPName [MAX_ISP_NAME];
  151. //CHAR szCNSIconPath [MAX_PATH];
  152. CHAR szBillingFormPath [MAX_PATH];
  153. CHAR szPayCSVPath [MAX_PATH];
  154. CHAR szOfferGUID [MAX_GUID];
  155. CHAR szMir [MAX_ISP_NAME];
  156. if (!ReadSZ(szTemp, sizeof(szTemp), pcCSVFile))
  157. {
  158. hr = ERROR_NO_MORE_ITEMS; // no more enteries
  159. goto ReadOneLineExit;
  160. }
  161. // Strip the single quotes from the isp Name
  162. StripQuotes(szISPName, szTemp);
  163. ReadVerifyW(wOfferID);
  164. ReadVerifySZ(szISPLogoPath, sizeof(szISPLogoPath));
  165. ReadVerifySZ(szISPMarketingHTMPath, sizeof(szISPMarketingHTMPath));
  166. ReadVerifySZ(szISPTierLogoPath, sizeof(szISPTierLogoPath));
  167. ReadVerifySZ(szISPTeaserPath, sizeof(szISPTeaserPath));
  168. ReadVerifySZ(szISPFilePath, sizeof(szISPFilePath));
  169. ReadVerifyDW(dwCfgFlag);
  170. ReadVerifyDW(dwRequiredUserInputFlags);
  171. ReadVerifySZ(szBillingFormPath, sizeof(szBillingFormPath));
  172. ReadVerifySZ(szPayCSVPath, sizeof(szPayCSVPath));
  173. ReadVerifySZ(szOfferGUID, sizeof(szOfferGUID));
  174. ReadVerifySZ(szMir, sizeof(szMir));
  175. ReadVerifyWEx(wLCID); //Accepts -1 as a valid number. currently this is used for LCID, since all langs has a LDID == -1
  176. ReadToEOL(pcCSVFile);
  177. #ifdef UNICODE
  178. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szISPName, MAX_ISP_NAME, m_szISPName, MAX_ISP_NAME);
  179. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szISPLogoPath, MAX_PATH, m_szISPLogoPath, MAX_PATH);
  180. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szISPMarketingHTMPath, MAX_PATH, m_szISPMarketingHTMPath,MAX_PATH);
  181. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szISPTierLogoPath, MAX_PATH, m_szISPTierLogoPath, MAX_PATH);
  182. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szISPTeaserPath, MAX_PATH, m_szISPTeaserPath, MAX_PATH);
  183. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szISPFilePath, MAX_PATH, m_szISPFilePath, MAX_PATH);
  184. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szBillingFormPath, MAX_PATH, m_szBillingFormPath, MAX_PATH);
  185. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPayCSVPath, MAX_PATH, m_szPayCSVPath, MAX_PATH);
  186. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szOfferGUID, MAX_GUID, m_szOfferGUID, MAX_GUID);
  187. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szMir, MAX_ISP_NAME, m_szMir, MAX_ISP_NAME);
  188. #else
  189. lstrcpy(m_szISPName, szISPName);
  190. lstrcpy(m_szISPLogoPath, szISPLogoPath);
  191. lstrcpy(m_szISPMarketingHTMPath, szISPMarketingHTMPath);
  192. lstrcpy(m_szISPTierLogoPath, szISPTierLogoPath);
  193. lstrcpy(m_szISPTeaserPath, szISPTeaserPath);
  194. lstrcpy(m_szISPFilePath, szISPFilePath);
  195. lstrcpy(m_szBillingFormPath, szBillingFormPath);
  196. lstrcpy(m_szPayCSVPath, szPayCSVPath);
  197. lstrcpy(m_szOfferGUID, szOfferGUID);
  198. lstrcpy(m_szMir, szMir);
  199. #endif
  200. bCNS = (ICW_CFGFLAG_CNS & dwCfgFlag) ? TRUE : FALSE;
  201. bSecureConnection = (ICW_CFGFLAG_SECURE & dwCfgFlag) ? TRUE : FALSE;
  202. //If this is nooffer we won't try to validate
  203. if (!(dwCfgFlag & ICW_CFGFLAG_OFFERS))
  204. {
  205. if (!ValidateFile(m_szISPMarketingHTMPath))
  206. hr = ERROR_FILE_NOT_FOUND;
  207. return hr;
  208. }
  209. if (!(dwCfgFlag & ICW_CFGFLAG_AUTOCONFIG))
  210. {
  211. if (!ValidateFile(m_szISPMarketingHTMPath))
  212. return ERROR_FILE_NOT_FOUND;
  213. }
  214. if (dwCfgFlag & ICW_CFGFLAG_OEM_SPECIAL)
  215. {
  216. if (!ValidateFile(m_szISPTierLogoPath) || !ValidateFile(m_szISPTeaserPath))
  217. dwCfgFlag &= ~ICW_CFGFLAG_OEM_SPECIAL ;
  218. }
  219. //Try and validate the integrity of various offers
  220. //based on type.
  221. //OLS, CNS, NO-CNS
  222. if (!ValidateFile(m_szISPLogoPath))
  223. return ERROR_FILE_NOT_FOUND;
  224. if (!ValidateFile(m_szISPFilePath))
  225. return ERROR_FILE_NOT_FOUND;
  226. // Validate the billing path only when billing option is set
  227. if (dwCfgFlag & ICW_CFGFLAG_BILL)
  228. {
  229. if(!ValidateFile(m_szBillingFormPath))
  230. return ERROR_FILE_NOT_FOUND;
  231. }
  232. // Validate the payment path only when payment option is set
  233. if (dwCfgFlag & ICW_CFGFLAG_PAYMENT)
  234. {
  235. if(!ValidateFile(m_szPayCSVPath))
  236. return ERROR_FILE_NOT_FOUND;
  237. }
  238. ReadOneLineExit:
  239. return hr;
  240. ReadOneLineError:
  241. hr = ERROR_INVALID_DATA;
  242. goto ReadOneLineExit;
  243. }
  244. HRESULT CISPCSV::ReadFirstLine
  245. (
  246. CCSVFile far *pcCSVFile
  247. )
  248. {
  249. CHAR szTemp[TEMP_BUFFER_LENGTH];
  250. for (int i = 0; i < NUM_ISPCSV_FIELDS; i++)
  251. {
  252. if (!ReadSZ(szTemp, sizeof(szTemp), pcCSVFile))
  253. {
  254. return(ERROR_INVALID_DATA);
  255. }
  256. }
  257. ReadToEOL(pcCSVFile);
  258. return (ERROR_SUCCESS);
  259. }
  260. void CISPCSV::MakeCompleteURL(LPTSTR lpszURL, LPTSTR lpszSRC)
  261. {
  262. TCHAR szCurrentDir[MAX_PATH] = TEXT("\0");
  263. // Form the URL
  264. GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir);
  265. wsprintf (lpszURL, TEXT("FILE://%s\\%s"), szCurrentDir, lpszSRC);
  266. }
  267. // Display this object's HTML page
  268. HRESULT CISPCSV::DisplayHTML(LPTSTR szFile)
  269. {
  270. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  271. HRESULT hr;
  272. // Make the URL
  273. MakeCompleteURL(szURL, szFile);
  274. hr = gpWizardState->pICWWebView->DisplayHTML(szURL);
  275. return (hr);
  276. }
  277. //Takes RES ID
  278. HRESULT CISPCSV::DisplayTextWithISPName
  279. (
  280. HWND hDlgCtrl,
  281. int iMsgString,
  282. TCHAR* pszExtra //sticks something on the very end of the string if needed.
  283. )
  284. {
  285. TCHAR szFinal [MAX_MESSAGE_LEN*3] = TEXT("\0");
  286. TCHAR szFmt [MAX_MESSAGE_LEN];
  287. TCHAR *args [1];
  288. LPVOID pszIntro = NULL;
  289. args[0] = (LPTSTR) m_szISPName;
  290. // BUGBUG should probably check for error return from LoadString
  291. LoadString(ghInstanceResDll, iMsgString, szFmt, ARRAYSIZE(szFmt));
  292. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  293. szFmt,
  294. 0,
  295. 0,
  296. (LPTSTR)&pszIntro,
  297. 0,
  298. (va_list*)args))
  299. {
  300. lstrcpy(szFinal, (LPTSTR)pszIntro);
  301. if (pszExtra)
  302. lstrcat(szFinal, pszExtra);
  303. SetWindowText(hDlgCtrl, szFinal);
  304. }
  305. if (pszIntro)
  306. {
  307. LocalFree(pszIntro);
  308. }
  309. return(S_OK);
  310. }
  311. #if 0
  312. // Delete a Persisted History stream
  313. HRESULT CISPCSV::DeleteHistory
  314. (
  315. BSTR bstrStreamName
  316. )
  317. {
  318. // No persistence if we don't have a storage object
  319. ASSERT(m_lpStgHistory);
  320. if (!m_lpStgHistory)
  321. return E_FAIL;
  322. // Delete the stream
  323. return (m_lpStgHistory->DestroyElement(bstrStreamName));
  324. }
  325. #endif
  326. // Save the history of current lpBrowser using the provided name
  327. HRESULT CISPCSV::SaveHistory
  328. (
  329. BSTR bstrStreamName
  330. )
  331. {
  332. IStream *lpStream;
  333. IPersistHistory *pHist;
  334. IWebBrowser2 *lpWebBrowser;
  335. HRESULT hr = S_OK;
  336. // No persistence if we don't have a storage object
  337. ASSERT(m_lpStgHistory);
  338. if (!m_lpStgHistory)
  339. return E_FAIL;
  340. // Create a new Stream
  341. if (SUCCEEDED(hr = m_lpStgHistory->CreateStream(bstrStreamName,
  342. STGM_DIRECT |
  343. STGM_READWRITE |
  344. STGM_SHARE_EXCLUSIVE |
  345. STGM_CREATE,
  346. 0,
  347. 0,
  348. &lpStream)))
  349. {
  350. // Get an IPersistHistory interface pointer on the current WebBrowser object
  351. gpWizardState->pICWWebView->get_BrowserObject(&lpWebBrowser);
  352. if ( SUCCEEDED(lpWebBrowser->QueryInterface(IID_IPersistHistory, (LPVOID*) &pHist)))
  353. {
  354. // Save the history
  355. pHist->SaveHistory(lpStream);
  356. pHist->Release();
  357. // Reset the stream pointer to the beginning
  358. lpStream->Seek(c_li0, STREAM_SEEK_SET, NULL);
  359. }
  360. lpStream->Release();
  361. }
  362. return (hr);
  363. }
  364. HRESULT CISPCSV::LoadHistory
  365. (
  366. BSTR bstrStreamName
  367. )
  368. {
  369. IStream *lpStream;
  370. IPersistHistory *pHist;
  371. IWebBrowser2 *lpWebBrowser;
  372. HRESULT hr = S_OK;
  373. // No persistence if we don't have a storage object
  374. ASSERT(m_lpStgHistory);
  375. if (!m_lpStgHistory)
  376. return E_FAIL;
  377. // Open the Stream
  378. if (SUCCEEDED(hr = m_lpStgHistory->OpenStream(bstrStreamName,
  379. NULL,
  380. STGM_DIRECT |
  381. STGM_READWRITE |
  382. STGM_SHARE_EXCLUSIVE,
  383. 0,
  384. &lpStream)))
  385. {
  386. // Get an IPersistHistory interface pointer on the current WebBrowser object
  387. gpWizardState->pICWWebView->get_BrowserObject(&lpWebBrowser);
  388. if ( SUCCEEDED(lpWebBrowser->QueryInterface(IID_IPersistHistory, (LPVOID*) &pHist)))
  389. {
  390. // Save the history
  391. pHist->LoadHistory(lpStream, NULL);
  392. pHist->Release();
  393. // Reset the stream pointer to the beginning
  394. lpStream->Seek(c_li0, STREAM_SEEK_SET, NULL);
  395. }
  396. lpStream->Release();
  397. }
  398. return (hr);
  399. }
  400. // This funtion will get the name of a ISP page cache filen from the page's ID
  401. HRESULT CISPCSV::GetCacheFileNameFromPageID
  402. (
  403. BSTR bstrPageID,
  404. LPTSTR lpszCacheFile,
  405. ULONG cbszCacheFile
  406. )
  407. {
  408. HRESULT hr = S_OK;
  409. IStream *lpStream;
  410. ULONG cbRead;
  411. if (!m_lpStgIspPages)
  412. return E_FAIL;
  413. // Open the stream
  414. if (SUCCEEDED(hr = m_lpStgIspPages->OpenStream(bstrPageID,
  415. NULL,
  416. STGM_DIRECT |
  417. STGM_READWRITE |
  418. STGM_SHARE_EXCLUSIVE,
  419. 0,
  420. &lpStream)))
  421. {
  422. // Read the file name
  423. lpStream->Read(lpszCacheFile, cbszCacheFile, &cbRead);
  424. // release the stream
  425. lpStream->Release();
  426. }
  427. return hr;
  428. }
  429. // This function will cleanup the ISP Page cache. This means deleting all temp files created
  430. // and cleaning up the structured storage object used to store the file names
  431. void CISPCSV::CleanupISPPageCache(BOOL bReleaseStorage)
  432. {
  433. IEnumSTATSTG *pEnum;
  434. STATSTG StreamInfo;
  435. IMalloc *pMalloc = NULL;
  436. // If we have a storage object already created, then enumerate the streams
  437. // in it, and free the underlying cache files.
  438. if (m_lpStgIspPages)
  439. {
  440. if (SUCCEEDED (SHGetMalloc (&pMalloc)))
  441. {
  442. if (SUCCEEDED(m_lpStgIspPages->EnumElements(0, NULL, 0, &pEnum)))
  443. {
  444. while(S_OK == pEnum->Next(1, &StreamInfo, NULL))
  445. {
  446. if (StreamInfo.pwcsName)
  447. {
  448. TCHAR szPath[MAX_PATH];
  449. if (SUCCEEDED(GetCacheFileNameFromPageID(StreamInfo.pwcsName,
  450. szPath,
  451. sizeof(szPath))))
  452. {
  453. // delete the file
  454. DeleteFile(szPath);
  455. m_lpStgIspPages->DestroyElement(StreamInfo.pwcsName);
  456. if(m_lpStgHistory)
  457. m_lpStgHistory->DestroyElement(StreamInfo.pwcsName);
  458. // Free the memory allocated by the enumerator
  459. pMalloc->Free (StreamInfo.pwcsName);
  460. }
  461. }
  462. }
  463. // Release the enumerator
  464. pEnum->Release();
  465. }
  466. // release the Shell Memory allocator
  467. pMalloc->Release ();
  468. }
  469. if (bReleaseStorage)
  470. {
  471. // Release the storage
  472. m_lpStgIspPages->Release();
  473. m_lpStgIspPages= NULL;
  474. }
  475. }
  476. }
  477. // This function will create a new page cache entry if necessary using the PageID as an
  478. // index. If an entry does not exists, and temp file will be create, then name stored,
  479. // and the data in lpszTempFile will be copied into the new file.
  480. // If the page already exists, this function will just return.
  481. HRESULT CISPCSV::CopyFiletoISPPageCache
  482. (
  483. BSTR bstrPageID,
  484. LPTSTR lpszTempFile
  485. )
  486. {
  487. HRESULT hr = S_OK;
  488. TCHAR szTempPath[MAX_PATH];
  489. TCHAR szISPCacheFile[MAX_PATH];
  490. IStream *lpStream;
  491. ULONG cbWritten;
  492. if (!m_lpStgIspPages)
  493. return E_FAIL;
  494. if (SUCCEEDED(GetCacheFileNameFromPageID(bstrPageID,
  495. szISPCacheFile,
  496. sizeof(szISPCacheFile))))
  497. {
  498. // The pageID already has a file in the cache, so we can just return success
  499. return S_OK;
  500. }
  501. if (!GetTempPath(ARRAYSIZE(szTempPath), szTempPath))
  502. return E_FAIL;
  503. // No file yet, so we have to create one
  504. if (!GetTempFileName(szTempPath, TEXT("ICW"), 0, szISPCacheFile))
  505. return E_FAIL;
  506. // Create a stream using the passed in page ID
  507. if (SUCCEEDED(hr = m_lpStgIspPages->CreateStream(bstrPageID,
  508. STGM_DIRECT |
  509. STGM_READWRITE |
  510. STGM_SHARE_EXCLUSIVE |
  511. STGM_CREATE,
  512. 0,
  513. 0,
  514. &lpStream)))
  515. {
  516. // Write the file name to the stream, including the NULL terminator
  517. #ifdef UNICODE
  518. DWORD dwSize = (lstrlen(szISPCacheFile)+1) * sizeof(TCHAR);
  519. if (SUCCEEDED(hr = lpStream->Write(szISPCacheFile, dwSize, &cbWritten)))
  520. #else
  521. if (SUCCEEDED(hr = lpStream->Write(szISPCacheFile, lstrlen(szISPCacheFile)+1, &cbWritten)))
  522. #endif
  523. {
  524. // Copy the passed in temp file
  525. if (!CopyFile(lpszTempFile, szISPCacheFile, FALSE))
  526. hr = E_FAIL;
  527. }
  528. // Release the stream
  529. lpStream->Release();
  530. }
  531. return hr;
  532. }