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.

1298 lines
30 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. Utils.cpp
  5. Abstract:
  6. Provides utility functions for the entire poject
  7. Author:
  8. Eran Yariv (EranY) Dec, 1999
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #define __FILE_ID__ 10
  13. #ifdef _DEBUG
  14. #define new DEBUG_NEW
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. extern CClientConsoleApp theApp;
  19. DWORD
  20. LoadResourceString (
  21. CString &cstr,
  22. int ResId
  23. )
  24. /*++
  25. Routine name : LoadResourceString
  26. Routine description:
  27. Loads a string from the resource
  28. Author:
  29. Eran Yariv (EranY), Jan, 2000
  30. Arguments:
  31. cstr [out] - String buffer
  32. ResId [in ] - String resource id
  33. Return Value:
  34. Standard win32 error code
  35. --*/
  36. {
  37. BOOL bRes;
  38. DWORD dwRes = ERROR_SUCCESS;
  39. try
  40. {
  41. bRes = cstr.LoadString (ResId);
  42. }
  43. catch (CMemoryException *pException)
  44. {
  45. DBG_ENTER(TEXT("LoadResourceString"), dwRes);
  46. TCHAR wszCause[1024];
  47. pException->GetErrorMessage (wszCause, 1024);
  48. pException->Delete ();
  49. VERBOSE (EXCEPTION_ERR,
  50. TEXT("CString::LoadString caused exception : %s"),
  51. wszCause);
  52. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  53. PopupError (dwRes);
  54. return dwRes;
  55. }
  56. if (!bRes)
  57. {
  58. dwRes = ERROR_NOT_FOUND;
  59. PopupError (dwRes);
  60. return dwRes;
  61. }
  62. return dwRes;
  63. } // LoadResourceString
  64. CString
  65. DWORDLONG2String (
  66. DWORDLONG dwlData
  67. )
  68. /*++
  69. Routine name : DWORDLONG2String
  70. Routine description:
  71. Converts a 64-bit unsigned number to string
  72. Author:
  73. Eran Yariv (EranY), Jan, 2000
  74. Arguments:
  75. dwlData [in] - Number to convert
  76. Return Value:
  77. Output string
  78. --*/
  79. {
  80. CString cstrResult;
  81. cstrResult.Format (TEXT("0x%016I64x"), dwlData);
  82. return cstrResult;
  83. } // DWORDLONG2String
  84. CString
  85. DWORD2String (
  86. DWORD dwData
  87. )
  88. /*++
  89. Routine name : DWORD2String
  90. Routine description:
  91. Converts a 32-bit unsigned number to string
  92. Author:
  93. Eran Yariv (EranY), Jan, 2000
  94. Arguments:
  95. dwData [in] - Number to convert
  96. Return Value:
  97. Output string
  98. --*/
  99. {
  100. CString cstrResult;
  101. cstrResult.Format (TEXT("%ld"), dwData);
  102. return cstrResult;
  103. } // DWORD2String
  104. DWORD
  105. Win32Error2String(
  106. DWORD dwWin32Err,
  107. CString& strError
  108. )
  109. /*++
  110. Routine name : Win32Error2String
  111. Routine description:
  112. Format a Win32 error code to a string
  113. Author:
  114. Eran Yariv (EranY), Jan, 2000
  115. Arguments:
  116. dwWin32Err [in] - Win32 error code
  117. strError [out] - Result string
  118. Return Value:
  119. error code
  120. --*/
  121. {
  122. DWORD dwRes = ERROR_SUCCESS;
  123. DBG_ENTER(TEXT("Win32Error2String"));
  124. LPTSTR lpszError=NULL;
  125. //
  126. // Create descriptive error text
  127. //
  128. if (!FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
  129. FORMAT_MESSAGE_FROM_SYSTEM |
  130. FORMAT_MESSAGE_IGNORE_INSERTS,
  131. NULL,
  132. dwWin32Err,
  133. 0,
  134. (TCHAR *)&lpszError,
  135. 0,
  136. NULL))
  137. {
  138. //
  139. // Failure to format the message
  140. //
  141. dwRes = GetLastError ();
  142. CALL_FAIL (RESOURCE_ERR, TEXT("FormatMessage"), dwRes);
  143. return dwRes;
  144. }
  145. try
  146. {
  147. strError = lpszError;
  148. }
  149. catch (...)
  150. {
  151. LocalFree (lpszError);
  152. return ERROR_NOT_ENOUGH_MEMORY;
  153. }
  154. LocalFree (lpszError);
  155. return dwRes;
  156. } // Win32Error2String
  157. DWORD
  158. LoadDIBImageList (
  159. CImageList &iml,
  160. int iResourceId,
  161. DWORD dwImageWidth,
  162. COLORREF crMask
  163. )
  164. /*++
  165. Routine name : LoadDIBImageList
  166. Routine description:
  167. Loads an image list from the resource, retaining 24-bit colors
  168. Author:
  169. Eran Yariv (EranY), Jan, 2000
  170. Arguments:
  171. iml [out] - Image list buffer
  172. iResourceId [in ] - Image list bitmap resource id
  173. dwImageWidth [in ] - Image width (pixels)
  174. crMask [in ] - Color key (transparent mask)
  175. Return Value:
  176. Standard Win32 error code
  177. --*/
  178. {
  179. DWORD dwRes = ERROR_SUCCESS;
  180. DBG_ENTER(TEXT("LoadDIBImageList"), dwRes);
  181. HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(iResourceId), RT_BITMAP);
  182. if (hInst)
  183. {
  184. HIMAGELIST hIml = ImageList_LoadImage ( hInst,
  185. MAKEINTRESOURCE(iResourceId),
  186. dwImageWidth,
  187. 0,
  188. crMask,
  189. IMAGE_BITMAP,
  190. LR_DEFAULTCOLOR);
  191. if (hIml)
  192. {
  193. if (!iml.Attach (hIml))
  194. {
  195. dwRes = ERROR_GEN_FAILURE;
  196. CALL_FAIL (WINDOW_ERR, TEXT("CImageList::Attach"), dwRes);
  197. DeleteObject (hIml);
  198. }
  199. }
  200. else
  201. {
  202. //
  203. // ImageList_LoadImage() failed
  204. //
  205. dwRes = GetLastError();
  206. CALL_FAIL (WINDOW_ERR, _T("ImageList_LoadImage"), dwRes);
  207. }
  208. }
  209. else
  210. {
  211. //
  212. // AfxFindResourceHandle() failed
  213. //
  214. dwRes = GetLastError();
  215. CALL_FAIL (WINDOW_ERR, _T("AfxFindResourceHandle"), dwRes);
  216. }
  217. return dwRes;
  218. } // LoadDIBImageList
  219. #define BUILD_THREAD_DEATH_TIMEOUT INFINITE
  220. DWORD
  221. WaitForThreadDeathOrShutdown (
  222. HANDLE hThread
  223. )
  224. /*++
  225. Routine name : WaitForThreadDeathOrShutdown
  226. Routine description:
  227. Waits for a thread to end.
  228. Also processes windows messages in the background.
  229. Stops waiting if the application is shutting down.
  230. Author:
  231. Eran Yariv (EranY), Jan, 2000
  232. Arguments:
  233. hThread [in] - Handle to thread
  234. Return Value:
  235. Standard Win23 error code
  236. --*/
  237. {
  238. DWORD dwRes = ERROR_SUCCESS;
  239. DBG_ENTER(TEXT("WaitForThreadDeathOrShutdown"), dwRes);
  240. for (;;)
  241. {
  242. //
  243. // We wait on the thread handle and the shutdown event (which ever comes first)
  244. //
  245. HANDLE hWaitHandles[2];
  246. hWaitHandles[0] = hThread;
  247. hWaitHandles[1] = CClientConsoleDoc::GetShutdownEvent ();
  248. if (NULL == hWaitHandles[1])
  249. {
  250. //
  251. // We're shutting down
  252. //
  253. return dwRes;
  254. }
  255. DWORD dwStart = GetTickCount ();
  256. VERBOSE (DBG_MSG,
  257. TEXT("Entering WaitForMultipleObjects (timeout = %ld)"),
  258. BUILD_THREAD_DEATH_TIMEOUT);
  259. //
  260. // Wait now....
  261. //
  262. dwRes = MsgWaitForMultipleObjects(
  263. sizeof (hWaitHandles) / sizeof(hWaitHandles[0]), // Num of wait objects
  264. hWaitHandles, // Array of wait objects
  265. FALSE, // Wait for either one
  266. BUILD_THREAD_DEATH_TIMEOUT, // Timeout
  267. QS_ALLINPUT); // Accept messages
  268. DWORD dwRes2 = GetLastError();
  269. VERBOSE (DBG_MSG,
  270. TEXT("Leaving WaitForMultipleObjects after waiting for %ld millisecs"),
  271. GetTickCount() - dwStart);
  272. switch (dwRes)
  273. {
  274. case WAIT_FAILED:
  275. dwRes = dwRes2;
  276. if (ERROR_INVALID_HANDLE == dwRes)
  277. {
  278. //
  279. // The thread is dead
  280. //
  281. VERBOSE (DBG_MSG, TEXT("Thread is dead (ERROR_INVALID_HANDLE)"));
  282. dwRes = ERROR_SUCCESS;
  283. }
  284. goto exit;
  285. case WAIT_OBJECT_0:
  286. //
  287. // The thread is not running
  288. //
  289. VERBOSE (DBG_MSG, TEXT("Thread is dead (WAIT_OBJECT_0)"));
  290. dwRes = ERROR_SUCCESS;
  291. goto exit;
  292. case WAIT_OBJECT_0 + 1:
  293. //
  294. // Shutdown is now in progress
  295. //
  296. VERBOSE (DBG_MSG, TEXT("Shutdown in progress"));
  297. dwRes = ERROR_SUCCESS;
  298. goto exit;
  299. case WAIT_OBJECT_0 + 2:
  300. //
  301. // System message (WM_xxx) in our queue
  302. //
  303. MSG msg;
  304. if (TRUE == ::GetMessage (&msg, NULL, NULL, NULL))
  305. {
  306. VERBOSE (DBG_MSG,
  307. TEXT("System message (0x%x)- deferring to AfxWndProc"),
  308. msg.message);
  309. CMainFrame *pFrm = GetFrm();
  310. if (!pFrm)
  311. {
  312. //
  313. // Shutdown in progress
  314. //
  315. goto exit;
  316. }
  317. if (msg.message != WM_KICKIDLE &&
  318. !pFrm->PreTranslateMessage(&msg))
  319. {
  320. ::TranslateMessage(&msg);
  321. ::DispatchMessage(&msg);
  322. }
  323. }
  324. else
  325. {
  326. //
  327. // Got WM_QUIT
  328. //
  329. AfxPostQuitMessage (0);
  330. dwRes = ERROR_SUCCESS;
  331. goto exit;
  332. }
  333. break;
  334. case WAIT_TIMEOUT:
  335. //
  336. // Thread won't die !!!
  337. //
  338. VERBOSE (DBG_MSG,
  339. TEXT("Wait timeout (%ld millisecs)"),
  340. BUILD_THREAD_DEATH_TIMEOUT);
  341. goto exit;
  342. default:
  343. //
  344. // What's this???
  345. //
  346. VERBOSE (DBG_MSG,
  347. TEXT("Unknown error (%ld)"),
  348. dwRes);
  349. ASSERTION_FAILURE;
  350. goto exit;
  351. }
  352. }
  353. exit:
  354. return dwRes;
  355. } // WaitForThreadDeathOrShutdown
  356. DWORD
  357. GetUniqueFileName (
  358. LPCTSTR lpctstrExt,
  359. CString &cstrResult
  360. )
  361. /*++
  362. Routine name : GetUniqueFileName
  363. Routine description:
  364. Generates a unique file name
  365. Author:
  366. Eran Yariv (EranY), Jan, 2000
  367. Arguments:
  368. lpctstrExt [in] - File extension
  369. cstrResult [out] - Result file name
  370. Return Value:
  371. Standard Win32 error code
  372. --*/
  373. {
  374. DWORD dwRes = ERROR_SUCCESS;
  375. DBG_ENTER(TEXT("GetUniqueFileName"), dwRes);
  376. TCHAR szDir[MAX_PATH];
  377. //
  378. // Get path to temp dir
  379. //
  380. if (!GetTempPath (MAX_PATH, szDir))
  381. {
  382. dwRes = GetLastError ();
  383. CALL_FAIL (FILE_ERR, TEXT("GetTempPath"), dwRes);
  384. return dwRes;
  385. }
  386. //
  387. // Try out indices - start with a random index and advance (cyclic) by 1.
  388. // We're calling rand() 3 times here because we want to get a larger
  389. // range than 0..RAND_MAX (=32768)
  390. //
  391. DWORD dwStartIndex = DWORD((DWORDLONG)(rand()) *
  392. (DWORDLONG)(rand()) *
  393. (DWORDLONG)(rand())
  394. );
  395. for (DWORD dwIndex = dwStartIndex+1; dwIndex != dwStartIndex; dwIndex++)
  396. {
  397. try
  398. {
  399. cstrResult.Format (TEXT("%s%s%08x%08x.%s"),
  400. szDir,
  401. CONSOLE_PREVIEW_TIFF_PREFIX,
  402. GetCurrentProcessId(),
  403. dwIndex,
  404. lpctstrExt);
  405. }
  406. catch (CMemoryException *pException)
  407. {
  408. TCHAR wszCause[1024];
  409. pException->GetErrorMessage (wszCause, 1024);
  410. pException->Delete ();
  411. VERBOSE (EXCEPTION_ERR,
  412. TEXT("CString::Format caused exception : %s"),
  413. wszCause);
  414. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  415. return dwRes;
  416. }
  417. HANDLE hFile = CreateFile( cstrResult,
  418. GENERIC_WRITE,
  419. FILE_SHARE_READ,
  420. NULL,
  421. CREATE_NEW,
  422. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
  423. NULL);
  424. if (INVALID_HANDLE_VALUE == hFile)
  425. {
  426. dwRes = GetLastError ();
  427. if (ERROR_FILE_EXISTS == dwRes)
  428. {
  429. //
  430. // Try next index id
  431. //
  432. dwRes = ERROR_SUCCESS;
  433. continue;
  434. }
  435. CALL_FAIL (FILE_ERR, TEXT("CreateFile"), dwRes);
  436. return dwRes;
  437. }
  438. //
  439. // Success - close the file (leave it with size 0)
  440. //
  441. CloseHandle (hFile);
  442. return dwRes;
  443. }
  444. //
  445. // We just scanned 4GB file names and all were busy - impossible.
  446. //
  447. ASSERTION_FAILURE;
  448. dwRes = ERROR_GEN_FAILURE;
  449. return dwRes;
  450. } // GetUniqueFileName
  451. DWORD
  452. CopyTiffFromServer (
  453. CServerNode *pServer,
  454. DWORDLONG dwlMsgId,
  455. FAX_ENUM_MESSAGE_FOLDER Folder,
  456. CString &cstrTiff
  457. )
  458. /*++
  459. Routine name : CopyTiffFromServer
  460. Routine description:
  461. Copies a TIFF file from the server's archive / queue
  462. Author:
  463. Eran Yariv (EranY), Jan, 2000
  464. Arguments:
  465. pServer [in] - Pointer to the server node
  466. dwlMsgId [in] - Id of job / message
  467. Folder [in] - Folder of message / job
  468. cstrTiff [out] - Name of TIFF file that arrived from the server
  469. Return Value:
  470. Standard Win32 error code
  471. --*/
  472. {
  473. DWORD dwRes = ERROR_SUCCESS;
  474. DBG_ENTER(TEXT("CopyTiffFromServer"), dwRes);
  475. //
  476. // Create a temporary file name for the TIFF
  477. //
  478. dwRes = GetUniqueFileName (FAX_TIF_FILE_EXT, cstrTiff);
  479. if (ERROR_SUCCESS != dwRes)
  480. {
  481. CALL_FAIL (GENERAL_ERR, TEXT("GetUniqueFileName"), dwRes);
  482. return dwRes;
  483. }
  484. HANDLE hFax;
  485. dwRes = pServer->GetConnectionHandle (hFax);
  486. if (ERROR_SUCCESS != dwRes)
  487. {
  488. CALL_FAIL (GENERAL_ERR, TEXT("CServerNode::GetConnectionHandle"), dwRes);
  489. goto exit;
  490. }
  491. {
  492. START_RPC_TIME(TEXT("FaxGetMessageTiff"));
  493. if (!FaxGetMessageTiff (hFax,
  494. dwlMsgId,
  495. Folder,
  496. cstrTiff))
  497. {
  498. dwRes = GetLastError ();
  499. END_RPC_TIME(TEXT("FaxGetMessageTiff"));
  500. pServer->SetLastRPCError (dwRes);
  501. CALL_FAIL (RPC_ERR, TEXT("FaxGetMessageTiff"), dwRes);
  502. goto exit;
  503. }
  504. END_RPC_TIME(TEXT("FaxGetMessageTiff"));
  505. }
  506. ASSERTION (ERROR_SUCCESS == dwRes);
  507. exit:
  508. if (ERROR_SUCCESS != dwRes)
  509. {
  510. DeleteFile (cstrTiff);
  511. }
  512. return dwRes;
  513. } // CopyTiffFromServer
  514. DWORD
  515. GetDllVersion (
  516. LPCTSTR lpszDllName
  517. )
  518. /*++
  519. Routine Description:
  520. Returns the version information for a DLL exporting "DllGetVersion".
  521. DllGetVersion is exported by the shell DLLs (specifically COMCTRL32.DLL).
  522. Arguments:
  523. lpszDllName - The name of the DLL to get version information from.
  524. Return Value:
  525. The version is retuned as DWORD where:
  526. HIWORD ( version DWORD ) = Major Version
  527. LOWORD ( version DWORD ) = Minor Version
  528. Use the macro PACKVERSION to comapre versions.
  529. If the DLL does not export "DllGetVersion" the function returns 0.
  530. --*/
  531. {
  532. DWORD dwVersion = 0;
  533. DBG_ENTER(TEXT("GetDllVersion"), dwVersion, TEXT("%s"), lpszDllName);
  534. HINSTANCE hinstDll;
  535. hinstDll = LoadLibrary(lpszDllName);
  536. if(hinstDll)
  537. {
  538. DLLGETVERSIONPROC pDllGetVersion;
  539. pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hinstDll, "DllGetVersion");
  540. // Because some DLLs may not implement this function, you
  541. // must test for it explicitly. Depending on the particular
  542. // DLL, the lack of a DllGetVersion function may
  543. // be a useful indicator of the version.
  544. if(pDllGetVersion)
  545. {
  546. DLLVERSIONINFO dvi;
  547. HRESULT hr;
  548. ZeroMemory(&dvi, sizeof(dvi));
  549. dvi.cbSize = sizeof(dvi);
  550. hr = (*pDllGetVersion)(&dvi);
  551. if(SUCCEEDED(hr))
  552. {
  553. dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion);
  554. }
  555. }
  556. FreeLibrary(hinstDll);
  557. }
  558. return dwVersion;
  559. } // GetDllVersion
  560. DWORD
  561. ReadRegistryString(
  562. LPCTSTR lpszSection, // in
  563. LPCTSTR lpszKey, // in
  564. CString& cstrValue // out
  565. )
  566. /*++
  567. Routine name : ReadRegistryString
  568. Routine description:
  569. read string from registry
  570. Author:
  571. Alexander Malysh (AlexMay), Feb, 2000
  572. Arguments:
  573. lpszSection [in] - section
  574. lpszKey [in] - key
  575. out [out] - value
  576. Return Value:
  577. Standard Win32 error code
  578. --*/
  579. {
  580. DWORD dwRes = ERROR_SUCCESS;
  581. DBG_ENTER(TEXT("ReadRegistryString"), dwRes);
  582. HKEY hKey;
  583. dwRes = RegOpenKeyEx( HKEY_CURRENT_USER, lpszSection, 0, KEY_QUERY_VALUE, &hKey);
  584. if(ERROR_SUCCESS != dwRes)
  585. {
  586. CALL_FAIL (GENERAL_ERR, TEXT("RegOpenKeyEx"), dwRes);
  587. return dwRes;
  588. }
  589. DWORD dwType;
  590. TCHAR tchData[1024];
  591. DWORD dwDataSize = sizeof(tchData);
  592. dwRes = RegQueryValueEx( hKey, lpszKey, 0, &dwType, (BYTE*)tchData, &dwDataSize);
  593. if(ERROR_SUCCESS != dwRes)
  594. {
  595. CALL_FAIL (GENERAL_ERR, TEXT("RegQueryValueEx"), dwRes);
  596. goto exit;
  597. }
  598. if(REG_SZ != dwType)
  599. {
  600. dwRes = ERROR_BADDB;
  601. goto exit;
  602. }
  603. try
  604. {
  605. cstrValue = tchData;
  606. }
  607. catch(...)
  608. {
  609. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  610. CALL_FAIL (MEM_ERR, TEXT("CString::operator="), dwRes);
  611. goto exit;
  612. }
  613. exit:
  614. dwRes = RegCloseKey( hKey );
  615. if(ERROR_SUCCESS != dwRes)
  616. {
  617. CALL_FAIL (GENERAL_ERR, TEXT("RegCloseKey"), dwRes);
  618. return dwRes;
  619. }
  620. return dwRes;
  621. } // ReadRegistryString
  622. DWORD
  623. WriteRegistryString(
  624. LPCTSTR lpszSection, // in
  625. LPCTSTR lpszKey, // in
  626. CString& cstrValue // in
  627. )
  628. /*++
  629. Routine name : WriteRegistryString
  630. Routine description:
  631. write string to the regostry
  632. Author:
  633. Alexander Malysh (AlexMay), Feb, 2000
  634. Arguments:
  635. lpszSection [in] - section
  636. lpszKey [in] - key
  637. out [in] - value
  638. Return Value:
  639. Standard Win32 error code
  640. --*/
  641. {
  642. DWORD dwRes = ERROR_SUCCESS;
  643. DBG_ENTER(TEXT("WriteRegistryString"), dwRes);
  644. HKEY hKey;
  645. dwRes = RegOpenKeyEx( HKEY_CURRENT_USER, lpszSection, 0, KEY_SET_VALUE, &hKey);
  646. if(ERROR_SUCCESS != dwRes)
  647. {
  648. CALL_FAIL (GENERAL_ERR, TEXT("RegOpenKeyEx"), dwRes);
  649. return dwRes;
  650. }
  651. LPCTSTR lpData = (LPCTSTR)cstrValue;
  652. dwRes = RegSetValueEx( hKey,
  653. lpszKey,
  654. 0,
  655. REG_SZ,
  656. (BYTE*)lpData,
  657. (1 + cstrValue.GetLength()) * sizeof (TCHAR));
  658. if(ERROR_SUCCESS != dwRes)
  659. {
  660. CALL_FAIL (GENERAL_ERR, TEXT("RegSetValueEx"), dwRes);
  661. goto exit;
  662. }
  663. exit:
  664. dwRes = RegCloseKey( hKey );
  665. if(ERROR_SUCCESS != dwRes)
  666. {
  667. CALL_FAIL (GENERAL_ERR, TEXT("RegCloseKey"), dwRes);
  668. return dwRes;
  669. }
  670. return dwRes;
  671. } // WriteRegistryString
  672. DWORD
  673. FaxSizeFormat(
  674. DWORDLONG dwlSize, // in
  675. CString& cstrValue // out
  676. )
  677. /*++
  678. Routine name : FaxSizeFormat
  679. Routine description:
  680. format string of file size
  681. Author:
  682. Alexander Malysh (AlexMay), Feb, 2000
  683. Arguments:
  684. wdlSize [in] - size
  685. out [out] - formatted string
  686. Return Value:
  687. Standard Win32 error code
  688. --*/
  689. {
  690. DWORD dwRes = ERROR_SUCCESS;
  691. DBG_ENTER(TEXT("FaxSizeFormat"), dwRes);
  692. if(dwlSize > 0 && dwlSize < 1024)
  693. {
  694. dwlSize = 1;
  695. }
  696. else
  697. {
  698. dwlSize = dwlSize / (DWORDLONG)1024;
  699. }
  700. try
  701. {
  702. cstrValue.Format (TEXT("%I64d"), dwlSize);
  703. }
  704. catch(...)
  705. {
  706. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  707. CALL_FAIL (MEM_ERR, TEXT("CString::Format"), dwRes);
  708. return dwRes;
  709. }
  710. //
  711. // format the number
  712. //
  713. int nFormatRes;
  714. TCHAR tszNumber[100];
  715. nFormatRes = GetNumberFormat(LOCALE_USER_DEFAULT, // locale
  716. 0, // options
  717. cstrValue, // input number string
  718. NULL, // formatting information
  719. tszNumber, // output buffer
  720. sizeof(tszNumber) / sizeof(tszNumber[0]) // size of output buffer
  721. );
  722. if(0 == nFormatRes)
  723. {
  724. dwRes = GetLastError();
  725. CALL_FAIL (GENERAL_ERR, TEXT("GetNumberFormat"), dwRes);
  726. return dwRes;
  727. }
  728. //
  729. // get decimal separator
  730. //
  731. TCHAR tszDec[10];
  732. nFormatRes = GetLocaleInfo(LOCALE_USER_DEFAULT, // locale identifier
  733. LOCALE_SDECIMAL, // information type
  734. tszDec, // information buffer
  735. sizeof(tszDec) / sizeof(tszDec[0]) // size of buffer
  736. );
  737. if(0 == nFormatRes)
  738. {
  739. dwRes = GetLastError();
  740. CALL_FAIL (GENERAL_ERR, TEXT("GetLocaleInfo"), dwRes);
  741. return dwRes;
  742. }
  743. //
  744. // cut the string on the decimal separator
  745. //
  746. TCHAR* pSeparator = _tcsstr(tszNumber, tszDec);
  747. if(NULL != pSeparator)
  748. {
  749. *pSeparator = TEXT('\0');
  750. }
  751. try
  752. {
  753. TCHAR szFormat[64] = {0};
  754. #ifdef UNICODE
  755. if(theApp.IsRTLUI())
  756. {
  757. //
  758. // Size field always should be LTR
  759. // Add LEFT-TO-RIGHT OVERRIDE (LRO)
  760. //
  761. szFormat[0] = UNICODE_LRO;
  762. }
  763. #endif
  764. _tcscat(szFormat, TEXT("%s KB"));
  765. cstrValue.Format (szFormat, tszNumber);
  766. }
  767. catch(...)
  768. {
  769. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  770. CALL_FAIL (MEM_ERR, TEXT("CString::Format"), dwRes);
  771. return dwRes;
  772. }
  773. return dwRes;
  774. } // FaxSizeFormat
  775. DWORD
  776. HtmlHelpTopic(
  777. HWND hWnd,
  778. TCHAR* tszHelpTopic
  779. )
  780. /*++
  781. Routine name : HtmlHelpTopic
  782. Routine description:
  783. open HTML Help topic
  784. Author:
  785. Alexander Malysh (AlexMay), Mar, 2000
  786. Arguments:
  787. hWnd [in] - window handler
  788. tszHelpTopic [in] - help topic
  789. Return Value:
  790. Standard Win32 error code
  791. --*/
  792. {
  793. DWORD dwRes = ERROR_SUCCESS;
  794. DBG_ENTER(TEXT("HtmlHelpTopic"), dwRes);
  795. if(!tszHelpTopic)
  796. {
  797. ASSERTION_FAILURE;
  798. return ERROR_INVALID_PARAMETER;
  799. }
  800. //
  801. // get help file name
  802. //
  803. TCHAR tszHelpFile[2 * MAX_PATH] = {0};
  804. _sntprintf(tszHelpFile,
  805. ARR_SIZE(tszHelpFile) - 1,
  806. TEXT("%s.%s%s"),
  807. theApp.m_pszExeName, // application name (FxsClnt)
  808. FAX_HTML_HELP_EXT, // help file extension (CHM)
  809. tszHelpTopic); // help topic
  810. SetLastError(0);
  811. HtmlHelp(NULL, tszHelpFile, HH_DISPLAY_TOPIC, NULL);
  812. dwRes = GetLastError();
  813. if(ERROR_DLL_NOT_FOUND == dwRes ||
  814. ERROR_MOD_NOT_FOUND == dwRes ||
  815. ERROR_PROC_NOT_FOUND == dwRes)
  816. {
  817. AlignedAfxMessageBox(IDS_ERR_NO_HTML_HELP);
  818. }
  819. return dwRes;
  820. }
  821. DWORD
  822. GetAppLoadPath(
  823. CString& cstrLoadPath
  824. )
  825. /*++
  826. Routine name : GetAppLoadPath
  827. Routine description:
  828. The directory from which the application loaded
  829. Author:
  830. Alexander Malysh (AlexMay), Feb, 2000
  831. Arguments:
  832. cstrLoadPath [out] - the directory
  833. Return Value:
  834. Standard Win32 error code
  835. --*/
  836. {
  837. DWORD dwRes = ERROR_SUCCESS;
  838. DBG_ENTER(TEXT("GetAppLoadPath"), dwRes);
  839. TCHAR tszFullPath[MAX_PATH+1]={0};
  840. DWORD dwGetRes = GetModuleFileName(NULL, tszFullPath, ARR_SIZE(tszFullPath)-1);
  841. if(0 == dwGetRes)
  842. {
  843. dwRes = GetLastError();
  844. CALL_FAIL (FILE_ERR, TEXT("GetModuleFileName"), dwRes);
  845. return dwRes;
  846. }
  847. //
  848. // cut file name
  849. //
  850. TCHAR* ptchFile = _tcsrchr(tszFullPath, TEXT('\\'));
  851. ASSERTION(ptchFile);
  852. ptchFile = _tcsinc(ptchFile);
  853. *ptchFile = TEXT('\0');
  854. try
  855. {
  856. cstrLoadPath = tszFullPath;
  857. }
  858. catch(...)
  859. {
  860. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  861. CALL_FAIL (MEM_ERR, TEXT("CString::operator="), dwRes);
  862. return dwRes;
  863. }
  864. return dwRes;
  865. } // GetAppLoadPath
  866. DWORD
  867. GetPrintersInfo(
  868. PRINTER_INFO_2*& pPrinterInfo2,
  869. DWORD& dwNumPrinters
  870. )
  871. /*++
  872. Routine name : GetPrintersInfo
  873. Routine description:
  874. enumerate printers and get printers info
  875. Author:
  876. Alexander Malysh (AlexMay), Feb, 2000
  877. Arguments:
  878. pPrinterInfo2 [out] - printer info structure array
  879. dwNumPrinters [out] - number of printers
  880. Return Value:
  881. Standard Win32 error code
  882. --*/
  883. {
  884. DWORD dwRes = ERROR_SUCCESS;
  885. DBG_ENTER(TEXT("GetPrintersInfo"), dwRes);
  886. //
  887. // First call, just collect required sizes
  888. //
  889. DWORD dwRequiredSize;
  890. if (!EnumPrinters ( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
  891. NULL, // Local server
  892. 2, // Info level
  893. NULL, // Initial buffer
  894. 0, // Initial buffer size
  895. &dwRequiredSize,
  896. &dwNumPrinters))
  897. {
  898. DWORD dwEnumRes = GetLastError ();
  899. if (ERROR_INSUFFICIENT_BUFFER != dwEnumRes)
  900. {
  901. dwRes = dwEnumRes;
  902. CALL_FAIL (RESOURCE_ERR, TEXT("EnumPrinters"), dwRes);
  903. return dwRes;
  904. }
  905. }
  906. //
  907. // Allocate buffer for printers list
  908. //
  909. try
  910. {
  911. pPrinterInfo2 = (PRINTER_INFO_2 *) new BYTE[dwRequiredSize];
  912. }
  913. catch (...)
  914. {
  915. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  916. CALL_FAIL (MEM_ERR, TEXT("new BYTE[dwRequiredSize]"), dwRes);
  917. return dwRes;
  918. }
  919. //
  920. // 2nd call, get the printers list
  921. //
  922. if (!EnumPrinters ( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
  923. NULL, // Local server
  924. 2, // Info level
  925. (LPBYTE)pPrinterInfo2, // Buffer
  926. dwRequiredSize, // Buffer size
  927. &dwRequiredSize,
  928. &dwNumPrinters))
  929. {
  930. dwRes = GetLastError ();
  931. CALL_FAIL (RESOURCE_ERR, TEXT("EnumPrinters"), dwRes);
  932. SAFE_DELETE_ARRAY (pPrinterInfo2);
  933. return dwRes;
  934. }
  935. if (!dwNumPrinters)
  936. {
  937. VERBOSE(DBG_MSG, TEXT("No printers in this machine"));
  938. }
  939. return dwRes;
  940. } // GetPrintersInfo
  941. UINT_PTR
  942. CALLBACK
  943. OFNHookProc(
  944. HWND hdlg, // handle to child dialog box
  945. UINT uiMsg, // message identifier
  946. WPARAM wParam, // message parameter
  947. LPARAM lParam // message parameter
  948. )
  949. /*++
  950. Routine name : OFNHookProc
  951. Routine description:
  952. Callback function that is used with the
  953. Explorer-style Open and Save As dialog boxes.
  954. Refer MSDN for more info.
  955. --*/
  956. {
  957. UINT_PTR nRes = 0;
  958. if(WM_NOTIFY == uiMsg)
  959. {
  960. LPOFNOTIFY pOfNotify = (LPOFNOTIFY)lParam;
  961. if(CDN_FILEOK == pOfNotify->hdr.code)
  962. {
  963. if(_tcslen(pOfNotify->lpOFN->lpstrFile) > (MAX_PATH-10))
  964. {
  965. AlignedAfxMessageBox(IDS_SAVE_AS_TOO_LONG, MB_OK | MB_ICONEXCLAMATION);
  966. SetWindowLong(hdlg, DWLP_MSGRESULT, 1);
  967. nRes = 1;
  968. }
  969. }
  970. }
  971. return nRes;
  972. }
  973. int
  974. AlignedAfxMessageBox(
  975. LPCTSTR lpszText,
  976. UINT nType,
  977. UINT nIDHelp
  978. )
  979. /*++
  980. Routine name : AlignedAfxMessageBox
  981. Routine description:
  982. Display message box with correct reading order
  983. Arguments:
  984. AfxMessageBox() arguments
  985. Return Value:
  986. MessageBox() result
  987. --*/
  988. {
  989. if(IsRTLUILanguage())
  990. {
  991. nType |= MB_RTLREADING | MB_RIGHT;
  992. }
  993. return AfxMessageBox(lpszText, nType, nIDHelp);
  994. }
  995. int
  996. AlignedAfxMessageBox(
  997. UINT nIDPrompt,
  998. UINT nType,
  999. UINT nIDHelp
  1000. )
  1001. /*++
  1002. Routine name : AlignedAfxMessageBox
  1003. Routine description:
  1004. Display message box with correct reading order
  1005. Arguments:
  1006. AfxMessageBox() arguments
  1007. Return Value:
  1008. MessageBox() result
  1009. --*/
  1010. {
  1011. if(IsRTLUILanguage())
  1012. {
  1013. nType |= MB_RTLREADING | MB_RIGHT;
  1014. }
  1015. return AfxMessageBox(nIDPrompt, nType, nIDHelp);
  1016. }
  1017. HINSTANCE
  1018. GetResourceHandle()
  1019. {
  1020. return GetResInst(FAX_CONSOLE_RESOURCE_DLL, NULL);
  1021. }