/*++ Copyright (c) 1990-1998, Microsoft Corporation All rights reserved. Module Name: dlgs.c Abstract: This module contains the common functions for the Win32 common dialogs. Revision History: --*/ // precompiled headers #include "precomp.h" #pragma hdrstop #include "util.h" // // Global Variables. // extern BOOL bInitializing; extern DWORD g_tlsiExtError; // // Function Prototypes. // LONG RgbInvertRgb( LONG rgbOld); const struct _ERRORMAP { DWORD dwCommDlgError; DWORD dwWin32Error; } ERRORMAP[] = { { CDERR_INITIALIZATION , ERROR_INVALID_PARAMETER}, { PDERR_INITFAILURE , ERROR_INVALID_PARAMETER}, { CDERR_STRUCTSIZE , ERROR_INVALID_PARAMETER}, { CDERR_NOTEMPLATE , ERROR_INVALID_PARAMETER}, { CDERR_NOHINSTANCE , ERROR_INVALID_PARAMETER}, { CDERR_NOHOOK , ERROR_INVALID_PARAMETER}, { CDERR_MEMALLOCFAILURE , ERROR_OUTOFMEMORY}, { CDERR_LOCKRESFAILURE , ERROR_INVALID_HANDLE}, { CDERR_DIALOGFAILURE , E_FAIL}, { PDERR_SETUPFAILURE , ERROR_INVALID_PARAMETER}, { PDERR_RETDEFFAILURE , ERROR_INVALID_PARAMETER}, { FNERR_BUFFERTOOSMALL , ERROR_INSUFFICIENT_BUFFER}, { FRERR_BUFFERLENGTHZERO, ERROR_INSUFFICIENT_BUFFER}, { FNERR_INVALIDFILENAME , ERROR_INVALID_NAME}, { PDERR_NODEFAULTPRN , E_FAIL}, { CFERR_NOFONTS , E_FAIL}, { CFERR_MAXLESSTHANMIN , ERROR_INVALID_PARAMETER}, }; //////////////////////////////////////////////////////////////////////////// // // StoreExtendedError // // Stores an extended error code for the next call to // CommDlgExtendedError. // //////////////////////////////////////////////////////////////////////////// void StoreExtendedError( DWORD dwError) { int i; for (i=0; i < ARRAYSIZE(ERRORMAP); i++) { if (ERRORMAP[i].dwCommDlgError == dwError) { SetLastError(ERRORMAP[i].dwWin32Error); break; } } TlsSetValue(g_tlsiExtError, UlongToPtr(dwError)); } //////////////////////////////////////////////////////////////////////////// // // GetStoredExtendedError // // Retieves the stored extended error code. // //////////////////////////////////////////////////////////////////////////// DWORD GetStoredExtendedError(void) { DWORD dwError; dwError = PtrToUlong(TlsGetValue(g_tlsiExtError)); return (dwError); } //////////////////////////////////////////////////////////////////////////// // // CommDlgExtendedError // // Provides additional information about dialog failure. // This should be called immediately after failure. // // Returns: LO word - error code // HI word - error specific info // //////////////////////////////////////////////////////////////////////////// DWORD WINAPI CommDlgExtendedError() { return (GetStoredExtendedError()); } //////////////////////////////////////////////////////////////////////////// // // HourGlass // // Turn hourglass on or off. // // bOn - specifies ON or OFF // //////////////////////////////////////////////////////////////////////////// VOID HourGlass( BOOL bOn) { // // Change cursor to hourglass. // if (!bInitializing) { if (!bMouse) { ShowCursor(bCursorLock = bOn); } SetCursor(LoadCursor(NULL, bOn ? IDC_WAIT : IDC_ARROW)); } } //////////////////////////////////////////////////////////////////////////// // // LoadAlterBitmap // // Loads a bitmap given its name and gives all the pixels that are // a certain color a new color. // // Returns: NULL - failed // handle to the bitmap loaded - success // //////////////////////////////////////////////////////////////////////////// HBITMAP WINAPI LoadAlterBitmap( int id, DWORD rgbReplace, DWORD rgbInstead) { LPBITMAPINFOHEADER qbihInfo; HDC hdcScreen; BOOL fFound; HANDLE hresLoad; HANDLE hres; LPLONG qlng; DWORD *qlngReplace; // points to bits that are replaced LPBYTE qbBits; HANDLE hbmp; LPBITMAPINFOHEADER lpBitmapInfo; UINT cbBitmapSize; hresLoad = FindResource(g_hinst, MAKEINTRESOURCE(id), RT_BITMAP); if (hresLoad == HNULL) { return (HNULL); } hres = LoadResource(g_hinst, hresLoad); if (hres == HNULL) { return (HNULL); } // // Lock the bitmap data and make a copy of it for the mask and the // bitmap. // cbBitmapSize = SizeofResource(g_hinst, hresLoad); lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hres); qbihInfo = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, cbBitmapSize); if ((lpBitmapInfo == NULL) || (qbihInfo == NULL)) { return (NULL); } memcpy((TCHAR *)qbihInfo, (TCHAR *)lpBitmapInfo, cbBitmapSize); // // Get a pointer into the color table of the bitmaps, cache the // number of bits per pixel. // rgbReplace = RgbInvertRgb(rgbReplace); rgbInstead = RgbInvertRgb(rgbInstead); qlng = (LPLONG)((LPSTR)(qbihInfo) + qbihInfo->biSize); fFound = FALSE; while (!fFound) { if (*qlng == (LONG)rgbReplace) { fFound = TRUE; qlngReplace = (DWORD *)qlng; *qlng = (LONG)rgbInstead; } qlng++; } // // First skip over the header structure. // qbBits = (LPBYTE)(qbihInfo + 1); // // Skip the color table entries, if any. // qbBits += (1 << (qbihInfo->biBitCount)) * sizeof(RGBQUAD); // // Create a color bitmap compatible with the display device. // hdcScreen = GetDC(HNULL); if (hdcScreen != HNULL) { hbmp = CreateDIBitmap( hdcScreen, qbihInfo, (LONG)CBM_INIT, qbBits, (LPBITMAPINFO)qbihInfo, DIB_RGB_COLORS ); ReleaseDC(HNULL, hdcScreen); } // // Reset color bits to original value. // *qlngReplace = (LONG)rgbReplace; LocalFree(qbihInfo); return (hbmp); } //////////////////////////////////////////////////////////////////////////// // // RgbInvertRgb // // Reverses the byte order of the RGB value (for file format). // // Returns the new color value (RGB to BGR). // //////////////////////////////////////////////////////////////////////////// LONG RgbInvertRgb( LONG rgbOld) { LONG lRet; BYTE R, G, B; R = GetRValue(rgbOld); G = GetGValue(rgbOld); B = GetBValue(rgbOld); lRet = (LONG)RGB(B, G, R); return (lRet); } //////////////////////////////////////////////////////////////////////////// // // HbmpLoadBmp // // Loads in a bitmap. // // Returns: Bitmap handle - success // HNULL - failure // //////////////////////////////////////////////////////////////////////////// #if 0 HBITMAP HbmpLoadBmp( WORD bmp) { HBITMAP hbmp; CHAR szBitmap[cbResNameMax]; hbmp = HNULL; if (LoadString(g_hinst, bmp, (LPTSTR)szBitmap, cbResNameMax - 1)) { hbmp = LoadBitmap(g_hinst, (LPCTSTR)szBitmap); } return (hbmp); } #endif //////////////////////////////////////////////////////////////////////////// // // AddNetButton // // Attempts to add a network button to the open, save, or print dialogs. // // hDlg - dialog to add button to // hInstance - instance handle for dlg // dyBottomMargin - DUs to bottom edge // //////////////////////////////////////////////////////////////////////////// #define xDUsToPels(DUs, lDlgBaseUnits) \ (int)(((DUs) * (int)LOWORD((lDlgBaseUnits))) / 4) #define yDUsToPels(DUs, lDlgBaseUnits) \ (int)(((DUs) * (int)HIWORD((lDlgBaseUnits))) / 8) VOID AddNetButton( HWND hDlg, HANDLE hInstance, int dyBottomMargin, BOOL bAddAccel, BOOL bTryLowerRight, BOOL bTryLowerLeft) { LONG lDlgBaseUnits; RECT rcDlg, rcCtrl, rcTmp; LONG xButton, yButton; LONG dxButton, dyButton; LONG dxDlgFrame, dyDlgFrame; LONG yDlgHeight, xDlgWidth; HWND hwndButton, hCtrl, hLastCtrl, hTmp, hSave; HFONT hFont; POINT ptTopLeft, ptTopRight, ptCenter, ptBtmLeft, ptBtmRight, ptTopLeftTmp; TCHAR szNetwork[MAX_PATH]; // // Make sure a network button (psh14) doesn't already exist in // the dialog. // if (GetDlgItem(hDlg, psh14)) { return; } // // Get dialog coordinate info. // lDlgBaseUnits = GetDialogBaseUnits(); dxDlgFrame = GetSystemMetrics(SM_CXDLGFRAME); dyDlgFrame = GetSystemMetrics(SM_CYDLGFRAME); GetWindowRect(hDlg, &rcDlg); rcDlg.left += dxDlgFrame; rcDlg.right -= dxDlgFrame; rcDlg.top += dyDlgFrame + GetSystemMetrics(SM_CYCAPTION); rcDlg.bottom -= dyDlgFrame; // // Get the OK button. // if (!(hCtrl = GetDlgItem(hDlg, IDOK))) { return; } GetWindowRect(hCtrl, &rcCtrl); ptTopLeft.x = rcCtrl.left; ptTopLeft.y = rcCtrl.top; // // Make sure the OK button isn't outside the dialog. // if (!PtInRect(&rcDlg, ptTopLeft)) { // // Try the CANCEL button. // if (!(hCtrl = GetDlgItem(hDlg, IDCANCEL))) { // // Both OK and CANCEL do not exist, so return. // return; } // // The check for the Cancel button outside the dialog is handled // below. // GetWindowRect(hCtrl, &rcCtrl); } hSave = hCtrl; #ifdef UNICODE // // Get the full hDlg value if coming from WOW. // if (IS_INTRESOURCE(hDlg)) { HWND hNewDlg = GetParent(hCtrl); if (hDlg == (HWND)LOWORD(hNewDlg)) { hDlg = hNewDlg; } } #endif // // Save the coordinate info of the button. // dxButton = rcCtrl.right - rcCtrl.left; dyButton = rcCtrl.bottom - rcCtrl.top; xButton = rcCtrl.left; yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits); yDlgHeight = rcDlg.bottom - yDUsToPels(dyBottomMargin, lDlgBaseUnits); // // Try to insert the network button in the lower right corner // of dialog box. // if (bTryLowerRight && (hTmp = GetDlgItem(hDlg, cmb2))) { // // See if the network button can be inserted in the // lower right corner of the dialog box. // hLastCtrl = hCtrl; GetWindowRect(hTmp, &rcTmp); yButton = rcTmp.top; // // Set the coordinates of the new button. // ptTopLeft.x = ptBtmLeft.x = xButton; ptTopLeft.y = ptTopRight.y = yButton; ptTopRight.x = ptBtmRight.x = xButton + dxButton; ptBtmLeft.y = ptBtmRight.y = yButton + dyButton; ptCenter.x = xButton + dxButton / 2; ptCenter.y = yButton + dyButton / 2; ScreenToClient(hDlg, (LPPOINT)&ptTopLeft); ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft); ScreenToClient(hDlg, (LPPOINT)&ptTopRight); ScreenToClient(hDlg, (LPPOINT)&ptBtmRight); ScreenToClient(hDlg, (LPPOINT)&ptCenter); // // See if the new button is over any other buttons. // if (((yButton + dyButton) < yDlgHeight) && ((ChildWindowFromPoint(hDlg, ptTopLeft) == hDlg) && (ChildWindowFromPoint(hDlg, ptTopRight) == hDlg) && (ChildWindowFromPoint(hDlg, ptCenter) == hDlg) && (ChildWindowFromPoint(hDlg, ptBtmLeft) == hDlg) && (ChildWindowFromPoint(hDlg, ptBtmRight) == hDlg))) { // // If the last control is the OK button and there is a // HELP button, then the last control should be the // HELP button. // if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) && (hCtrl = GetDlgItem(hDlg, pshHelp))) { GetWindowRect(hCtrl, &rcCtrl); ptTopLeftTmp.x = rcCtrl.left; ptTopLeftTmp.y = rcCtrl.top; // // Make sure the HELP button isn't outside the dialog // and then set the last control to be the HELP button. // if (PtInRect(&rcDlg, ptTopLeftTmp)) { hLastCtrl = hCtrl; } } // // If the last control is still the OK button and there is a // CANCEL button, then the last control should be the // CANCEL button. // if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) && (hCtrl = GetDlgItem(hDlg, IDCANCEL))) { GetWindowRect(hCtrl, &rcCtrl); ptTopLeftTmp.x = rcCtrl.left; ptTopLeftTmp.y = rcCtrl.top; // // Make sure the CANCEL button isn't outside the dialog // and then set the last control to be the CANCEL button. // if (PtInRect(&rcDlg, ptTopLeftTmp)) { hLastCtrl = hCtrl; } } goto FoundPlace; } // // Reset yButton. // yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits); } // // Try to insert the network button vertically below the other // control buttons. // while (hCtrl != NULL) { // // Move vertically down and see if there is space. // hLastCtrl = hCtrl; GetWindowRect(hCtrl, &rcCtrl); yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits); // // Make sure there is still room in the dialog. // if ((yButton + dyButton) > yDlgHeight) { // // No space. // break; } // // Set the coordinates of the new button. // ptTopLeft.x = ptBtmLeft.x = xButton; ptTopLeft.y = ptTopRight.y = yButton; ptTopRight.x = ptBtmRight.x = xButton + dxButton; ptBtmLeft.y = ptBtmRight.y = yButton + dyButton; ptCenter.x = xButton + dxButton / 2; ptCenter.y = yButton + dyButton / 2; ScreenToClient(hDlg, (LPPOINT)&ptTopLeft); ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft); ScreenToClient(hDlg, (LPPOINT)&ptTopRight); ScreenToClient(hDlg, (LPPOINT)&ptBtmRight); ScreenToClient(hDlg, (LPPOINT)&ptCenter); // // See if the new button is over any other buttons. // if (((hCtrl = ChildWindowFromPoint(hDlg, ptTopLeft)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptTopRight)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptCenter)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmLeft)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmRight)) == hDlg)) { goto FoundPlace; } } // // Try to insert the network button in the lower left corner of // the dialog box. // if (bTryLowerLeft) { // // Get the width of the dialog to make sure the button doesn't // go off the side of the dialog. // xDlgWidth = rcDlg.right - xDUsToPels(FILE_RIGHT_MARGIN, lDlgBaseUnits); // // Use the OK or CANCEL button saved earlier to get the size of // the buttons. // hCtrl = hSave; // // Start at the far left of the dialog. // // NOTE: We know that hCtrl is not NULL at this point because // otherwise we would have returned earlier. // // The print dialogs have a left margin of 8. // GetWindowRect(hCtrl, &rcCtrl); xButton = rcDlg.left + xDUsToPels(FILE_LEFT_MARGIN + 3, lDlgBaseUnits); yButton = rcCtrl.top; while (1) { hLastCtrl = hCtrl; // // Make sure there is still room in the dialog. // if ((xButton + dxButton) > xDlgWidth) { // // No space. // break; } // // Set the coordinates of the new button. // ptTopLeft.x = ptBtmLeft.x = xButton; ptTopLeft.y = ptTopRight.y = yButton; ptTopRight.x = ptBtmRight.x = xButton + dxButton; ptBtmLeft.y = ptBtmRight.y = yButton + dyButton; ptCenter.x = xButton + dxButton / 2; ptCenter.y = yButton + dyButton / 2; ScreenToClient(hDlg, (LPPOINT)&ptTopLeft); ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft); ScreenToClient(hDlg, (LPPOINT)&ptTopRight); ScreenToClient(hDlg, (LPPOINT)&ptBtmRight); ScreenToClient(hDlg, (LPPOINT)&ptCenter); // // See if the new button is over any other buttons. // if ( ( ((hCtrl = ChildWindowFromPoint(hDlg, ptTopLeft)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptTopRight)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptCenter)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmLeft)) == hDlg) && ((hCtrl = ChildWindowFromPoint(hDlg, ptBtmRight)) == hDlg) ) ) { // // If the last control is the OK button and there is a // HELP button, then the last control should be the // HELP button. // if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) && (hCtrl = GetDlgItem(hDlg, pshHelp))) { GetWindowRect(hCtrl, &rcCtrl); ptTopLeftTmp.x = rcCtrl.left; ptTopLeftTmp.y = rcCtrl.top; // // Make sure the HELP button isn't outside the dialog // and then set the last control to be the HELP button. // if (PtInRect(&rcDlg, ptTopLeftTmp)) { hLastCtrl = hCtrl; } } // // If the last control is still the OK button and there is a // CANCEL button, then the last control should be the // CANCEL button. // if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) && (hCtrl = GetDlgItem(hDlg, IDCANCEL))) { GetWindowRect(hCtrl, &rcCtrl); ptTopLeftTmp.x = rcCtrl.left; ptTopLeftTmp.y = rcCtrl.top; // // Make sure the CANCEL button isn't outside the dialog // and then set the last control to be the CANCEL button. // if (PtInRect(&rcDlg, ptTopLeftTmp)) { hLastCtrl = hCtrl; } } goto FoundPlace; } // // Make sure we encountered another control and that we // didn't go off the end of the dialog. // if (!hCtrl) { break; } // // Move over to the right and see if there is space. // GetWindowRect(hCtrl, &rcCtrl); xButton = rcCtrl.right + xDUsToPels(4, lDlgBaseUnits); } } return; FoundPlace: xButton = ptTopLeft.x; yButton = ptTopLeft.y; //If it a mirrored Dlg then the direction will be to the right. if (IS_WINDOW_RTL_MIRRORED(hDlg)) xButton -= dxButton; #ifndef UNICODE // // For non-localized apps that don't include the network button as part // of their template, don't add a Far East one because the characters // will not be displayed correctly. // { #define NetworkButtonText TEXT("Network...") #define NetworkButtonTextAccel TEXT("Net&work...") CPINFO cpinfo; if ((GetCPInfo(CP_ACP, &cpinfo)) && (cpinfo.MaxCharSize > 1)) { TEXTMETRIC tm; HFONT hPrevFont; HWND hIDOK = GetDlgItem(hDlg, IDOK); HDC hDC = GetDC(hIDOK); hFont = (HFONT)SendMessage(hIDOK, WM_GETFONT, 0, 0L); if (hFont != NULL) { hPrevFont = SelectObject(hDC, hFont); GetTextMetrics(hDC, &tm); SelectObject(hDC, hPrevFont); ReleaseDC(hIDOK, hDC); if (tm.tmCharSet == ANSI_CHARSET) { lstrcpy( szNetwork, bAddAccel ? NetworkButtonTextAccel : NetworkButtonText ); goto CreateNetworkButton; } } } } #endif if (CDLoadString( g_hinst, (bAddAccel ? iszNetworkButtonTextAccel : iszNetworkButtonText), (LPTSTR)szNetwork, MAX_PATH )) { #ifndef UNICODE CreateNetworkButton: #endif hwndButton = CreateWindow( TEXT("button"), szNetwork, WS_VISIBLE | WS_CHILD | WS_GROUP | WS_TABSTOP | BS_PUSHBUTTON, xButton, yButton, dxButton, dyButton, hDlg, NULL, hInstance, NULL ); if (hwndButton != NULL) { SetWindowLong(hwndButton, GWL_ID, psh14); SetWindowPos( hwndButton, hLastCtrl, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); hFont = (HFONT)SendDlgItemMessage(hDlg, IDOK, WM_GETFONT, 0, 0L); SendMessage(hwndButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE,0)); } } } //////////////////////////////////////////////////////////////////////////// // // IsNetworkInstalled // //////////////////////////////////////////////////////////////////////////// BOOL IsNetworkInstalled() { if (GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS) { return (TRUE); } else { return (FALSE); } } #ifdef WINNT //////////////////////////////////////////////////////////////////////////// // // Ssync_ANSI_UNICODE_Struct_For_WOW (This is exported for WOW) // // For WOW support on NT only. // // When a 16-bit app calls one of the comdlg API's, WOW thunks the 16-bit // comdlg struct passed by the app to a 32-bit ANSI struct. Comdlg32 code // then thunks the 32-bit ANSI struct into a UNICODE struct. This scheme // creates a problem for WOW apps because on Win3.1, the app and comdlg16 // share the same structure. When either updates the struct, the other is // aware of the change. // // This function allows us to sychronize the UNICODE struct with the app's // 16-bit struct & vice versa from WOW. // //////////////////////////////////////////////////////////////////////////// VOID Ssync_ANSI_UNICODE_Struct_For_WOW( HWND hDlg, BOOL fDirection, DWORD dwID) { switch (dwID) { case ( WOW_CHOOSECOLOR ) : { Ssync_ANSI_UNICODE_CC_For_WOW(hDlg, fDirection); break; } case ( WOW_CHOOSEFONT ) : { Ssync_ANSI_UNICODE_CF_For_WOW(hDlg, fDirection); break; } case ( WOW_OPENFILENAME ) : { Ssync_ANSI_UNICODE_OFN_For_WOW(hDlg, fDirection); break; } case ( WOW_PRINTDLG ) : { Ssync_ANSI_UNICODE_PD_For_WOW(hDlg, fDirection); break; } // case not needed for FINDREPLACE } } #endif #ifdef WX86 //////////////////////////////////////////////////////////////////////////// // // Wx86GetX86Callback // // Creates a RISC-callable alias for a x86 hook function pointer. // // lpfnHook - x86 address of hook // // Returns a function pointer which can be called from RISC. // //////////////////////////////////////////////////////////////////////////// PVOID Wx86GetX86Callback( PVOID lpfnHook) { if (!lpfnHook) { return (NULL); } if (!pfnAllocCallBx86) { HMODULE hMod; if (!Wx86CurrentTib()) { // // Wx86 is not running in this thread. Assume a RISC app has // passed a bad flag value and that lpfnHook is already a RISC // function pointer. // return (lpfnHook); } hMod = GetModuleHandle(TEXT("wx86.dll")); if (hMod == NULL) { // // Wx86 is running, but wx86.dll is not loaded! This should // never happen, but if it does, assume lpfnHook is already a // RISC pointer. // return (lpfnHook); } pfnAllocCallBx86 = (PALLOCCALLBX86)GetProcAddress( hMod, "AllocCallBx86" ); if (!pfnAllocCallBx86) { // // Something has gone terribly wrong! // return (lpfnHook); } } // // Call into Wx86.dll to create a RISC-to-x86 callback which takes // 4 parameters and has no logging. // return (*pfnAllocCallBx86)(lpfnHook, 4, NULL, NULL); } #endif //////////////////////////////////////////////////////////////////////////// // // CDLoadString // //////////////////////////////////////////////////////////////////////////// int CDLoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax) { return CDLoadStringEx(CP_ACP, hInstance, uID, lpBuffer, nBufferMax); } // CDLoadStringEx takes a codepage, so we can store unicode strings in the resource file int CDLoadStringEx(UINT cp, HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax) { HRSRC hResInfo; int cch = 0; LPWSTR lpwsz; LANGID LangID; if (!GET_BIDI_LOCALIZED_SYSTEM_LANGID(NULL)) { #ifdef WINNT return LoadString(hInstance, uID, lpBuffer, nBufferMax); #else lpwsz = (LPWSTR) LocalAlloc(NONZEROLPTR, nBufferMax * sizeof(WCHAR)); if (lpwsz) { int iRet; LoadStringWrapW(hInstance, uID, lpwsz, nBufferMax); iRet = WideCharToMultiByte(cp, 0, lpwsz, -1, lpBuffer, nBufferMax, NULL, NULL); LocalFree(lpwsz); return iRet; } return 0; #endif } LangID = (LANGID)TlsGetValue(g_tlsLangID); if (!LangID || MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) == LangID) { return LoadString(hInstance, uID, lpBuffer, nBufferMax); } if (!lpBuffer || (nBufferMax-- == 0)) return 0; // String Tables are broken up into 16 string resources. Find the resource // containing the string we are interested in. if (hResInfo = FindResourceExFallback(hInstance, RT_STRING, MAKEINTRESOURCE((uID>>4)+1), LangID)) { // Load the resource. Note LoadResource returns an address. if (lpwsz = (LPWSTR)LoadResource(hInstance, hResInfo)) { // Move past the other strings in this resource. // (16 strings in a segment -> & 0x0F) for (uID %= 16; uID; uID--) { lpwsz += *lpwsz + 1; } cch = min(*lpwsz, nBufferMax - 1); #ifdef UNICODE // Copy the string into the buffer; memcpy(lpBuffer, lpwsz+1, cch*sizeof(WCHAR)); #else // Copy the string into the buffer, converting to Ansi. cch= WideCharToMultiByte( CP_ACP, 0, lpwsz+1, cch, lpBuffer, cch, NULL, NULL); #endif } } lpBuffer[cch] = 0; return cch; } #define ENGLISH_APP 0 #define MIRRORED_APP 1 #define BIDI_APP 2 DWORD GetAppType(HWND hWnd) { DWORD dwExStyle = 0; HWND hWndT = hWnd; DWORD dwAppType = ENGLISH_APP; #ifdef CHECK_OWNER //Check the window and its owners. while (!dwExStyle && hWndT) { dwExStyle = GetWindowLongA(hWndT, GWL_EXSTYLE) & (WS_EX_RIGHT | WS_EX_RTLREADING | RTL_MIRRORED_WINDOW); hWndT = GetWindow(hWndT, GW_OWNER); } if (!dwExStyle) { #endif //If we still did not find then check the parents. hWndT = hWnd; while (!dwExStyle && hWndT) { dwExStyle = GetWindowLongA(hWndT, GWL_EXSTYLE) & (WS_EX_RIGHT | WS_EX_RTLREADING | RTL_MIRRORED_WINDOW); hWndT = GetParent(hWndT); } #ifdef CHECK_OWNER } #endif if (dwExStyle & RTL_MIRRORED_WINDOW) { dwAppType = MIRRORED_APP; } else if (dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING)) { dwAppType = BIDI_APP; } return dwAppType; } DWORD GetTemplateType(HANDLE hDlgTemplate) { DWORD dwExStyle = 0; DWORD dwAppType = ENGLISH_APP; LPDLGTEMPLATE pDlgTemplate; pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate); if (pDlgTemplate) { if (((LPDLGTEMPLATEEX) pDlgTemplate)->wSignature == 0xFFFF) { dwExStyle = ((LPDLGTEMPLATEEX) pDlgTemplate)->dwExStyle; } else { dwExStyle = pDlgTemplate->dwExtendedStyle; } } if (dwExStyle & RTL_MIRRORED_WINDOW) { dwAppType = MIRRORED_APP; } else if (dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING)) { dwAppType = BIDI_APP; } return dwAppType; } LANGID GetDialogLanguage(HWND hwndOwner, HANDLE hDlgTemplate) { LANGID LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); DWORD dwType; if (GET_BIDI_LOCALIZED_SYSTEM_LANGID(&LangID)) { if (hDlgTemplate == NULL) { dwType = GetAppType(hwndOwner); } else { dwType = GetTemplateType(hDlgTemplate); } switch (dwType) { case ENGLISH_APP : LangID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); break; case MIRRORED_APP: LangID = MAKELANGID(PRIMARYLANGID(LangID), SUBLANG_DEFAULT); break; case BIDI_APP : LangID = MAKELANGID(PRIMARYLANGID(LangID), SUBLANG_SYS_DEFAULT); break; } } return LangID; }