/*++ Copyright (c) 1999 Microsoft Corporation Module Name: Utils.cpp Abstract: Provides utility functions for the entire poject Author: Eran Yariv (EranY) Dec, 1999 Revision History: --*/ #include "stdafx.h" #define __FILE_ID__ 10 #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern CClientConsoleApp theApp; DWORD LoadResourceString ( CString &cstr, int ResId ) /*++ Routine name : LoadResourceString Routine description: Loads a string from the resource Author: Eran Yariv (EranY), Jan, 2000 Arguments: cstr [out] - String buffer ResId [in ] - String resource id Return Value: Standard win32 error code --*/ { BOOL bRes; DWORD dwRes = ERROR_SUCCESS; try { bRes = cstr.LoadString (ResId); } catch (CMemoryException *pException) { DBG_ENTER(TEXT("LoadResourceString"), dwRes); TCHAR wszCause[1024]; pException->GetErrorMessage (wszCause, 1024); pException->Delete (); VERBOSE (EXCEPTION_ERR, TEXT("CString::LoadString caused exception : %s"), wszCause); dwRes = ERROR_NOT_ENOUGH_MEMORY; PopupError (dwRes); return dwRes; } if (!bRes) { dwRes = ERROR_NOT_FOUND; PopupError (dwRes); return dwRes; } return dwRes; } // LoadResourceString CString DWORDLONG2String ( DWORDLONG dwlData ) /*++ Routine name : DWORDLONG2String Routine description: Converts a 64-bit unsigned number to string Author: Eran Yariv (EranY), Jan, 2000 Arguments: dwlData [in] - Number to convert Return Value: Output string --*/ { CString cstrResult; cstrResult.Format (TEXT("0x%016I64x"), dwlData); return cstrResult; } // DWORDLONG2String CString DWORD2String ( DWORD dwData ) /*++ Routine name : DWORD2String Routine description: Converts a 32-bit unsigned number to string Author: Eran Yariv (EranY), Jan, 2000 Arguments: dwData [in] - Number to convert Return Value: Output string --*/ { CString cstrResult; cstrResult.Format (TEXT("%ld"), dwData); return cstrResult; } // DWORD2String DWORD Win32Error2String( DWORD dwWin32Err, CString& strError ) /*++ Routine name : Win32Error2String Routine description: Format a Win32 error code to a string Author: Eran Yariv (EranY), Jan, 2000 Arguments: dwWin32Err [in] - Win32 error code strError [out] - Result string Return Value: error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("Win32Error2String")); LPTSTR lpszError=NULL; // // Create descriptive error text // if (!FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwWin32Err, 0, (TCHAR *)&lpszError, 0, NULL)) { // // Failure to format the message // dwRes = GetLastError (); CALL_FAIL (RESOURCE_ERR, TEXT("FormatMessage"), dwRes); return dwRes; } try { strError = lpszError; } catch (...) { LocalFree (lpszError); return ERROR_NOT_ENOUGH_MEMORY; } LocalFree (lpszError); return dwRes; } // Win32Error2String DWORD LoadDIBImageList ( CImageList &iml, int iResourceId, DWORD dwImageWidth, COLORREF crMask ) /*++ Routine name : LoadDIBImageList Routine description: Loads an image list from the resource, retaining 24-bit colors Author: Eran Yariv (EranY), Jan, 2000 Arguments: iml [out] - Image list buffer iResourceId [in ] - Image list bitmap resource id dwImageWidth [in ] - Image width (pixels) crMask [in ] - Color key (transparent mask) Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("LoadDIBImageList"), dwRes); HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(iResourceId), RT_BITMAP); if (hInst) { HIMAGELIST hIml = ImageList_LoadImage ( hInst, MAKEINTRESOURCE(iResourceId), dwImageWidth, 0, crMask, IMAGE_BITMAP, LR_DEFAULTCOLOR); if (hIml) { if (!iml.Attach (hIml)) { dwRes = ERROR_GEN_FAILURE; CALL_FAIL (WINDOW_ERR, TEXT("CImageList::Attach"), dwRes); DeleteObject (hIml); } } else { // // ImageList_LoadImage() failed // dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, _T("ImageList_LoadImage"), dwRes); } } else { // // AfxFindResourceHandle() failed // dwRes = GetLastError(); CALL_FAIL (WINDOW_ERR, _T("AfxFindResourceHandle"), dwRes); } return dwRes; } // LoadDIBImageList #define BUILD_THREAD_DEATH_TIMEOUT INFINITE DWORD WaitForThreadDeathOrShutdown ( HANDLE hThread ) /*++ Routine name : WaitForThreadDeathOrShutdown Routine description: Waits for a thread to end. Also processes windows messages in the background. Stops waiting if the application is shutting down. Author: Eran Yariv (EranY), Jan, 2000 Arguments: hThread [in] - Handle to thread Return Value: Standard Win23 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("WaitForThreadDeathOrShutdown"), dwRes); for (;;) { // // We wait on the thread handle and the shutdown event (which ever comes first) // HANDLE hWaitHandles[2]; hWaitHandles[0] = hThread; hWaitHandles[1] = CClientConsoleDoc::GetShutdownEvent (); if (NULL == hWaitHandles[1]) { // // We're shutting down // return dwRes; } DWORD dwStart = GetTickCount (); VERBOSE (DBG_MSG, TEXT("Entering WaitForMultipleObjects (timeout = %ld)"), BUILD_THREAD_DEATH_TIMEOUT); // // Wait now.... // dwRes = MsgWaitForMultipleObjects( sizeof (hWaitHandles) / sizeof(hWaitHandles[0]), // Num of wait objects hWaitHandles, // Array of wait objects FALSE, // Wait for either one BUILD_THREAD_DEATH_TIMEOUT, // Timeout QS_ALLINPUT); // Accept messages DWORD dwRes2 = GetLastError(); VERBOSE (DBG_MSG, TEXT("Leaving WaitForMultipleObjects after waiting for %ld millisecs"), GetTickCount() - dwStart); switch (dwRes) { case WAIT_FAILED: dwRes = dwRes2; if (ERROR_INVALID_HANDLE == dwRes) { // // The thread is dead // VERBOSE (DBG_MSG, TEXT("Thread is dead (ERROR_INVALID_HANDLE)")); dwRes = ERROR_SUCCESS; } goto exit; case WAIT_OBJECT_0: // // The thread is not running // VERBOSE (DBG_MSG, TEXT("Thread is dead (WAIT_OBJECT_0)")); dwRes = ERROR_SUCCESS; goto exit; case WAIT_OBJECT_0 + 1: // // Shutdown is now in progress // VERBOSE (DBG_MSG, TEXT("Shutdown in progress")); dwRes = ERROR_SUCCESS; goto exit; case WAIT_OBJECT_0 + 2: // // System message (WM_xxx) in our queue // MSG msg; if (TRUE == ::GetMessage (&msg, NULL, NULL, NULL)) { VERBOSE (DBG_MSG, TEXT("System message (0x%x)- deferring to AfxWndProc"), msg.message); CMainFrame *pFrm = GetFrm(); if (!pFrm) { // // Shutdown in progress // goto exit; } if (msg.message != WM_KICKIDLE && !pFrm->PreTranslateMessage(&msg)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } else { // // Got WM_QUIT // AfxPostQuitMessage (0); dwRes = ERROR_SUCCESS; goto exit; } break; case WAIT_TIMEOUT: // // Thread won't die !!! // VERBOSE (DBG_MSG, TEXT("Wait timeout (%ld millisecs)"), BUILD_THREAD_DEATH_TIMEOUT); goto exit; default: // // What's this??? // VERBOSE (DBG_MSG, TEXT("Unknown error (%ld)"), dwRes); ASSERTION_FAILURE; goto exit; } } exit: return dwRes; } // WaitForThreadDeathOrShutdown DWORD GetUniqueFileName ( LPCTSTR lpctstrExt, CString &cstrResult ) /*++ Routine name : GetUniqueFileName Routine description: Generates a unique file name Author: Eran Yariv (EranY), Jan, 2000 Arguments: lpctstrExt [in] - File extension cstrResult [out] - Result file name Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("GetUniqueFileName"), dwRes); TCHAR szDir[MAX_PATH]; // // Get path to temp dir // if (!GetTempPath (MAX_PATH, szDir)) { dwRes = GetLastError (); CALL_FAIL (FILE_ERR, TEXT("GetTempPath"), dwRes); return dwRes; } // // Try out indices - start with a random index and advance (cyclic) by 1. // We're calling rand() 3 times here because we want to get a larger // range than 0..RAND_MAX (=32768) // DWORD dwStartIndex = DWORD((DWORDLONG)(rand()) * (DWORDLONG)(rand()) * (DWORDLONG)(rand()) ); for (DWORD dwIndex = dwStartIndex+1; dwIndex != dwStartIndex; dwIndex++) { try { cstrResult.Format (TEXT("%s%s%08x%08x.%s"), szDir, CONSOLE_PREVIEW_TIFF_PREFIX, GetCurrentProcessId(), dwIndex, lpctstrExt); } catch (CMemoryException *pException) { TCHAR wszCause[1024]; pException->GetErrorMessage (wszCause, 1024); pException->Delete (); VERBOSE (EXCEPTION_ERR, TEXT("CString::Format caused exception : %s"), wszCause); dwRes = ERROR_NOT_ENOUGH_MEMORY; return dwRes; } HANDLE hFile = CreateFile( cstrResult, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY, NULL); if (INVALID_HANDLE_VALUE == hFile) { dwRes = GetLastError (); if (ERROR_FILE_EXISTS == dwRes) { // // Try next index id // dwRes = ERROR_SUCCESS; continue; } CALL_FAIL (FILE_ERR, TEXT("CreateFile"), dwRes); return dwRes; } // // Success - close the file (leave it with size 0) // CloseHandle (hFile); return dwRes; } // // We just scanned 4GB file names and all were busy - impossible. // ASSERTION_FAILURE; dwRes = ERROR_GEN_FAILURE; return dwRes; } // GetUniqueFileName DWORD CopyTiffFromServer ( CServerNode *pServer, DWORDLONG dwlMsgId, FAX_ENUM_MESSAGE_FOLDER Folder, CString &cstrTiff ) /*++ Routine name : CopyTiffFromServer Routine description: Copies a TIFF file from the server's archive / queue Author: Eran Yariv (EranY), Jan, 2000 Arguments: pServer [in] - Pointer to the server node dwlMsgId [in] - Id of job / message Folder [in] - Folder of message / job cstrTiff [out] - Name of TIFF file that arrived from the server Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CopyTiffFromServer"), dwRes); // // Create a temporary file name for the TIFF // dwRes = GetUniqueFileName (FAX_TIF_FILE_EXT, cstrTiff); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("GetUniqueFileName"), dwRes); return dwRes; } HANDLE hFax; dwRes = pServer->GetConnectionHandle (hFax); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("CServerNode::GetConnectionHandle"), dwRes); goto exit; } { START_RPC_TIME(TEXT("FaxGetMessageTiff")); if (!FaxGetMessageTiff (hFax, dwlMsgId, Folder, cstrTiff)) { dwRes = GetLastError (); END_RPC_TIME(TEXT("FaxGetMessageTiff")); pServer->SetLastRPCError (dwRes); CALL_FAIL (RPC_ERR, TEXT("FaxGetMessageTiff"), dwRes); goto exit; } END_RPC_TIME(TEXT("FaxGetMessageTiff")); } ASSERTION (ERROR_SUCCESS == dwRes); exit: if (ERROR_SUCCESS != dwRes) { DeleteFile (cstrTiff); } return dwRes; } // CopyTiffFromServer DWORD GetDllVersion ( LPCTSTR lpszDllName ) /*++ Routine Description: Returns the version information for a DLL exporting "DllGetVersion". DllGetVersion is exported by the shell DLLs (specifically COMCTRL32.DLL). Arguments: lpszDllName - The name of the DLL to get version information from. Return Value: The version is retuned as DWORD where: HIWORD ( version DWORD ) = Major Version LOWORD ( version DWORD ) = Minor Version Use the macro PACKVERSION to comapre versions. If the DLL does not export "DllGetVersion" the function returns 0. --*/ { DWORD dwVersion = 0; DBG_ENTER(TEXT("GetDllVersion"), dwVersion, TEXT("%s"), lpszDllName); HINSTANCE hinstDll; hinstDll = LoadLibrary(lpszDllName); if(hinstDll) { DLLGETVERSIONPROC pDllGetVersion; pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hinstDll, "DllGetVersion"); // Because some DLLs may not implement this function, you // must test for it explicitly. Depending on the particular // DLL, the lack of a DllGetVersion function may // be a useful indicator of the version. if(pDllGetVersion) { DLLVERSIONINFO dvi; HRESULT hr; ZeroMemory(&dvi, sizeof(dvi)); dvi.cbSize = sizeof(dvi); hr = (*pDllGetVersion)(&dvi); if(SUCCEEDED(hr)) { dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion); } } FreeLibrary(hinstDll); } return dwVersion; } // GetDllVersion DWORD ReadRegistryString( LPCTSTR lpszSection, // in LPCTSTR lpszKey, // in CString& cstrValue // out ) /*++ Routine name : ReadRegistryString Routine description: read string from registry Author: Alexander Malysh (AlexMay), Feb, 2000 Arguments: lpszSection [in] - section lpszKey [in] - key out [out] - value Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("ReadRegistryString"), dwRes); HKEY hKey; dwRes = RegOpenKeyEx( HKEY_CURRENT_USER, lpszSection, 0, KEY_QUERY_VALUE, &hKey); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RegOpenKeyEx"), dwRes); return dwRes; } DWORD dwType; TCHAR tchData[1024]; DWORD dwDataSize = sizeof(tchData); dwRes = RegQueryValueEx( hKey, lpszKey, 0, &dwType, (BYTE*)tchData, &dwDataSize); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RegQueryValueEx"), dwRes); goto exit; } if(REG_SZ != dwType) { dwRes = ERROR_BADDB; goto exit; } try { cstrValue = tchData; } catch(...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("CString::operator="), dwRes); goto exit; } exit: dwRes = RegCloseKey( hKey ); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RegCloseKey"), dwRes); return dwRes; } return dwRes; } // ReadRegistryString DWORD WriteRegistryString( LPCTSTR lpszSection, // in LPCTSTR lpszKey, // in CString& cstrValue // in ) /*++ Routine name : WriteRegistryString Routine description: write string to the regostry Author: Alexander Malysh (AlexMay), Feb, 2000 Arguments: lpszSection [in] - section lpszKey [in] - key out [in] - value Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("WriteRegistryString"), dwRes); HKEY hKey; dwRes = RegOpenKeyEx( HKEY_CURRENT_USER, lpszSection, 0, KEY_SET_VALUE, &hKey); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RegOpenKeyEx"), dwRes); return dwRes; } LPCTSTR lpData = (LPCTSTR)cstrValue; dwRes = RegSetValueEx( hKey, lpszKey, 0, REG_SZ, (BYTE*)lpData, (1 + cstrValue.GetLength()) * sizeof (TCHAR)); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RegSetValueEx"), dwRes); goto exit; } exit: dwRes = RegCloseKey( hKey ); if(ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("RegCloseKey"), dwRes); return dwRes; } return dwRes; } // WriteRegistryString DWORD FaxSizeFormat( DWORDLONG dwlSize, // in CString& cstrValue // out ) /*++ Routine name : FaxSizeFormat Routine description: format string of file size Author: Alexander Malysh (AlexMay), Feb, 2000 Arguments: wdlSize [in] - size out [out] - formatted string Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("FaxSizeFormat"), dwRes); if(dwlSize > 0 && dwlSize < 1024) { dwlSize = 1; } else { dwlSize = dwlSize / (DWORDLONG)1024; } try { cstrValue.Format (TEXT("%I64d"), dwlSize); } catch(...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("CString::Format"), dwRes); return dwRes; } // // format the number // int nFormatRes; TCHAR tszNumber[100]; nFormatRes = GetNumberFormat(LOCALE_USER_DEFAULT, // locale 0, // options cstrValue, // input number string NULL, // formatting information tszNumber, // output buffer sizeof(tszNumber) / sizeof(tszNumber[0]) // size of output buffer ); if(0 == nFormatRes) { dwRes = GetLastError(); CALL_FAIL (GENERAL_ERR, TEXT("GetNumberFormat"), dwRes); return dwRes; } // // get decimal separator // TCHAR tszDec[10]; nFormatRes = GetLocaleInfo(LOCALE_USER_DEFAULT, // locale identifier LOCALE_SDECIMAL, // information type tszDec, // information buffer sizeof(tszDec) / sizeof(tszDec[0]) // size of buffer ); if(0 == nFormatRes) { dwRes = GetLastError(); CALL_FAIL (GENERAL_ERR, TEXT("GetLocaleInfo"), dwRes); return dwRes; } // // cut the string on the decimal separator // TCHAR* pSeparator = _tcsstr(tszNumber, tszDec); if(NULL != pSeparator) { *pSeparator = TEXT('\0'); } try { TCHAR szFormat[64] = {0}; #ifdef UNICODE if(theApp.IsRTLUI()) { // // Size field always should be LTR // Add LEFT-TO-RIGHT OVERRIDE (LRO) // szFormat[0] = UNICODE_LRO; } #endif _tcscat(szFormat, TEXT("%s KB")); cstrValue.Format (szFormat, tszNumber); } catch(...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("CString::Format"), dwRes); return dwRes; } return dwRes; } // FaxSizeFormat DWORD HtmlHelpTopic( HWND hWnd, TCHAR* tszHelpTopic ) /*++ Routine name : HtmlHelpTopic Routine description: open HTML Help topic Author: Alexander Malysh (AlexMay), Mar, 2000 Arguments: hWnd [in] - window handler tszHelpTopic [in] - help topic Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("HtmlHelpTopic"), dwRes); if(!tszHelpTopic) { ASSERTION_FAILURE; return ERROR_INVALID_PARAMETER; } // // get help file name // TCHAR tszHelpFile[2 * MAX_PATH] = {0}; _sntprintf(tszHelpFile, ARR_SIZE(tszHelpFile) - 1, TEXT("%s.%s%s"), theApp.m_pszExeName, // application name (FxsClnt) FAX_HTML_HELP_EXT, // help file extension (CHM) tszHelpTopic); // help topic SetLastError(0); HtmlHelp(NULL, tszHelpFile, HH_DISPLAY_TOPIC, NULL); dwRes = GetLastError(); if(ERROR_DLL_NOT_FOUND == dwRes || ERROR_MOD_NOT_FOUND == dwRes || ERROR_PROC_NOT_FOUND == dwRes) { AlignedAfxMessageBox(IDS_ERR_NO_HTML_HELP); } return dwRes; } DWORD GetAppLoadPath( CString& cstrLoadPath ) /*++ Routine name : GetAppLoadPath Routine description: The directory from which the application loaded Author: Alexander Malysh (AlexMay), Feb, 2000 Arguments: cstrLoadPath [out] - the directory Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("GetAppLoadPath"), dwRes); TCHAR tszFullPath[MAX_PATH+1]={0}; DWORD dwGetRes = GetModuleFileName(NULL, tszFullPath, ARR_SIZE(tszFullPath)-1); if(0 == dwGetRes) { dwRes = GetLastError(); CALL_FAIL (FILE_ERR, TEXT("GetModuleFileName"), dwRes); return dwRes; } // // cut file name // TCHAR* ptchFile = _tcsrchr(tszFullPath, TEXT('\\')); ASSERTION(ptchFile); ptchFile = _tcsinc(ptchFile); *ptchFile = TEXT('\0'); try { cstrLoadPath = tszFullPath; } catch(...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("CString::operator="), dwRes); return dwRes; } return dwRes; } // GetAppLoadPath DWORD GetPrintersInfo( PRINTER_INFO_2*& pPrinterInfo2, DWORD& dwNumPrinters ) /*++ Routine name : GetPrintersInfo Routine description: enumerate printers and get printers info Author: Alexander Malysh (AlexMay), Feb, 2000 Arguments: pPrinterInfo2 [out] - printer info structure array dwNumPrinters [out] - number of printers Return Value: Standard Win32 error code --*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("GetPrintersInfo"), dwRes); // // First call, just collect required sizes // DWORD dwRequiredSize; if (!EnumPrinters ( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, // Local server 2, // Info level NULL, // Initial buffer 0, // Initial buffer size &dwRequiredSize, &dwNumPrinters)) { DWORD dwEnumRes = GetLastError (); if (ERROR_INSUFFICIENT_BUFFER != dwEnumRes) { dwRes = dwEnumRes; CALL_FAIL (RESOURCE_ERR, TEXT("EnumPrinters"), dwRes); return dwRes; } } // // Allocate buffer for printers list // try { pPrinterInfo2 = (PRINTER_INFO_2 *) new BYTE[dwRequiredSize]; } catch (...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("new BYTE[dwRequiredSize]"), dwRes); return dwRes; } // // 2nd call, get the printers list // if (!EnumPrinters ( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, // Local server 2, // Info level (LPBYTE)pPrinterInfo2, // Buffer dwRequiredSize, // Buffer size &dwRequiredSize, &dwNumPrinters)) { dwRes = GetLastError (); CALL_FAIL (RESOURCE_ERR, TEXT("EnumPrinters"), dwRes); SAFE_DELETE_ARRAY (pPrinterInfo2); return dwRes; } if (!dwNumPrinters) { VERBOSE(DBG_MSG, TEXT("No printers in this machine")); } return dwRes; } // GetPrintersInfo UINT_PTR CALLBACK OFNHookProc( HWND hdlg, // handle to child dialog box UINT uiMsg, // message identifier WPARAM wParam, // message parameter LPARAM lParam // message parameter ) /*++ Routine name : OFNHookProc Routine description: Callback function that is used with the Explorer-style Open and Save As dialog boxes. Refer MSDN for more info. --*/ { UINT_PTR nRes = 0; if(WM_NOTIFY == uiMsg) { LPOFNOTIFY pOfNotify = (LPOFNOTIFY)lParam; if(CDN_FILEOK == pOfNotify->hdr.code) { if(_tcslen(pOfNotify->lpOFN->lpstrFile) > (MAX_PATH-10)) { AlignedAfxMessageBox(IDS_SAVE_AS_TOO_LONG, MB_OK | MB_ICONEXCLAMATION); SetWindowLong(hdlg, DWLP_MSGRESULT, 1); nRes = 1; } } } return nRes; } int AlignedAfxMessageBox( LPCTSTR lpszText, UINT nType, UINT nIDHelp ) /*++ Routine name : AlignedAfxMessageBox Routine description: Display message box with correct reading order Arguments: AfxMessageBox() arguments Return Value: MessageBox() result --*/ { if(IsRTLUILanguage()) { nType |= MB_RTLREADING | MB_RIGHT; } return AfxMessageBox(lpszText, nType, nIDHelp); } int AlignedAfxMessageBox( UINT nIDPrompt, UINT nType, UINT nIDHelp ) /*++ Routine name : AlignedAfxMessageBox Routine description: Display message box with correct reading order Arguments: AfxMessageBox() arguments Return Value: MessageBox() result --*/ { if(IsRTLUILanguage()) { nType |= MB_RTLREADING | MB_RIGHT; } return AfxMessageBox(nIDPrompt, nType, nIDHelp); } HINSTANCE GetResourceHandle() { return GetResInst(FAX_CONSOLE_RESOURCE_DLL, NULL); }