BOOL WINAPI IsCharUpperW( WCHAR wChar) { WORD ctype1info; if (GetStringTypeW(CT_CTYPE1, &wChar, 1, &ctype1info)) { if (ctype1info & C1_UPPER) { return TRUE; } else { return FALSE; } } /* * GetStringTypeW failed! The caller is not expecting * failure, IsCharLowerW does not have a failure indicator, so we * determine the case as best we can. */ RIPMSG1(RIP_WARNING, "IsCharUpper(L'\\x%.4lx') failed", wChar); if (IS_UNICODE_BLK1(wChar)) { return IsCharUpperA((CHAR)wChar); } else { return FALSE; } }
DWORD WINAPI CharLowerBuffW( LPWSTR pwsz, DWORD cwch) { int cwchT; DWORD i; if (cwch == 0) { return 0; } cwchT = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, pwsz, cwch, pwsz, cwch); if (cwchT != 0) { return cwchT; } /* * LCMapString failed! The caller is not expecting failure, * CharLowerBuffW does not have a failure indicator, so we * convert the buffer to lower case as best we can. */ RIPMSG1(RIP_WARNING, "CharLowerBuffW(%ls) failed", pwsz); for (i=0; i < cwch; i++) { if (IS_UNICODE_BLK1(pwsz[i]) && IsCharUpperA((char)pwsz[i])) { pwsz[i] += 'a'-'A'; } } return cwch; }
VOID SetDialogPointer(PWND pwnd, LONG_PTR lPtr) { if ((pwnd->cbwndExtra < DLGWINDOWEXTRA) || TestWF(pwnd, WFSERVERSIDEPROC) || (PpiCurrent() != GETPTI(pwnd)->ppi)) { RIPMSG1(RIP_WARNING, "SetDialogPointer: Unexpected pwnd:%#p", pwnd); return; } ((PDIALOG)pwnd)->pdlg = (PDLG)lPtr; if (lPtr == 0) { pwnd->fnid |= FNID_CLEANEDUP_BIT; ClrWF(pwnd, WFDIALOGWINDOW); } else { if (pwnd->fnid == 0) { pwnd->fnid = FNID_DIALOG; } SetWF(pwnd, WFDIALOGWINDOW); } }
LPWSTR WINAPI CharLowerW( LPWSTR pwsz) { /* * Early out for NULL string or '\0' */ if (pwsz == NULL) { return pwsz; } if (!IS_PTR(pwsz)) { if (!LCMapStringW( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, (LPWSTR)&pwsz, 1, (LPWSTR)&pwsz, 1 )) { /* * We don't expect LCMapString to fail! The caller is not expecting * failure, CharLowerW does not have a failure indicator, so we do * nothing. */ RIPMSG1(RIP_WARNING, "CharLowerW(%#p): LCMapString failed\n", pwsz); } return pwsz; } /* * pwsz is a null-terminated string */ CharLowerBuffW(pwsz, wcslen(pwsz)+1); return pwsz; }
/***************************************************************************\ * ConnectConv * * Description: * Work function for all Connect cases. * * Method: * * To reduce the number of windows we use and to simplify how client * windows handle multiple WM_DDE_ACK messages during initiation, a * single client window can handle many conversations, each with * a different server window. * * The client window is created and set to a initiation state via the * GWL_CONVSTATE window word. Initiates are then sent to enumerated server * window candidates. * The GWL_CONVSTATE value is used by the DDEML mother windows * to determine if only one or several ACKs are desired to minimize * unnessary message traffic. * * The client window GWL_CONVCONTEXT? window words are also used by * Event Windows to pass context information. * * Note that all client and server windows are children of the mother * window. This reduces the number of top level windows that * WM_DDE_INITIATES need to hit. * * Each WM_DDE_ACK that is received by a client window while in the * initiation state causes it to create a CL_CONV_INFO structure, * partially initialize it, and link it into its list of CL_CONV_INFO * structures. The head of the list is pointed to by the GWL_PCI * client window word. * * After each WM_DDE_INITIALIZE is sent, the GWL_PCI value is checked * to see if it exists and needs initialization to be completed. If * this is the case the init code knows that at least one ACK was * received in response to the WM_DDE_INITIALIZE send. The * initialization of each CL_CONV_INFO struct that needs it is then completed. * * Once the broadcasting of WM_DDE_INITIALIZE is done, the init code * then sets the GWL_CONVSTATE value in the client window to indicate that * initialization is complete. * * Returns: * The head pci to the client window or NULL if no connections made it. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ PCL_CONV_INFO ConnectConv( PCL_INSTANCE_INFO pcii, LATOM laService, LATOM laTopic, HWND hwndTarget, // 0 implies broadcast HWND hwndSkip, // 0 implies no skips - avoids self-connections. PCONVCONTEXT pCC, HCONVLIST hConvList, DWORD clst) { INIT_ENUM ie; PCL_CONV_INFO pci; PCONV_INFO pcoi; GATOM gaService, gaTopic; CheckDDECritIn; if (hwndTarget && hwndTarget == hwndSkip) { return(NULL); } LeaveDDECrit; CheckDDECritOut; if (pcii->flags & IIF_UNICODE) { ie.hwndClient = CreateWindowW((LPWSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTW]), L"", WS_CHILD, 0, 0, 0, 0, pcii->hwndMother, (HMENU)0, (HANDLE)0, (LPVOID)NULL); } else { ie.hwndClient = CreateWindowA((LPSTR)(gpsi->atomSysClass[ICLS_DDEMLCLIENTA]), "", WS_CHILD, 0, 0, 0, 0, pcii->hwndMother, (HMENU)0, (HANDLE)0, (LPVOID)NULL); } EnterDDECrit; if (ie.hwndClient == 0) { return (NULL); } if (pCC != NULL) { if (!NtUserDdeSetQualityOfService(ie.hwndClient, &(pCC->qos), NULL)) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); goto Error; } } /* * Note that a pci will be created and allocated for each ACK recieved. */ SetConvContext(ie.hwndClient, (LONG *)pCC); SetWindowLong(ie.hwndClient, GWL_CONVSTATE, clst); SetWindowLong(ie.hwndClient, GWL_SHINST, (LONG)pcii->hInstServer); SetWindowLong(ie.hwndClient, GWL_CHINST, (LONG)pcii->hInstClient); gaService = LocalToGlobalAtom(laService); gaTopic = LocalToGlobalAtom(laTopic); ie.lParam = MAKELONG(gaService, gaTopic); if (!hwndTarget) { ie.hwndSkip = hwndSkip; ie.laServiceRequested = laService; ie.laTopic = laTopic; ie.hConvList = hConvList; ie.clst = clst; } LeaveDDECrit; if (hwndTarget) { SendMessage(hwndTarget, WM_DDE_INITIATE, (DWORD)ie.hwndClient, ie.lParam); } else { /* * Send this message to the nddeagnt app first so it can start * the netdde services BEFORE we do an enumeration of windows. * This lets things work the first time. NetDDEAgent caches * service status so this is the fastest way to do this. */ HWND hwndAgent = FindWindowW(SZ_NDDEAGNT_CLASS, SZ_NDDEAGNT_TITLE); if (hwndAgent) { SendMessage(hwndAgent, WM_DDE_INITIATE, (WPARAM)ie.hwndClient, ie.lParam); } EnumWindows((WNDENUMPROC)InitiateEnumerationProc, (LONG)&ie); } EnterDDECrit; /* * hConvList may have been destroyed during the enumeration but we are * done with it now so no need to revalidate. */ #ifdef DEBUG { WCHAR sz[10]; if (gaService && GlobalGetAtomName(gaService, sz, 10) == 0) { RIPMSG1(RIP_ERROR, "Bad Service Atom after Initiate phase: %lX", (DWORD)gaService); } if (gaTopic && GlobalGetAtomName(gaTopic, sz, 10) == 0) { RIPMSG1(RIP_ERROR, "Bad Topic Atom after Initiate phase: %lX", (DWORD)gaTopic); } } #endif // DEBUG GlobalDeleteAtom(gaService); GlobalDeleteAtom(gaTopic); // // Get the first pci allocated when a WM_DDE_ACK was recieved. // pci = (PCL_CONV_INFO)GetWindowLong(ie.hwndClient, GWL_PCI); if (pci == NULL) { Error: LeaveDDECrit; NtUserDestroyWindow(ie.hwndClient); EnterDDECrit; return (NULL); } SetWindowLong(ie.hwndClient, GWL_CONVSTATE, CLST_CONNECTED); if (hwndTarget) { /* * If hwndTarget was NULL, the enumeration proc took care of this. */ pci->hwndReconnect = hwndTarget; UserAssert(pci->ci.next == NULL); pci->ci.laServiceRequested = laService; IncLocalAtomCount(laService); // pci copy } if (pcii->MonitorFlags & MF_CONV) { for (pcoi = (PCONV_INFO)pci; pcoi; pcoi = pcoi->next) { MONCONV(pcoi, TRUE); } } return (pci); }
WINUSERAPI HANDLE WINAPI SetSysColorsTemp( CONST COLORREF *lpRGBs, CONST HBRUSH *lpBrushes, UINT_PTR cBrushes) // Count of brushes or handle { UINT cbRGBSize; UINT i; UINT abElements[COLOR_MAX]; /* * See if we are resetting the colors back to a saved state */ if (lpRGBs == NULL) { /* * When restoring cBrushes is really a handle to the old global * handle. Make sure that is true. Also lpBrushes is unused */ UNREFERENCED_PARAMETER(lpBrushes); UserAssert(lpBrushes == NULL); UserAssert(cBrushes == (ULONG_PTR)gpOriginalRGBs); if (gpOriginalRGBs == NULL) { RIPMSG0(RIP_ERROR, "SetSysColorsTemp: Can not restore if not saved"); return NULL; } /* * reset the global Colors */ UserAssert((sizeof(abElements)/sizeof(abElements[0])) >= gcOriginalRGBs); for (i = 0; i < gcOriginalRGBs; i++) abElements[i] = i; NtUserSetSysColors(gcOriginalRGBs, abElements, gpOriginalRGBs, 0); UserLocalFree(gpOriginalRGBs); gpOriginalRGBs = NULL; gcOriginalRGBs = 0; return (HANDLE)TRUE; } /* * Make sure we aren't trying to set too many colors * If we allow more then COLOR_MAX change the abElements array */ if (cBrushes > COLOR_MAX) { RIPMSG1(RIP_ERROR, "SetSysColorsTemp: trying to set too many colors %lX", cBrushes); return NULL; } /* * If we have already a saved state then don't let them save it again */ if (gpOriginalRGBs != NULL) { RIPMSG0(RIP_ERROR, "SetSysColorsTemp: temp colors already set"); return NULL; } /* * If we are here then we must be setting the new temp colors * * First save the old colors */ cbRGBSize = sizeof(COLORREF) * (UINT)cBrushes; UserAssert(sizeof(COLORREF) == sizeof(int)); gpOriginalRGBs = UserLocalAlloc(HEAP_ZERO_MEMORY, cbRGBSize); if (gpOriginalRGBs == NULL) { RIPMSG0(RIP_WARNING, "SetSysColorsTemp: unable to alloc temp colors buffer"); } RtlCopyMemory(gpOriginalRGBs, gpsi->argbSystem, cbRGBSize); /* * Now set the new colors. */ UserAssert( (sizeof(abElements)/sizeof(abElements[0])) >= cBrushes); for (i = 0; i < cBrushes; i++) abElements[i] = i; NtUserSetSysColors((UINT)cBrushes, abElements, lpRGBs, 0); gcOriginalRGBs = (UINT)cBrushes; return gpOriginalRGBs; }
HWND WINAPI ImmCreateSoftKeyboard( UINT uType, HWND hOwner, int x, int y) { static BOOL fFirstSoftKeyboard = TRUE; PIMEDPI pImeDpi; DWORD fdwUICaps; int nWidth, nHeight; HKL hCurrentKL; UINT i; HWND hSKWnd; RECT rcWork; SIZE szWork; if (!uType) { return (HWND)NULL; } if (uType >= sizeof(SoftKeyboardClassName) / sizeof(LPWSTR)) { return (HWND)NULL; } hCurrentKL = GetKeyboardLayout(0); pImeDpi = ImmLockImeDpi(hCurrentKL); if (pImeDpi == NULL) { RIPMSG1(RIP_WARNING, "ImmCreateSoftKeyboard, pImeDpi = NULL (hkl = 0x%x).\n", hCurrentKL); return (HWND)NULL; } fdwUICaps = pImeDpi->ImeInfo.fdwUICaps; ImmUnlockImeDpi(pImeDpi); if (!(fdwUICaps & UI_CAP_SOFTKBD)) { return (HWND)NULL; } if (fFirstSoftKeyboard) { if (!GetNearestMonitorSize(hOwner, &rcWork)) { // failed return NULL; } for (i = 0; i < sizeof(guScanCode) / sizeof(UINT); i++) { guScanCode[i] = MapVirtualKey(i, 0); } // LATER: have to consider the dynamic resolution change szWork.cx = rcWork.right - rcWork.left; UserAssert(szWork.cx > UI_MARGIN * 2); szWork.cy = rcWork.bottom - rcWork.top; UserAssert(szWork.cy > UI_MARGIN * 2); gptRaiseEdge.x = GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CXBORDER); gptRaiseEdge.y = GetSystemMetrics(SM_CYEDGE) + GetSystemMetrics(SM_CYBORDER); fFirstSoftKeyboard = FALSE; } if (!RegisterSoftKeyboard(uType)) { return (HWND)NULL; } GetSoftKeyboardDimension(uType, &nWidth, &nHeight); // boundry check if (x < 0) { x = 0; } else if (x + nWidth > szWork.cx) { x = szWork.cx - nWidth; } if (y < 0) { y = 0; } else if (y + nHeight > szWork.cy) { y = szWork.cy - nHeight; } switch (uType) { case SOFTKEYBOARD_TYPE_T1: hSKWnd = CreateWindowEx(0, SoftKeyboardClassName[uType], (LPCWSTR)NULL, WS_POPUP|WS_DISABLED, x, y, nWidth, nHeight, (HWND)hOwner, (HMENU)NULL, ghInst, NULL); break; case SOFTKEYBOARD_TYPE_C1: hSKWnd = CreateWindowEx(WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME, SoftKeyboardClassName[uType], (LPCWSTR)NULL, WS_POPUP|WS_DISABLED|WS_BORDER, x, y, nWidth, nHeight, (HWND)hOwner, (HMENU)NULL, ghInst, NULL); break; default: return (HWND)NULL; } ShowWindow(hSKWnd, SW_HIDE); UpdateWindow(hSKWnd); return (hSKWnd); }
VOID vMoveFileFromSystemToFontsDir(WCHAR *pwcFile) { WCHAR awcTmpBuf[MAX_PATH]; WCHAR awcTmp[MAX_PATH]; FLONG fl; WCHAR *pwcTmp; #if DBG BOOL bOk; #endif if (bMakePathNameW(awcTmp, pwcFile,NULL, &fl)) { // If the font is in the system subdirectory we will just move it // to the fonts subdirectory. The path in the registry is relative // and we will leave it alone. if ( (fl & (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH)) == (FONT_IN_SYSTEM_DIR | FONT_RELATIVE_PATH) ) { // find the bare file part, this is what will be written // in the registry pwcTmp = &awcTmp[wcslen(awcTmp) - 1]; while ((pwcTmp >= awcTmp) && (*pwcTmp != L'\\') && (*pwcTmp != L':')) pwcTmp--; if (pwcTmp > awcTmp) pwcTmp++; // need to move the font to fonts dir, can reuse the // buffer on the stack to build the full destination path wcscpy(awcTmpBuf, gpwcFontsDir); lstrcatW(awcTmpBuf, L"\\"); lstrcatW(awcTmpBuf, pwcTmp); // note that MoveFile should succeed, for if there was // a font file of the same file name in %windir%\fonts dir // we would not have been in this code path. #if DBG bOk = #endif MoveFileW(awcTmp, awcTmpBuf); RIPMSG3(RIP_VERBOSE, "move %ws to %ws %s", awcTmp, awcTmpBuf, (bOk) ? "succeeded" : "failed"); } #if DBG else { RIPMSG2(RIP_WARNING, "File %ws not in system directory, fl = 0x%lx\n", awcTmp, fl); } #endif } #if DBG else { RIPMSG1(RIP_WARNING, "Could not locate %ws", pwcFile); } #endif }
VOID ImmPostMessages( HWND hWnd, HIMC hImc, INT iNum, PTRANSMSG pTransMsg) { INT i; BOOL fAnsiIME; PCLIENTIMC pClientImc; PTRANSMSG pTransMsgTemp, pTransMsgBuf = NULL; // // Check if the IME is unicode or not. // The message buffer contains unicode messages // if the IME is unicode. // pClientImc = ImmLockClientImc(hImc); if (pClientImc == NULL) { RIPMSG1(RIP_WARNING, "ImmPostMessages: Invalid hImc %lx.", hImc); return; } fAnsiIME = ! TestICF(pClientImc, IMCF_UNICODE); ImmUnlockClientImc(pClientImc); // // translate messages to 3.x format if the App's version is 3.x. // pTransMsgTemp = pTransMsg; if (GetClientInfo()->dwExpWinVer < VER40) { DWORD dwLangId = PRIMARYLANGID( LANGIDFROMLCID( GetSystemDefaultLCID())); if ( (dwLangId == LANG_KOREAN && TransGetLevel(hWnd) == 3) || dwLangId == LANG_JAPANESE ) { pTransMsgBuf = ImmLocalAlloc(0, iNum * sizeof(TRANSMSG)); if (pTransMsgBuf != NULL) { RtlCopyMemory(pTransMsgBuf, pTransMsg, iNum * sizeof(TRANSMSG)); iNum = WINNLSTranslateMessage(iNum, pTransMsgBuf, hImc, fAnsiIME, dwLangId ); pTransMsgTemp = pTransMsgBuf; } } } for (i = 0; i < iNum; i++) { if (fAnsiIME) { PostMessageA(hWnd, pTransMsgTemp->message, pTransMsgTemp->wParam, pTransMsgTemp->lParam); } else { PostMessageW(hWnd, pTransMsgTemp->message, pTransMsgTemp->wParam, pTransMsgTemp->lParam); } pTransMsgTemp++; } if (pTransMsgBuf != NULL) { ImmLocalFree(pTransMsgBuf); } }
/***************************************************************************\ * ImmTranslateMessage (Called from user\client\ntstubs.c\TranslateMessage()) * * Call ImeToAsciiEx() * * History: * 01-Mar-1996 TakaoK Created \***************************************************************************/ BOOL ImmTranslateMessage( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HIMC hImc; PINPUTCONTEXT pInputContext; BOOL fReturn = FALSE; HKL hkl; PIMEDPI pImeDpi = NULL; PBYTE pbKeyState; PTRANSMSG pTransMsg; PTRANSMSGLIST pTransMsgList; DWORD dwSize; UINT uVKey; INT iNum; UNREFERENCED_PARAMETER(wParam); // // we're interested in only those keyboard messages. // switch (message) { case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: break; default: return FALSE; } // // input context is necessary for further handling // hImc = ImmGetContext(hwnd); pInputContext = ImmLockIMC(hImc); if (pInputContext == NULL) { ImmReleaseContext(hwnd, hImc); return FALSE; } // // At first, handle VK_PROCESSKEY generated by IME. // if (!pInputContext->fChgMsg) { if ((iNum=pInputContext->dwNumMsgBuf) != 0) { pTransMsg = (PTRANSMSG)ImmLockIMCC(pInputContext->hMsgBuf); if (pTransMsg != NULL) { ImmPostMessages(hwnd, hImc, iNum, pTransMsg); ImmUnlockIMCC(pInputContext->hMsgBuf); fReturn = TRUE; } pInputContext->dwNumMsgBuf = 0; } goto ExitITM; } pInputContext->fChgMsg = FALSE; // // retrieve the keyboard layout and IME entry points // hkl = GetKeyboardLayout( GetWindowThreadProcessId(hwnd, NULL) ); pImeDpi = ImmLockImeDpi(hkl); if (pImeDpi == NULL) { RIPMSG1(RIP_WARNING, "ImmTranslateMessage pImeDpi is NULL(hkl=%x)", hkl); goto ExitITM; } pbKeyState = ImmLocalAlloc(0, 256); if ( pbKeyState == NULL ) { RIPMSG0(RIP_WARNING, "ImmTranslateMessage out of memory" ); goto ExitITM; } if (!GetKeyboardState(pbKeyState)) { RIPMSG0(RIP_WARNING, "ImmTranslateMessage GetKeyboardState() failed" ); ImmLocalFree( pbKeyState ); goto ExitITM; } // // Translate the saved vkey into character code if needed // uVKey = pInputContext->uSavedVKey; if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) { WCHAR wcTemp; iNum = ToUnicode(pInputContext->uSavedVKey, // virtual-key code HIWORD(lParam), // scan code pbKeyState, // key-state array &wcTemp, // buffer for translated key 1, // size of buffer 0); if (iNum == 1) { // // hi word : unicode character code // hi byte of lo word : zero // lo byte of lo word : virtual key // uVKey = (uVKey & 0x00ff) | ((UINT)wcTemp << 16); } } else { WORD wTemp = 0; iNum = ToAsciiEx(pInputContext->uSavedVKey, // virtual-key code HIWORD(lParam), // scan code pbKeyState, // key-state array &wTemp, // buffer for translated key 0, // active-menu flag hkl); ImmAssert(iNum <= 2); if (iNum > 0) { // // hi word : should be zero // hi byte of lo word : character code // lo byte of lo word : virtual key // uVKey = (uVKey & 0x00FF) | ((UINT)wTemp << 8); if ((BYTE)uVKey == VK_PACKET) { // // If ANSI IME is wide vkey aware, its ImeToAsciiEx will receive the uVKey // as follows: // // 31 24 23 16 15 8 7 0 // +----------------+-----------------------------+-------------------+---------------+ // | 24~31:reserved | 16~23:trailing byte(if any) | 8~15:leading byte | 0~7:VK_PACKET | // +----------------+-----------------------------+-------------------+---------------+ // ImmAssert(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY); } else { uVKey &= 0xffff; } } } } dwSize = FIELD_OFFSET(TRANSMSGLIST, TransMsg) + TRANSMSGCOUNT * sizeof(TRANSMSG); pTransMsgList = (PTRANSMSGLIST)ImmLocalAlloc(0, dwSize); if (pTransMsgList == NULL) { RIPMSG0(RIP_WARNING, "ImmTranslateMessage out of memory" ); ImmLocalFree(pbKeyState); goto ExitITM; } pTransMsgList->uMsgCount = TRANSMSGCOUNT; iNum = (*pImeDpi->pfn.ImeToAsciiEx)(uVKey, HIWORD(lParam), pbKeyState, pTransMsgList, 0, hImc); if (iNum > TRANSMSGCOUNT) { // // The message buffer is not big enough. IME put messages // into hMsgBuf in the input context. // pTransMsg = (PTRANSMSG)ImmLockIMCC(pInputContext->hMsgBuf); if (pTransMsg != NULL) { ImmPostMessages(hwnd, hImc, iNum, pTransMsg); ImmUnlockIMCC(pInputContext->hMsgBuf); } #ifdef LATER // Shouldn't we need this ? fReturn = TRUE; #endif } else if (iNum > 0) { ImmPostMessages(hwnd, hImc, iNum, &pTransMsgList->TransMsg[0]); fReturn = TRUE; } ImmLocalFree(pbKeyState); ImmLocalFree(pTransMsgList); ExitITM: ImmUnlockImeDpi(pImeDpi); ImmUnlockIMC(hImc); ImmReleaseContext(hwnd, hImc); return fReturn; }
BOOL LoadIME( PIMEINFOEX piiex, PIMEDPI pImeDpi) { WCHAR wszImeFile[MAX_PATH]; BOOL fSuccess; UINT i; i = GetSystemDirectoryW(wszImeFile, MAX_PATH); wszImeFile[i] = L'\0'; AddBackslash(wszImeFile); wcscat(wszImeFile, piiex->wszImeFile); pImeDpi->hInst = LoadLibraryW(wszImeFile); if (!pImeDpi->hInst) { RIPMSG1(RIP_WARNING, "LoadIME: LoadLibraryW(%ws) failed", wszImeFile); goto LoadIME_ErrOut; } #define GET_IMEPROCT(x) \ if (!(pImeDpi->pfn.##x.t = (PVOID) GetProcAddress(pImeDpi->hInst, #x))) { \ RIPMSG1(RIP_WARNING, "LoadIME: " #x " not supported in %ws", wszImeFile); \ goto LoadIME_ErrOut; } #define GET_IMEPROC(x) \ if (!(pImeDpi->pfn.##x = (PVOID) GetProcAddress(pImeDpi->hInst, #x))) { \ RIPMSG1(RIP_WARNING, "LoadIME: " #x " not supported in %ws", wszImeFile); \ goto LoadIME_ErrOut; } GET_IMEPROCT(ImeInquire); GET_IMEPROCT(ImeConversionList); GET_IMEPROCT(ImeRegisterWord); GET_IMEPROCT(ImeUnregisterWord); GET_IMEPROCT(ImeGetRegisterWordStyle); GET_IMEPROCT(ImeEnumRegisterWord); GET_IMEPROC (ImeConfigure); GET_IMEPROC (ImeDestroy); GET_IMEPROC (ImeEscape); GET_IMEPROC (ImeProcessKey); GET_IMEPROC (ImeSelect); GET_IMEPROC (ImeSetActiveContext); GET_IMEPROC (ImeToAsciiEx); GET_IMEPROC (NotifyIME); GET_IMEPROC (ImeSetCompositionString); #undef GET_IMEPROCT #undef GET_IMEPROC if (!InquireIme(pImeDpi)) { RIPMSG0(RIP_WARNING, "LoadIME: InquireIme failed"); LoadIME_ErrOut: FreeLibrary(pImeDpi->hInst); pImeDpi->hInst = NULL; fSuccess = FALSE; } else { fSuccess = TRUE; } /* * Update kernel side IMEINFOEX for this keyboard layout if * this is its first loading. */ if (piiex->fLoadFlag == IMEF_NONLOAD) { if (fSuccess) { RtlCopyMemory((PBYTE)&piiex->ImeInfo, (PBYTE)&pImeDpi->ImeInfo, sizeof(IMEINFO)); RtlCopyMemory((PBYTE)piiex->wszUIClass, (PBYTE)pImeDpi->wszUIClass, sizeof(pImeDpi->wszUIClass)); piiex->fLoadFlag = IMEF_LOADED; } else { piiex->fLoadFlag = IMEF_LOADERROR; } NtUserSetImeInfoEx(piiex); } return fSuccess; }
BOOL WINAPI ImmConfigureIMEW( HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) { PWND pWnd; PIMEDPI pImeDpi; BOOL fRet = FALSE; if ((pWnd = ValidateHwnd(hWnd)) == (PWND)NULL) { RIPMSG1(RIP_WARNING, "ImmConfigureIMEA: invalid window handle %x", hWnd); return FALSE; } if (!TestWindowProcess(pWnd)) { RIPMSG1(RIP_WARNING, "ImmConfigureIMEA: hWnd=%lx belongs to different process!", hWnd); return FALSE; } pImeDpi = FindOrLoadImeDpi(hKL); if (pImeDpi == NULL) { RIPMSG0(RIP_WARNING, "ImmConfigureIMEA: no pImeDpi entry."); return FALSE; } if ((pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) || lpData == NULL) { /* * Doesn't need A/W conversion. Calls directly to IME to * bring up the configuration dialogbox. */ fRet = (*pImeDpi->pfn.ImeConfigure)(hKL, hWnd, dwMode, lpData); ImmUnlockImeDpi(pImeDpi); return fRet; } /* * Unicode caller, ANSI IME. Needs A/W conversion on lpData when * dwMode == IME_CONFIG_REGISTERWORD. In this case, lpData points * to a structure of REGISTERWORDW. */ switch (dwMode) { case IME_CONFIG_REGISTERWORD: { LPREGISTERWORDW lpRegisterWordW; REGISTERWORDA RegisterWordA; LPVOID lpBuffer; ULONG cbBuffer; BOOL bUDC; INT i; lpRegisterWordW = (LPREGISTERWORDW)lpData; cbBuffer = 0; lpBuffer = NULL; if (lpRegisterWordW->lpReading != NULL) cbBuffer += wcslen(lpRegisterWordW->lpReading) + 1; if (lpRegisterWordW->lpWord != NULL) cbBuffer += wcslen(lpRegisterWordW->lpWord) + 1; if (cbBuffer != 0) { cbBuffer *= sizeof(WCHAR); if ((lpBuffer = ImmLocalAlloc(0, cbBuffer)) == NULL) { RIPMSG0(RIP_WARNING, "ImmConfigureIMEW: memory failure."); break; } } if (lpRegisterWordW->lpReading != NULL) { RegisterWordA.lpReading = lpBuffer; i = WideCharToMultiByte( CP_ACP, (DWORD)0, (LPWSTR)lpRegisterWordW->lpReading, (INT)wcslen(lpRegisterWordW->lpReading), (LPSTR)RegisterWordA.lpReading, (INT)cbBuffer, (LPSTR)NULL, (LPBOOL)&bUDC); RegisterWordA.lpReading[i] = '\0'; cbBuffer -= (i * sizeof(CHAR)); } else { RegisterWordA.lpReading = NULL; } if (lpRegisterWordW->lpWord != NULL) { if (RegisterWordA.lpReading != NULL) RegisterWordA.lpWord = &RegisterWordA.lpReading[i+1]; else RegisterWordA.lpWord = lpBuffer; i = WideCharToMultiByte( CP_ACP, (DWORD)0, (LPWSTR)lpRegisterWordW->lpWord, (INT)wcslen(lpRegisterWordW->lpWord), (LPSTR)RegisterWordA.lpWord, (INT)cbBuffer, (LPSTR)NULL, (LPBOOL)&bUDC); RegisterWordA.lpWord[i] = '\0'; } else RegisterWordA.lpWord = NULL; fRet = ImmConfigureIMEA(hKL, hWnd, dwMode, &RegisterWordA); if (lpBuffer != NULL) ImmLocalFree(lpBuffer); break; } default: fRet = ImmConfigureIMEA(hKL, hWnd, dwMode, lpData); break; } ImmUnlockImeDpi(pImeDpi); return fRet; }
PIMEDPI FindOrLoadImeDpi( HKL hKL) { PIMEDPI pImeDpi, pTmpImeDpi; IMEINFOEX iiex; /* * Non IME based keyboard layout doesn't have IMEDPI. */ if (!IS_IME_KBDLAYOUT(hKL)) return (PIMEDPI)NULL; pImeDpi = ImmLockImeDpi(hKL); if (pImeDpi == NULL) { /* * This process hasn't load up the specified IME based layout. * Query the IME information and load it up now. */ if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL)) { RIPMSG1(RIP_WARNING, "FindOrLoadImeDpi: ImmGetImeInfoEx(%lx) failed", hKL); return NULL; } /* * Win95 behaviour: If there was an IME load error for this layout, * further attempt to load the same IME layout will be rejected. */ if (iiex.fLoadFlag == IMEF_LOADERROR) return NULL; /* * Allocate a new IMEDPI for this layout. */ pImeDpi = (PIMEDPI)ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI)); if (pImeDpi == NULL) return NULL; if (!LoadIME(&iiex, pImeDpi)) { LocalFree(pImeDpi); return NULL; } pImeDpi->hKL = hKL; pImeDpi->cLock++; /* * Link in the newly allocated entry. */ RtlEnterCriticalSection(&gcsImeDpi); /* * Serach the gpImeDpi list again and discard this * pImeDpi if other thread has updated the list for * the same layout while we leave the critical section. */ pTmpImeDpi = ImmLockImeDpi(hKL); if (pTmpImeDpi == NULL) { /* * Update the global list for this new pImeDpi entry. */ pImeDpi->pNext = gpImeDpi; gpImeDpi = pImeDpi; RtlLeaveCriticalSection(&gcsImeDpi); } else { /* * The same IME has been loaded, discard this extra entry. */ RtlLeaveCriticalSection(&gcsImeDpi); UnloadIME(pImeDpi, FALSE); ImmLocalFree(pImeDpi); pImeDpi = pTmpImeDpi; } } return pImeDpi; }
BOOL InquireIme( PIMEDPI pImeDpi) { WNDCLASS wc; WCHAR wszClassName[IM_UI_CLASS_SIZE]; PIMEINFO pImeInfo = &pImeDpi->ImeInfo; (*pImeDpi->pfn.ImeInquire.w)(pImeInfo, (PVOID)wszClassName, NULL); /* * parameter checking for each fields. */ if (pImeInfo->dwPrivateDataSize == 0) pImeInfo->dwPrivateDataSize = sizeof(UINT); if (pImeInfo->fdwProperty & ~(IME_PROP_ALL)) { RIPMSG0(RIP_WARNING, "wrong property"); return FALSE; } if (pImeInfo->fdwConversionCaps & ~(IME_CMODE_ALL)) { RIPMSG0(RIP_WARNING, "wrong conversion capabilities"); return FALSE; } if (pImeInfo->fdwSentenceCaps & ~(IME_SMODE_ALL)) { RIPMSG0(RIP_WARNING, "wrong sentence capabilities"); return FALSE; } if (pImeInfo->fdwUICaps & ~(UI_CAP_ALL)) { RIPMSG0(RIP_WARNING, "wrong UI capabilities"); return FALSE; } if (pImeInfo->fdwSCSCaps & ~(SCS_CAP_ALL)) { RIPMSG0(RIP_WARNING, "wrong set comp string capabilities"); return FALSE; } if (pImeInfo->fdwSelectCaps & ~(SELECT_CAP_ALL)) { RIPMSG0(RIP_WARNING, "wrong select capabilities"); return FALSE; } if (!(pImeInfo->fdwProperty & IME_PROP_UNICODE)) { ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; RtlInitAnsiString(&AnsiString, (LPSTR)wszClassName); UnicodeString.MaximumLength = (SHORT)sizeof(pImeDpi->wszUIClass); UnicodeString.Buffer = pImeDpi->wszUIClass; if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE))) { return FALSE; } } else { RtlCopyMemory(pImeDpi->wszUIClass, wszClassName, sizeof(wszClassName)); pImeDpi->wszUIClass[IM_UI_CLASS_SIZE-1] = L'\0'; } if (!GetClassInfoW((HINSTANCE)pImeDpi->hInst, pImeDpi->wszUIClass, &wc)) { RIPMSG1(RIP_WARNING, "UI class (%ws) not found in this IME", pImeDpi->wszUIClass); return FALSE; } else if (wc.cbWndExtra < sizeof(DWORD) * 2) { RIPMSG0(RIP_WARNING, "UI class cbWndExtra problem"); return FALSE; } return TRUE; }
void xxxTrackMouseMove(PWND pwnd, int htEx, UINT message) { BOOL fNewpwndTrack; DWORD dwDTCancel = 0; TL tlpwnd; LPWSTR pstr; PDESKTOP pdesk = PtiCurrent()->rpdesk; PTHREADINFO ptiTrack; #if DBG /* * Let's warn if this function gets reenterd so we can make sure * nothing bad will follow. This should be a rare situation. * Look in gptiReEntered to find out who is already here. */ static UINT gcReEntered = 0; static PTHREADINFO gptiReEntered; if(gcReEntered++ != 0){ RIPMSG2(RIP_WARNING, "Reentered xxxTrackMouseMove; previous thread was %#p, current thread is %#p", gptiReEntered, PtiCurrent()); } gptiReEntered = PtiCurrent(); CheckLock(pwnd); /* * We must be on an interactive window station. */ if (pdesk->rpwinstaParent != NULL && pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO) { RIPMSG0(RIP_ERROR, "Can't use tooltips on non-interactive winsta"); } { static POINT pt = {0, 0}; #ifdef UNDONE /* * We might have taken a guess on the hit test (see FindNCHitEx) * so if we're at the same point and same window, something * might be fishy */ if ((pt.x == gpsi->ptCursor.x) && (pt.y == gpsi->ptCursor.y) && (pdesk->spwndTrack == pwnd)) { RIPMSG1(RIP_WARNING, "xxxTrackMouseMove: Same point & window. %#p", pwnd); } #endif /* * Something is supposed to have changed or we're wasting time */ UserAssert((pt.x != gpsi->ptCursor.x) || (pt.y != gpsi->ptCursor.y) || (pdesk->spwndTrack != pwnd) || (pdesk->htEx != htEx) || (message != WM_MOUSEMOVE)); /* * Remember last tracked point */ pt = gpsi->ptCursor; } /* * pwnd is supposed to be on the current thread and queue */ UserAssert(PtiCurrent() == GETPTI(pwnd)); UserAssert(PtiCurrent()->pq == GETPTI(pwnd)->pq); #endif /* * Have we switched windows? */ fNewpwndTrack = (pdesk->spwndTrack != pwnd); /* * If no tracking is taking place, just go set the new * tracking state */ if (!(pdesk->dwDTFlags & DF_MOUSEMOVETRK)) { goto SetNewState; } /* * Potentially while we leave the critical section below in * xxxCancelMouseMoveTracking, spwndTrack could be destroyed and unlocked * and then we go and create the tooltip. This would mean that * DF_TOOLTIPACTIVE (part of DF_MOUSEMOVETRK test above) would be set, * but pdesk->spwndTrack would be NULL and we can AV dereferencing * pdesk->spwndTrack below. Prevent this by making the check here. */ if (pdesk->spwndTrack == NULL) { goto SetNewState; } /* * Nuke hottracking and deactivate tooltip state, if any. * Do it sychronously if we're tracking on the current queue; * Otherwise, post an event and let it happen later. */ ptiTrack = GETPTI(pdesk->spwndTrack); if (PtiCurrent()->pq == ptiTrack->pq) { dwDTCancel |= DF_HOTTRACKING; } else if (pdesk->dwDTFlags & (DF_HOTTRACKING | DF_TOOLTIPACTIVE)) { PostEventMessage(ptiTrack, ptiTrack->pq, QEVENT_CANCELMOUSEMOVETRK, pdesk->spwndTrack, pdesk->dwDTFlags, pdesk->htEx, DF_HOTTRACKING); /* * Paranoid assertion. If we're switching queues, we must * be switching windows. Did we just go through * ReattachThreads? */ UserAssert(pwnd != pdesk->spwndTrack); pdesk->dwDTFlags &= ~(DF_HOTTRACKING | DF_TOOLTIPACTIVE); } /* * If we're on the client area or the user clicked, * nuke the tooltip (if any). * Since we might want to re-show the tooltip, we don't nuke it * now if we swichted windows (we'll nuke it later if needed) */ if ((htEx == HTCLIENT) || (message != WM_MOUSEMOVE)) { dwDTCancel |= DF_TOOLTIPACTIVE; } /* * If we switched windows or crossed client/nonclinet boundaries, * end track mouse leave/hover. */ if (fNewpwndTrack || ((pdesk->htEx == HTCLIENT) ^ (htEx == HTCLIENT))) { dwDTCancel |= DF_TRACKMOUSEEVENT; } /* * Cancel whatever is active and needs to go away */ ThreadLockAlways(pdesk->spwndTrack, &tlpwnd); xxxCancelMouseMoveTracking(pdesk->dwDTFlags, pdesk->spwndTrack, pdesk->htEx, dwDTCancel); ThreadUnlock(&tlpwnd); pdesk->dwDTFlags &= ~dwDTCancel; SetNewState: /* * Hottracking/tooltip on mouse move if on NC hitest and enabled */ if ((htEx != HTCLIENT) && (message == WM_MOUSEMOVE) && TestEffectUP(HOTTRACKING)) { /* * Hottrack the new hit test area */ if (xxxHotTrack(pwnd, htEx, TRUE)) { pdesk->dwDTFlags |= DF_HOTTRACKING; } /* * Remove/set the tool tip. * We always do this synchronously because it doesn't mess * with pwnd's or spwnTrack's queue */ if ((pstr = IsTooltipHittest(pwnd, LOWORD(htEx))) != NULL) { PTOOLTIPWND pttwnd = (PTOOLTIPWND)pdesk->spwndTooltip; ThreadLockAlways(pttwnd, &tlpwnd); xxxCreateTooltip(pttwnd, pstr); ThreadUnlock(&tlpwnd); pdesk->dwDTFlags |= DF_TOOLTIP; } else { PTOOLTIPWND pttwnd = (PTOOLTIPWND)pdesk->spwndTooltip; ThreadLockAlways(pttwnd, &tlpwnd); xxxResetTooltip(pttwnd); ThreadUnlock(&tlpwnd); } } /* if (htEx != HTCLIENT) */ ValidateThreadLocks(NULL, PtiCurrent()->ptl, (ULONG_PTR)&pwnd, TRUE); /* * Update new track window if needed. */ if (fNewpwndTrack) { PWND pwndActivate; Lock(&pdesk->spwndTrack, pwnd); /* * Active window tracking. * If there is non-zero timeout, get the window we're supposed to activate * and set the timer. Otherwise, set the queue flag so * xxxActiveWindowTracking can do its thing. */ if ((message == WM_MOUSEMOVE) && TestUP(ACTIVEWINDOWTRACKING)) { if (UP(ACTIVEWNDTRKTIMEOUT) != 0) { pwndActivate = GetActiveTrackPwnd(pwnd, NULL); if (pwndActivate != NULL) { InternalSetTimer(pwndActivate, IDSYS_WNDTRACKING, UP(ACTIVEWNDTRKTIMEOUT), xxxSystemTimerProc, TMRF_SYSTEM); } } else { PtiCurrent()->pq->QF_flags |= QF_ACTIVEWNDTRACKING; } /* if (TestUP(ACTIVEWNDTRKZORDER)) */ } /* if (TestUP(ACTIVEWINDOWTRACKING)) */ } /* * Save new hit test code */ pdesk->htEx = htEx; #if DBG --gcReEntered; #endif }
VOID NlsKbdInitializePerSystem(VOID) { RTL_QUERY_REGISTRY_TABLE QueryTable[4]; UNICODE_STRING EndString, HelpString; UNICODE_STRING YesString, NoString; UNICODE_STRING HomeString, ClearString; UNICODE_STRING HelpKeyString; UNICODE_STRING KanaHelpString; UNICODE_STRING ClearKeyString; NTSTATUS status; // // Set default VK_DBE_xxx status. // // // AlphaNumeric input mode. // NlsSetKeyStateToggle(VK_DBE_ALPHANUMERIC); // // Single byte character input mode. // NlsSetKeyStateToggle(VK_DBE_SBCSCHAR); // // No roman input mode. // NlsSetKeyStateToggle(VK_DBE_NOROMAN); // // No code input mode. // NlsSetKeyStateToggle(VK_DBE_NOCODEINPUT); // // From Here, below code is for compatibility for Windows NT 3.xx // for NEC PC-9800 verion. // // // Initialize default strings. // RtlInitUnicodeString(&EndString, L"end"); RtlInitUnicodeString(&HelpString,L"help"); RtlInitUnicodeString(&YesString,L"yes"); RtlInitUnicodeString(&NoString, L"no"); RtlInitUnicodeString(&HomeString, L"home"); RtlInitUnicodeString(&ClearString,L"clear"); // // Initialize recieve buffer. // RtlInitUnicodeString(&HelpKeyString,NULL); RtlInitUnicodeString(&KanaHelpString,NULL); RtlInitUnicodeString(&ClearKeyString,NULL); // // Initalize query tables. // // ValueName : "helpkey" // ValueData : if "end" VK_END, otherwise VK_HELP // QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[0].Name = (PWSTR) L"helpkey", QueryTable[0].EntryContext = (PVOID) &HelpKeyString; QueryTable[0].DefaultType = REG_SZ; QueryTable[0].DefaultData = &EndString; QueryTable[0].DefaultLength = 0; // // ValueName : "KanaHelpKey" // ValueData : if "yes" if kana on switch VK_HELP and VK_END // QueryTable[1].QueryRoutine = NULL; QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[1].Name = (PWSTR) L"KanaHelpKey", QueryTable[1].EntryContext = (PVOID) &KanaHelpString; QueryTable[1].DefaultType = REG_SZ; QueryTable[1].DefaultData = &YesString; QueryTable[1].DefaultLength = 0; // // ValueName : "clrkey" // ValueData : if "home" VK_HOME, otherwise VK_CLEAR // QueryTable[2].QueryRoutine = NULL; QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[2].Name = (PWSTR) L"clrkey", QueryTable[2].EntryContext = (PVOID) &ClearKeyString; QueryTable[2].DefaultType = REG_SZ; QueryTable[2].DefaultData = &HomeString; QueryTable[2].DefaultLength = 0; QueryTable[3].QueryRoutine = NULL; QueryTable[3].Flags = 0; QueryTable[3].Name = NULL; status = RtlQueryRegistryValues( RTL_REGISTRY_WINDOWS_NT, NLSKBD_CONFIG_PATH, QueryTable, NULL, NULL); if (!NT_SUCCESS(status)) { RIPMSG1(RIP_WARNING, "FEKBD:RtlQueryRegistryValues fails (%x)\n", status); return; } if (RtlEqualUnicodeString(&HelpKeyString,&HelpString,TRUE)) { /* * Generate VK_HELP, when NLSKBD_HELP_OR_END is called. */ fNlsKbdConfiguration &= ~GEN_VK_END; } if (RtlEqualUnicodeString(&KanaHelpString,&NoString,TRUE)) { /* * In case of "yes": * If 'kana' is on, when NLSKBD_HELP_OR_END is called, switch VK_END and VK_HELP. * Else, in case of "no": * Doesn't generate by 'kana' toggle state. */ fNlsKbdConfiguration &= ~GEN_KANA_AWARE; } if (RtlEqualUnicodeString(&ClearKeyString,&ClearString,TRUE)) { /* * Generate VK_CLEAR, when KBDNLS_HOME_OR_CLEAR is called. */ fNlsKbdConfiguration &= ~GEN_VK_HOME; } return; }
VOID GetVersionInfo( BOOL Verbose ) { WCHAR NameBuffer[MAXVERSIONBUFFER]; WCHAR Title1[128]; WCHAR Title2[128]; WCHAR wszPID[MAXVERSIONSTRING]; WCHAR wszPro[MAXVERSIONSTRING]; WCHAR wszSrv[MAXVERSIONSTRING]; WCHAR wszPBuild[MAXVERSIONSTRING]; WCHAR wszEvaluation[MAXVERSIONSTRING]; UNICODE_STRING UserBuildString; UNICODE_STRING UserTypeString; UNICODE_STRING UserCSDString; NTSTATUS Status; RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable[] = { {NULL, RTL_QUERY_REGISTRY_DIRECT, L"CurrentBuildNumber", &UserBuildString, REG_NONE, NULL, 0}, {NULL, RTL_QUERY_REGISTRY_DIRECT, L"CurrentType", &UserTypeString, REG_NONE, NULL, 0}, {NULL, RTL_QUERY_REGISTRY_DIRECT, L"CSDVersion", &UserCSDString, REG_NONE, NULL, 0}, {NULL, 0, NULL, NULL, REG_NONE, NULL, 0} }; UserBuildString.Buffer = &NameBuffer[OFFSET_BLDSTRING]; UserBuildString.Length = 0; UserBuildString.MaximumLength = MAXVERSIONSTRING * sizeof(WCHAR); UserTypeString.Buffer = &NameBuffer[OFFSET_TYPSTRING]; UserTypeString.Length = 0; UserTypeString.MaximumLength = MAXVERSIONSTRING * sizeof(WCHAR); UserCSDString.Buffer = &NameBuffer[OFFSET_CSDSTRING]; UserCSDString.Length = 0; UserCSDString.MaximumLength = MAXVERSIONSTRING * sizeof(WCHAR); Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, L"", BaseServerRegistryConfigurationTable, NULL, NULL); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "GetVersionInfo failed with status %x", Status); return; } ServerLoadString( hModuleWin, STR_DTBS_PRODUCTID, wszPID, ARRAY_SIZE(wszPID) ); ServerLoadString( hModuleWin, STR_DTBS_PRODUCTPRO, wszPro, ARRAY_SIZE(wszPro) ); ServerLoadString( hModuleWin, STR_DTBS_PRODUCTSRV, wszSrv, ARRAY_SIZE(wszSrv) ); ServerLoadString( hModuleWin, STR_DTBS_PRODUCTBUILD, wszPBuild, ARRAY_SIZE(wszPBuild) ); /* * Write out Debugging Version message. */ /* * Bug 280256 - joejo * Create new desktop build information strings */ swprintf( wszProductName, wszPID, ((USER_SHARED_DATA->NtProductType == NtProductWinNt) ? wszPro : wszSrv) ); if (gfUnsignedDrivers) { /* This takes precedence */ ServerLoadString( hModuleWin, STR_TESTINGONLY, wszEvaluation, ARRAY_SIZE(wszEvaluation) ); } else if (USER_SHARED_DATA->SystemExpirationDate.QuadPart) { ServerLoadString(hModuleWin, STR_DTBS_EVALUATION, wszEvaluation, ARRAY_SIZE(wszEvaluation)); } else { wszEvaluation[0] = '\0'; } swprintf( wszProductBuild, wszPBuild, wszEvaluation, UserBuildString.Buffer ); if (Verbose) { ServerLoadString( hModuleWin, STR_SAFEMODE_TITLE1, Title1, ARRAY_SIZE(Title1) ); ServerLoadString( hModuleWin, STR_SAFEMODE_TITLE2, Title2, ARRAY_SIZE(Title2) ); swprintf( wszT, UserCSDString.Length == 0 ? Title1 : Title2, UserBuildString.Buffer, UserCSDString.Buffer, USER_SHARED_DATA->NtSystemRoot ); } else { PWSTR s = wcsrchr( UserTypeString.Buffer, L' ' ); if (s) { s += 1; } else { s = UserTypeString.Buffer; } ServerLoadString( hModuleWin, STR_SAFEMODE_TITLE3, Title1, ARRAY_SIZE(Title1) ); ServerLoadString( hModuleWin, STR_SAFEMODE_TITLE4, Title2, ARRAY_SIZE(Title2) ); swprintf( wszT, UserCSDString.Length == 0 ? Title1 : Title2, UserBuildString.Buffer, UserCSDString.Buffer, s ); } }
BOOL RtlWCSMessageWParamCharToMB(DWORD msg, WPARAM *pWParam) { DWORD dwAnsi; NTSTATUS Status; WORD CodePage; int nbWch; #ifdef FE_SB // RtlWCSMessageWParamCharToMB() // // Format of *pWParam here... // // LOWORD(*pWParam) = Unicode CodePoint... // HIWORD(*pWParam) = Has some information for DBCS messaging // (ex. WPARAM_IR_DBCSCHAR) // // Then we need to convert ONLY loword of wParam to Unicode... // #endif // FE_SB #ifndef FE_SB // NtBug #3135 (Closed 02/04/93) // Publisher Posts WM_CHAR messages with wParam > 0xFF (not a valid ANSI char)! // // It does this to disable TranslateAccelerator for that char. // MSPub's winproc must get the non-ANSI 'character' value, so PostMessage must // translate *two* characters of wParam for character messages, and PeekMessage // must translate *two* Unicode chars of wParam for ANSI app. #endif /* * Only these messages have CHARs: others are passed through */ switch(msg) { #ifdef FE_IME // RtlWCSMessageWParamCharToMB() case WM_IME_CHAR: case WM_IME_COMPOSITION: #endif // FE_IME case WM_CHAR: case WM_CHARTOITEM: case EM_SETPASSWORDCHAR: case WM_DEADCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: case WM_MENUCHAR: CodePage = THREAD_CODEPAGE(); dwAnsi = 0; nbWch = IS_DBCS_ENABLED() ? 1 * sizeof(WCHAR) : 2 * sizeof(WCHAR); if (IS_ACP(CodePage)) { // HACK HACK HACK HACK (for NtBug #3135) // to allow applications that store data in high word of wParam // Jan/06/96 hiroyama Status = RtlUnicodeToMultiByteN((LPSTR)&dwAnsi, sizeof(dwAnsi), NULL, (LPWSTR)pWParam, nbWch); if (!NT_SUCCESS(Status)) { // LATER IanJa: returning FALSE makes GetMessage fail, which // terminates the app. We should use some default 'bad character' // I use 0x00 for now. *pWParam = 0x00; return TRUE; } } else { int cwch; // assuming little endian #ifdef _USERK_ cwch = EngWideCharToMultiByte(CodePage, (LPWSTR)pWParam, nbWch, (LPSTR)&dwAnsi, sizeof(dwAnsi)); #else cwch = WideCharToMultiByte(CodePage, 0, (LPCWSTR)pWParam, nbWch / sizeof(WCHAR), (LPSTR)&dwAnsi, sizeof(dwAnsi), NULL, NULL); #endif // _USERK_ // KdPrint(("0x%04x -> 0x%02x (%d)\n", *pWParam, dwAnsi, CodePage)); if (cwch == 0) { *pWParam = 0x00; return TRUE; } } if (IS_DBCS_ENABLED()) { WORD wAnsi = LOWORD(dwAnsi); // // From: // HIBYTE(wAnsi) = Dbcs TrailingByte. // LOBYTE(wAnsi) = Dbcs LeadingByte or Sbcs character. // // To: // HIWORD(*pWParam) = Original Data (information for DBCS messgaing). // HIBYTE(LOWORD(*pWParam)) = Dbcs LeadingByte Byte. // LOBYTE(LOWORD(*pWParam)) = Dbcs TrailingByte or Sbcs character. // if (IS_DBCS_MESSAGE(wAnsi)) { // // It's a DBCS character. // *pWParam = MAKEWPARAM(MAKEWORD(HIBYTE(wAnsi),LOBYTE(wAnsi)),HIWORD(*pWParam)); } else { // // It's a SBCS character. // *pWParam = MAKEWPARAM(MAKEWORD(LOBYTE(wAnsi),0),0); } } else { #if DBG if ((dwAnsi == 0) || (dwAnsi > 0xFF)) { RIPMSG1(RIP_VERBOSE, "msgW -> msgA: char = 0x%.4lX\n", dwAnsi); } #endif *pWParam = dwAnsi; } break; } return TRUE; }
BOOL RtlMBMessageWParamCharToWCS(DWORD msg, WPARAM *pWParam) { DWORD dwUni; NTSTATUS Status; // FE_SB (RtlMBMessageWParamCharToWCS) BOOL bWmCrIrDbcsChar = FALSE; WORD wAnsi = LOWORD(*pWParam); // end FE_SB (RtlMBMessageWParamCharToWCS) WORD CodePage = THREAD_CODEPAGE(); /* * Only these messages have CHARs: others are passed through */ switch(msg) { // FE_SB (RtlMBMessageWParamCharToWCS) case WM_CHAR: // // WM_CHAR's wParam format for WM_IME_REPORT:IR_DBCSCHAR // if (IS_DBCS_ENABLED() && (*pWParam & WMCR_IR_DBCSCHAR)) { // // Mark this message is sent as IR_DBCSCHAR format. // bWmCrIrDbcsChar = TRUE; } // // Fall through.... // #ifdef FE_IME case WM_IME_CHAR: case WM_IME_COMPOSITION: // // We need to re-align for Unicode convertsion.. // WM_CHAR/WM_IME_CHAR/WM_IME_COMPOSITION's wParam format : // // ReAlign IR_DBCS char format to regular sequence. // // From: // // HIWORD(wParam) = 0; // HIBYTE(LOWORD(wParam)) = DBCS LeadingByte. // LOBYTE(LOWORD(wParan)) = DBCS TrailingByte or SBCS character. // // To: // HIWORD(wParam) = 0; // HIBYTE(LOWORD(wParam)) = DBCS TrailingByte. // LOBYTE(LOWORD(wParam)) = DBCS LeadingByte or SBCS character. // if (IS_DBCS_ENABLED()) { *pWParam = MAKE_WPARAM_DBCSCHAR(wAnsi); } #endif // // Fall through... // // end FE_SB (RtlMBMessageWParamCharToWCS) case WM_CHARTOITEM: case EM_SETPASSWORDCHAR: case WM_DEADCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: case WM_MENUCHAR: dwUni = 0; if (IS_ACP(CodePage)) { Status = RtlMultiByteToUnicodeN((LPWSTR)&dwUni, sizeof(dwUni), NULL, (LPSTR)pWParam, 2 * sizeof(CHAR)); if (!NT_SUCCESS(Status)) return FALSE; } else { int cwch; #ifdef _USERK_ cwch = EngMultiByteToWideChar(CodePage, (LPWSTR)&dwUni, sizeof(dwUni), (LPSTR)pWParam, 2); #else cwch = MultiByteToWideChar(CodePage, 0, (LPSTR)pWParam, 2, (LPWSTR)&dwUni, sizeof(dwUni) / sizeof(WCHAR)); #endif // _USERK_ // KdPrint(("0x%02x -> 0x%04x (%d)\n", *pWParam, dwUni, CodePage)); if (cwch == 0) { return FALSE; } } // FE_SB (RtlMBMessageWParamCharToWCS) // // if this character is sent for WM_IME_REPORT:IR_DBCSCHAR, we mark it. // if (bWmCrIrDbcsChar) dwUni |= WMCR_IR_DBCSCHAR; // else FE_SB (RtlMBMessageWParamCharToWCS) #if DBG if ((dwUni == 0) || (dwUni > 0xFF)) { RIPMSG1(RIP_VERBOSE, "msgA -> msgW: wchar = 0x%lX\n", dwUni); } #endif // end FE_SB *pWParam = dwUni; break; } return TRUE; }
VOID vProcessFontEntry( HKEY hkey, WCHAR *pwcValueName, WCHAR *pwcFileName ) { BOOL bFot = FALSE; WCHAR awcTTF[MAX_PATH]; WCHAR awcTmpBuf[MAX_PATH]; WCHAR *pwcTTF; FLONG fl, fl2; FLONG flEmbed; DWORD dwPidTid; if (bCheckFontEntry(pwcValueName, EXT_TRUETYPE)) { // This is a tt entry, either .fot or .ttf if (bFot = bCheckFontEntry(pwcFileName,EXT_FOT)) { // this is an .fot entry, must find ttf pointed to by .fot, // but first must get the full path to the .fot file // for cGetTTFFromFOT routine expects it. We will also need // the full path to the .fot file so that we can delete it // eventually. if (bMakePathNameW(awcTmpBuf, pwcFileName,NULL, &fl2)) { if (cGetTTFFromFOT(awcTmpBuf, MAX_PATH, awcTTF, &fl, &flEmbed, &dwPidTid) && !(fl & FONT_ISNOT_FOT)) { // fix the entry to point to .ttf file. At this point // awcTTF points to the FULL path to the .ttf file. // However, we will only need a relative path to the // .ttf file, when the .ttf file is in the %windir%\system // or %windir%\fonts directories. In case the file is in the // %windir%\system directory we shall copy it to %windir%\fonts // directory and write the relative path to the registry. // In case it is in the %windir%\fonts directory we do not // touch the file and also just write the relative path to the // registry. In any other case we just write the full .ttf // path to the registry. // first delete the .fot file, it is no longer needed if (bFot && !gbWin31Upgrade) { UserVerify(DeleteFileW(awcTmpBuf)); } if ((fl & (FONT_IN_FONTS_DIR | FONT_IN_SYSTEM_DIR)) == 0) { // if ttf file is not in either the system or the fonts // directories, just write the full path to the registry pwcTTF = awcTTF; } else { // find the bare file part, this is what will be written // in the registry pwcTTF = &awcTTF[wcslen(awcTTF) - 1]; while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':')) pwcTTF--; pwcTTF++; if (fl & FONT_IN_SYSTEM_DIR) { // need to move the ttf to fonts dir, can reuse the // buffer on the stack: wcscpy(awcTmpBuf, gpwcFontsDir); lstrcatW(awcTmpBuf, L"\\"); lstrcatW(awcTmpBuf, pwcTTF); // note that MoveFile should succeed, for if there was // a ttf file of the same file name in %windir%\fonts dir // we would not have been in this code path. RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf); if (!gbWin31Upgrade) { UserVerify(MoveFileW(awcTTF, awcTmpBuf)); } else { // Boolean value TRUE means "do not copy if target exists" UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE)); } } } RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF); UserVerify(ERROR_SUCCESS == RegSetValueExW( hkey, // here is the key pwcValueName, 0, REG_SZ, (CONST BYTE*) pwcTTF, (DWORD)((wcslen(pwcTTF)+1) * sizeof(WCHAR)))); } #ifdef DEBUG else { RIPMSG1(RIP_WARNING, "Could not locate ttf pointed to by %ws", awcTmpBuf); } #endif } #ifdef DEBUG else { RIPMSG1(RIP_WARNING, "Could not locate .fot: %ws", pwcFileName); } #endif } } else { // not a true type case. little bit simpler, // we will use awcTTF buffer for the full path name, and pwcTTF // as local variable even though these TTF names are misnomer // for these are not tt fonts if (bMakePathNameW(awcTTF, pwcFileName,NULL, &fl)) { // At this point // awcTTF points to the FULL path to the font file. // If the font is in the system subdirectory we will just move it // to the fonts subdirectory. If the path in the registry is relative // we will leave it alone. If it is an absolute path, we shall // fix the registry entry to only contain relative path, the // absolute path is redundant. if (fl & (FONT_IN_SYSTEM_DIR | FONT_IN_FONTS_DIR)) { // find the bare file part, this is what will be written // in the registry pwcTTF = &awcTTF[wcslen(awcTTF) - 1]; while ((pwcTTF >= awcTTF) && (*pwcTTF != L'\\') && (*pwcTTF != L':')) pwcTTF--; pwcTTF++; if (fl & FONT_IN_SYSTEM_DIR) { // need to move the font to fonts dir, can reuse the // buffer on the stack to build the full destination path wcscpy(awcTmpBuf, gpwcFontsDir); lstrcatW(awcTmpBuf, L"\\"); lstrcatW(awcTmpBuf, pwcTTF); // note that MoveFile should succeed, for if there was // a font file of the same file name in %windir%\fonts dir // we would not have been in this code path. The only time // it could fail if the path in the registry is absolute. RIPMSG2(RIP_VERBOSE, "Moving %ws to %ws", awcTTF, awcTmpBuf); if (!gbWin31Upgrade) { UserVerify(MoveFileW(awcTTF, awcTmpBuf)); } else { // Boolean value TRUE means "do not copy if target exists" UserVerify(CopyFileW(awcTTF, awcTmpBuf, TRUE)); } } // check if the file path in the registry is absolute, // if so make it relative: if (!(fl & FONT_RELATIVE_PATH)) { RIPMSG2(RIP_VERBOSE, "writing to the registry:\n %ws=%ws", pwcValueName, pwcTTF); UserVerify(ERROR_SUCCESS == RegSetValueExW( hkey, // here is the key pwcValueName, 0, REG_SZ, (CONST BYTE*) pwcTTF, (DWORD)((wcslen(pwcTTF)+1) * sizeof(WCHAR)))); } } } } }
/*****************************************************************************\ * * GetGUIThreadInfo() * * This gets GUI information out of context. If you pass in a NULL thread ID, * we will get the 'global' information, using the foreground thread. This * is guaranteed to be the real active window, focus window, etc. Yes, you * could do it yourself by calling GetForegroundWindow, getting the thread ID * of that window via GetWindowThreadProcessId, then passing the ID into * GetGUIThreadInfo(). However, that takes three calls and aside from being * a pain, anything could happen in the middle. So passing in NULL gets * you stuff in one call and hence also works right. * * This function returns FALSE if the thread doesn't have a queue or the * thread ID is bogus. * \*****************************************************************************/ BOOL WINAPI _GetGUIThreadInfo(PTHREADINFO pti, PGUITHREADINFO pgui) { PQ pq; /* * Validate threadinfo structure */ if (pgui->cbSize != sizeof(GUITHREADINFO)) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "GUITHREADINFO.cbSize %d is wrong", pgui->cbSize); return FALSE; } /* * Is this a valid initialized GUI thread? */ if (pti != NULL) { if ((pq = pti->pq) == NULL) { // does this ever happen? RIPMSG1(RIP_ERROR, "GetGUIThreadInfo: No queue for pti %lx", pti); return FALSE; } } else { /* * Use the foreground queue. To get menu state information we must also * figure out the right pti. This matches _GetForegroundWindow() logic. */ if ((pq = gpqForeground) == NULL) { // this does sometimes happen... RIPMSG0(RIP_WARNING, "GetGUIThreadInfo: No foreground queue"); return FALSE; } if (pq->spwndActive && (GETPTI(pq->spwndActive)->pq == pq)) { pti = GETPTI(pq->spwndActive); if (PtiCurrentShared()->rpdesk != pti->rpdesk) { RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground window on different desktop"); return FALSE; } } } UserAssert(pq != NULL); /* * For C2 security, verify that pq and pti are on the current thread's desktop. * We can't directly determine which desktop pq belongs to, but we can at * least ensure that any caret info we return is not from another desktop */ if (pq->caret.spwnd && (GETPTI(pq->caret.spwnd)->rpdesk != PtiCurrentShared()->rpdesk)) { RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground caret on different desktop"); return FALSE; } if (pti && (pti->rpdesk != PtiCurrentShared()->rpdesk)) { RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "Foreground thread on different desktop"); return FALSE; } pgui->flags = 0; pgui->hwndMoveSize = NULL; pgui->hwndMenuOwner = NULL; /* * Get Menu information from the THREADINFO */ if (pti != NULL) { if (pti->pmsd && !pti->pmsd->fTrackCancelled && pti->pmsd->spwnd) { pgui->flags |= GUI_INMOVESIZE; pgui->hwndMoveSize = HWq(pti->pmsd->spwnd); } if (pti->pMenuState && pti->pMenuState->pGlobalPopupMenu) { pgui->flags |= GUI_INMENUMODE; if (pti->pMenuState->pGlobalPopupMenu->fHasMenuBar) { if (pti->pMenuState->pGlobalPopupMenu->fIsSysMenu) { pgui->flags |= GUI_SYSTEMMENUMODE; } } else { pgui->flags |= GUI_POPUPMENUMODE; } if (pti->pMenuState->pGlobalPopupMenu->spwndNotify) pgui->hwndMenuOwner = HWq(pti->pMenuState->pGlobalPopupMenu->spwndNotify); } } /* * Get the rest of the information from the queue */ pgui->hwndActive = HW(pq->spwndActive); pgui->hwndFocus = HW(pq->spwndFocus); pgui->hwndCapture = HW(pq->spwndCapture); pgui->hwndCaret = NULL; if (pq->caret.spwnd) { pgui->hwndCaret = HWq(pq->caret.spwnd); /* * These coords are always relative to the client of hwndCaret * of course. */ pgui->rcCaret.left = pq->caret.x; pgui->rcCaret.right = pgui->rcCaret.left + pq->caret.cx; pgui->rcCaret.top = pq->caret.y; pgui->rcCaret.bottom = pgui->rcCaret.top + pq->caret.cy; if (pq->caret.iHideLevel == 0) pgui->flags |= GUI_CARETBLINKING; } else if (pti && (pti->ppi->W32PF_Flags & W32PF_CONSOLEHASFOCUS)) { /* * The thread is running in the console window with focus. Pull * out the info from the console pseudo caret. */ pgui->hwndCaret = pti->rpdesk->cciConsole.hwnd; pgui->rcCaret = pti->rpdesk->cciConsole.rc; } else { SetRectEmpty(&pgui->rcCaret); } return TRUE; }
void xxxEndMenu( PMENUSTATE pMenuState) { BOOL fMenuStateOwner; PPOPUPMENU ppopup; PTHREADINFO ptiCurrent; if ((ppopup = pMenuState->pGlobalPopupMenu) == NULL) { /* * We're not really in menu mode. This can happen * if we are forced out of menu loop too soon; i.e, from * inside xxxMNGetPopup or xxxTrackPopupMenuEx. */ UserAssert(!pMenuState->fInsideMenuLoop && !pMenuState->fMenuStarted); return; } pMenuState->fInsideMenuLoop = FALSE; pMenuState->fMenuStarted = FALSE; /* * Mark the popup as destroyed so people will not use it anymore. * This means that root popups can be marked as destroyed before * actually being destroyed (nice and confusing). */ ppopup->fDestroyed = TRUE; /* * Determine if this is the menu loop owner before calling back. * Only the owner can destroy the menu windows */ ptiCurrent = PtiCurrent(); fMenuStateOwner = (ptiCurrent == pMenuState->ptiMenuStateOwner); /* * Release mouse capture if we got it in xxxStartMenuState */ if (ptiCurrent->pq->spwndCapture == pMenuState->pGlobalPopupMenu->spwndNotify) { xxxMNReleaseCapture(); } /* * Bail if this is not the menu loop owner */ if (!fMenuStateOwner) { RIPMSG1(RIP_WARNING, "xxxEndMenu: Thread %#p doesn't own the menu loop", ptiCurrent); return; } /* * If the menu loop is running on a thread different than the thread * that owns spwndNotify, we can have two threads trying to end * this menu at the same time. */ if (pMenuState->fInEndMenu) { RIPMSG1(RIP_WARNING, "xxxEndMenu: already in EndMenu. pMenuState:%#p", pMenuState); return; } pMenuState->fInEndMenu = TRUE; if (pMenuState->pGlobalPopupMenu->spwndNotify != NULL) { if (!pMenuState->pGlobalPopupMenu->fInCancel) { xxxMNDismiss(pMenuState); } } else { BOOL fTrackedPopup = ppopup->fIsTrackPopup; /* * This should do the same stuff as MenuCancelMenus but not send any * messages... */ xxxMNCloseHierarchy(ppopup, pMenuState); if (fTrackedPopup) { xxxDestroyWindow(ppopup->spwndPopupMenu); } } }
LRESULT APIENTRY ListBoxWndProcWorker( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, DWORD fAnsi) { HWND hwnd = HWq(pwnd); PAINTSTRUCT ps; HDC hdc; LPRECT lprc; PLBIV plb; /* List Box Instance Variable */ INT iSel; /* Index of selected item */ DWORD dw; TL tlpwndParent; UINT wFlags; LPWSTR lpwsz = NULL; LRESULT lReturn = 0; static BOOL fInit = TRUE; CheckLock(pwnd); VALIDATECLASSANDSIZE(pwnd, FNID_LISTBOX); INITCONTROLLOOKASIDE(&ListboxLookaside, LBIV, spwnd, 4); /* * Get the plb for the given window now since we will use it a lot in * various handlers. This was stored using SetWindowLong(hwnd,0,plb) * when the listbox was first created (by INITCONTROLLOOKASIDE above) */ plb = ((PLBWND)pwnd)->pLBIV; /* * Handle ANSI translations of input parameters */ if (fAnsi) { switch (message) { case LB_ADDSTRING: case LB_ADDSTRINGUPPER: case LB_ADDSTRINGLOWER: case LB_FINDSTRING: case LB_FINDSTRINGEXACT: case LB_INSERTSTRING: case LB_INSERTSTRINGUPPER: case LB_INSERTSTRINGLOWER: case LB_SELECTSTRING: if (!plb->fHasStrings) { break; } // Fall through... case LB_ADDFILE: case LB_DIR: if (lParam) { if (!MBToWCS((LPSTR)lParam, -1, &lpwsz, -1, TRUE)) return LB_ERR; } break; default: break; } if (lpwsz) { lParam = (LPARAM)lpwsz; } } switch (message) { case LB_GETTOPINDEX: // Return index of top item displayed. return plb->iTop; case LB_SETTOPINDEX: if (wParam && ((INT)wParam < 0 || (INT)wParam >= plb->cMac)) { RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, ""); return LB_ERR; } if (plb->cMac) { xxxNewITop(plb, (INT)wParam); } break; case WM_STYLECHANGED: plb->fRtoLReading = (TestWF(pwnd, WEFRTLREADING) != 0); plb->fRightAlign = (TestWF(pwnd, WEFRIGHT) != 0); xxxCheckRedraw(plb, FALSE, 0); break; case WM_WINDOWPOSCHANGED: /* * If we are in the middle of creation, ignore this * message because it will generate a WM_SIZE message. * See xxxLBCreate(). */ if (!plb->fIgnoreSizeMsg) goto CallDWP; break; case WM_SIZE: /* * If we are in the middle of creation, ignore size * messages. See xxxLBCreate(). */ if (!plb->fIgnoreSizeMsg) xxxLBSize(plb, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_ERASEBKGND: ThreadLock(plb->spwndParent, &tlpwndParent); FillWindow(HW(plb->spwndParent), hwnd, (HDC)wParam, (HBRUSH)CTLCOLOR_LISTBOX); ThreadUnlock(&tlpwndParent); return TRUE; case LB_RESETCONTENT: xxxLBResetContent(plb); break; case WM_TIMER: if (wParam == IDSYS_LBSEARCH) { plb->iTypeSearch = 0; NtUserKillTimer(hwnd, IDSYS_LBSEARCH); xxxInvertLBItem(plb, plb->iSel, TRUE); break; } message = WM_MOUSEMOVE; xxxTrackMouse(plb, message, plb->ptPrev); break; /* * Fall through */ case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_LBUTTONDBLCLK: { POINT pt; POINTSTOPOINT(pt, lParam); xxxTrackMouse(plb, message, pt); } break; case WM_MBUTTONDOWN: EnterReaderModeHelper(hwnd); break; case WM_CAPTURECHANGED: // // Note that this message should be handled only on unexpected // capture changes currently. // UserAssert(TestWF(pwnd, WFWIN40COMPAT)); if (plb->fCaptured) xxxLBButtonUp(plb, LBUP_NOTIFY); break; case LBCB_STARTTRACK: // // Start tracking mouse moves in the listbox, setting capture // if (!plb->pcbox) break; plb->fCaptured = FALSE; if (wParam) { POINT pt; POINTSTOPOINT(pt, lParam); _ScreenToClient(pwnd, &pt); xxxTrackMouse(plb, WM_LBUTTONDOWN, pt); } else { NtUserSetCapture(hwnd); plb->fCaptured = TRUE; plb->iLastSelection = plb->iSel; } break; case LBCB_ENDTRACK: // Kill capture, tracking, etc. if (plb->fCaptured) xxxLBButtonUp(plb, LBUP_RELEASECAPTURE | (wParam ? LBUP_SELCHANGE : LBUP_RESETSELECTION)); break; case WM_PRINTCLIENT: xxxLBPaint(plb, (HDC) wParam, NULL); break; case WM_PAINT: if (wParam) { hdc = (HDC) wParam; lprc = NULL; } else { hdc = NtUserBeginPaint(hwnd, &ps); lprc = &(ps.rcPaint); } if (IsLBoxVisible(plb)) xxxLBPaint(plb, hdc, lprc); if (!wParam) NtUserEndPaint(hwnd, &ps); break; case WM_NCDESTROY: case WM_FINALDESTROY: xxxDestroyLBox(plb, pwnd); break; case WM_SETFOCUS: // DISABLED in Win 3.1 xxxUpdateWindow(pwnd); CaretCreate(plb); xxxLBSetCaret(plb, TRUE); xxxNotifyOwner(plb, LBN_SETFOCUS); if (FWINABLE()) { if (_IsWindowVisible(pwnd)) { LBEvent(plb, EVENT_OBJECT_FOCUS, plb->iSelBase); } } break; case WM_KILLFOCUS: /* * Reset the wheel delta count. */ gcWheelDelta = 0; xxxLBSetCaret(plb, FALSE); xxxCaretDestroy(plb); xxxNotifyOwner(plb, LBN_KILLFOCUS); if (plb->iTypeSearch) { plb->iTypeSearch = 0; NtUserKillTimer(hwnd, IDSYS_LBSEARCH); } if (plb->pszTypeSearch) { UserLocalFree(plb->pszTypeSearch); plb->pszTypeSearch = NULL; } break; case WM_MOUSEWHEEL: { int cDetants; int cPage; int cLines; RECT rc; int windowWidth; int cPos; /* * Don't handle zoom and datazoom. */ if (wParam & (MK_SHIFT | MK_CONTROL)) { goto CallDWP; } lReturn = 1; gcWheelDelta -= (short) HIWORD(wParam); cDetants = gcWheelDelta / WHEEL_DELTA; if ( cDetants != 0 && gpsi->ucWheelScrollLines > 0 && (pwnd->style & (WS_VSCROLL | WS_HSCROLL))) { gcWheelDelta = gcWheelDelta % WHEEL_DELTA; if (pwnd->style & WS_VSCROLL) { cPage = max(1, (plb->cItemFullMax - 1)); cLines = cDetants * (int) min((UINT) cPage, gpsi->ucWheelScrollLines); cPos = max(0, min(plb->iTop + cLines, plb->cMac - 1)); if (cPos != plb->iTop) { xxxLBoxCtlScroll(plb, SB_THUMBPOSITION, cPos); xxxLBoxCtlScroll(plb, SB_ENDSCROLL, 0); } } else if (plb->fMultiColumn) { cPage = max(1, plb->numberOfColumns); cLines = cDetants * (int) min((UINT) cPage, gpsi->ucWheelScrollLines); cPos = max( 0, min((plb->iTop / plb->itemsPerColumn) + cLines, plb->cMac - 1 - ((plb->cMac - 1) % plb->itemsPerColumn))); if (cPos != plb->iTop) { xxxLBoxCtlHScrollMultiColumn(plb, SB_THUMBPOSITION, cPos); xxxLBoxCtlHScrollMultiColumn(plb, SB_ENDSCROLL, 0); } } else { _GetClientRect(plb->spwnd, &rc); windowWidth = rc.right; cPage = max(plb->cxChar, (windowWidth / 3) * 2) / plb->cxChar; cLines = cDetants * (int) min((UINT) cPage, gpsi->ucWheelScrollLines); cPos = max( 0, min(plb->xOrigin + (cLines * plb->cxChar), plb->maxWidth)); if (cPos != plb->xOrigin) { xxxLBoxCtlHScroll(plb, SB_THUMBPOSITION, cPos); xxxLBoxCtlHScroll(plb, SB_ENDSCROLL, 0); } } } } break; case WM_VSCROLL: xxxLBoxCtlScroll(plb, LOWORD(wParam), HIWORD(wParam)); break; case WM_HSCROLL: xxxLBoxCtlHScroll(plb, LOWORD(wParam), HIWORD(wParam)); break; case WM_GETDLGCODE: return DLGC_WANTARROWS | DLGC_WANTCHARS; case WM_CREATE: return xxxLBCreate(plb, pwnd, (LPCREATESTRUCT) lParam); case WM_SETREDRAW: /* * If wParam is nonzero, the redraw flag is set * If wParam is zero, the flag is cleared */ xxxLBSetRedraw(plb, (wParam != 0)); break; case WM_ENABLE: xxxLBInvalidateRect(plb, NULL, !plb->OwnerDraw); break; case WM_SETFONT: xxxLBSetFont(plb, (HANDLE)wParam, LOWORD(lParam)); break; case WM_GETFONT: return (LRESULT)plb->hFont; case WM_DRAGSELECT: case WM_DRAGLOOP: case WM_DRAGMOVE: case WM_DROPFILES: ThreadLock(plb->spwndParent, &tlpwndParent); lReturn = SendMessage(HW(plb->spwndParent), message, wParam, lParam); ThreadUnlock(&tlpwndParent); return lReturn; case WM_QUERYDROPOBJECT: case WM_DROPOBJECT: /* * fix up control data, then pass message to parent */ LBDropObjectHandler(plb, (PDROPSTRUCT)lParam); ThreadLock(plb->spwndParent, &tlpwndParent); lReturn = SendMessage(HW(plb->spwndParent), message, wParam, lParam); ThreadUnlock(&tlpwndParent); return lReturn; case LB_GETITEMRECT: return LBGetItemRect(plb, (INT)wParam, (LPRECT)lParam); case LB_GETITEMDATA: return LBGetItemData(plb, (INT)wParam); // wParam = item index case LB_SETITEMDATA: /* * wParam is item index */ return LBSetItemData(plb, (INT)wParam, lParam); case LB_ADDSTRINGUPPER: wFlags = UPPERCASE | LBI_ADD; goto CallInsertItem; case LB_ADDSTRINGLOWER: wFlags = LOWERCASE | LBI_ADD; goto CallInsertItem; case LB_ADDSTRING: wFlags = LBI_ADD; goto CallInsertItem; case LB_INSERTSTRINGUPPER: wFlags = UPPERCASE; goto CallInsertItem; case LB_INSERTSTRINGLOWER: wFlags = LOWERCASE; goto CallInsertItem; case LB_INSERTSTRING: wFlags = 0; CallInsertItem: lReturn = ((LRESULT) xxxLBInsertItem(plb, (LPWSTR) lParam, (int) wParam, wFlags)); break; case LB_INITSTORAGE: return xxxLBInitStorage(plb, fAnsi, (INT)wParam, (INT)lParam); case LB_DELETESTRING: return xxxLBoxCtlDelete(plb, (INT)wParam); case LB_DIR: /* * wParam - Dos attribute value. * lParam - Points to a file specification string */ lReturn = xxxLbDir(plb, (INT)wParam, (LPWSTR)lParam); break; case LB_ADDFILE: lReturn = xxxLbInsertFile(plb, (LPWSTR)lParam); break; case LB_SETSEL: return xxxLBSetSel(plb, (wParam != 0), (INT)lParam); case LB_SETCURSEL: /* * If window obscured, update so invert will work correctly */ // DISABLED in Win 3.1 xxxUpdateWindow(pwnd); return xxxLBSetCurSel(plb, (INT)wParam); case LB_GETSEL: if (wParam >= (UINT) plb->cMac) return((LRESULT) LB_ERR); return IsSelected(plb, (INT)wParam, SELONLY); case LB_GETCURSEL: if (plb->wMultiple == SINGLESEL) { return plb->iSel; } return plb->iSelBase; case LB_SELITEMRANGE: if (plb->wMultiple == SINGLESEL) { /* * Can't select a range if only single selections are enabled */ RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE,"Invalid index passed to LB_SELITEMRANGE"); return LB_ERR; } xxxLBSelRange(plb, LOWORD(lParam), HIWORD(lParam), (wParam != 0)); break; case LB_SELITEMRANGEEX: if (plb->wMultiple == SINGLESEL) { /* * Can't select a range if only single selections are enabled */ RIPERR0(ERROR_INVALID_LB_MESSAGE, RIP_VERBOSE,"LB_SELITEMRANGEEX:Can't select a range if only single selections are enabled"); return LB_ERR; } else { BOOL fHighlight = ((DWORD)lParam > (DWORD)wParam); if (fHighlight == FALSE) { ULONG_PTR temp = lParam; lParam = wParam; wParam = temp; } xxxLBSelRange(plb, (INT)wParam, (INT)lParam, fHighlight); } break; case LB_GETTEXTLEN: if (lParam != 0) { RIPMSG1(RIP_WARNING, "LB_GETTEXTLEN with lParam = %lx\n", lParam); } lReturn = LBGetText(plb, TRUE, fAnsi, (INT)wParam, NULL); break; case LB_GETTEXT: lReturn = LBGetText(plb, FALSE, fAnsi, (INT)wParam, (LPWSTR)lParam); break; case LB_GETCOUNT: // Lotus Approach calls CallWndProc(ListWndProc, LB_GETCOUNT,...) // on a window that doesn't have a plb yet. So, we need to make // this check. Bug #6675 - 11/7/94 -- if(plb) return((LRESULT) plb->cMac); else return(0); case LB_SETCOUNT: return xxxLBSetCount(plb, (INT)wParam); case LB_SELECTSTRING: case LB_FINDSTRING: iSel = xxxFindString(plb, (LPWSTR)lParam, (INT)wParam, PREFIX, TRUE); if (message == LB_FINDSTRING || iSel == LB_ERR) { lReturn = iSel; } else { lReturn = xxxLBSetCurSel(plb, iSel); } break; case LB_GETLOCALE: return plb->dwLocaleId; case LB_SETLOCALE: /* * Validate locale */ wParam = ConvertDefaultLocale((LCID)wParam); if (!IsValidLocale((LCID)wParam, LCID_INSTALLED)) return LB_ERR; dw = plb->dwLocaleId; plb->dwLocaleId = (DWORD)wParam; return dw; case WM_KEYDOWN: /* * IanJa: Use LOWORD() to get low 16-bits of wParam - this should * work for Win16 & Win32. The value obtained is the virtual key */ xxxLBoxCtlKeyInput(plb, message, LOWORD(wParam)); break; case WM_CHAR: xxxLBoxCtlCharInput(plb, LOWORD(wParam), fAnsi); break; case LB_GETSELITEMS: case LB_GETSELCOUNT: /* * IanJa/Win32 should this be LPWORD now? */ return LBoxGetSelItems(plb, (message == LB_GETSELCOUNT), (INT)wParam, (LPINT)lParam); case LB_SETTABSTOPS: /* * IanJa/Win32: Tabs given by array of INT for backwards compatability */ return LBSetTabStops(plb, (INT)wParam, (LPINT)lParam); case LB_GETHORIZONTALEXTENT: /* * Return the max width of the listbox used for horizontal scrolling */ return plb->maxWidth; case LB_SETHORIZONTALEXTENT: /* * Set the max width of the listbox used for horizontal scrolling */ if (plb->maxWidth != (INT)wParam) { plb->maxWidth = (INT)wParam; /* * When horizontal extent is set, Show/hide the scroll bars. * NOTE: LBShowHideScrollBars() takes care if Redraw is OFF. * Fix for Bug #2477 -- 01/14/91 -- SANKAR -- */ xxxLBShowHideScrollBars(plb); //Try to show or hide scroll bars if (plb->fHorzBar && plb->fRightAlign && !(plb->fMultiColumn || plb->OwnerDraw)) { /* * origin to right */ xxxLBoxCtlHScroll(plb, SB_BOTTOM, 0); } } break; /* originally returned register ax (message) ! */ case LB_SETCOLUMNWIDTH: /* * Set the width of a column in a multicolumn listbox */ plb->cxColumn = (INT)wParam; LBCalcItemRowsAndColumns(plb); if (IsLBoxVisible(plb)) NtUserInvalidateRect(hwnd, NULL, TRUE); xxxLBShowHideScrollBars(plb); break; case LB_SETANCHORINDEX: if ((INT)wParam >= plb->cMac) { RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE,"Invalid index passed to LB_SETANCHORINDEX"); return LB_ERR; } plb->iMouseDown = (INT)wParam; plb->iLastMouseMove = (INT)wParam; xxxInsureVisible(plb, (int) wParam, (BOOL)(lParam != 0)); break; case LB_GETANCHORINDEX: return plb->iMouseDown; case LB_SETCARETINDEX: if ( (plb->iSel == -1) || ((plb->wMultiple != SINGLESEL) && (plb->cMac > (INT)wParam))) { /* * Set's the iSelBase to the wParam * if lParam, then don't scroll if partially visible * else scroll into view if not fully visible */ xxxInsureVisible(plb, (INT)wParam, (BOOL)LOWORD(lParam)); xxxSetISelBase(plb, (INT)wParam); break; } else { if ((INT)wParam >= plb->cMac) { RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE,"Invalid index passed to LB_SETCARETINDEX"); } return LB_ERR; } break; case LB_GETCARETINDEX: return plb->iSelBase; case LB_SETITEMHEIGHT: case LB_GETITEMHEIGHT: return LBGetSetItemHeightHandler(plb, message, (INT)wParam, LOWORD(lParam)); break; case LB_FINDSTRINGEXACT: lReturn = xxxFindString(plb, (LPWSTR)lParam, (INT)wParam, EQ, TRUE); break; case LB_ITEMFROMPOINT: { POINT pt; BOOL bOutside; DWORD dwItem; POINTSTOPOINT(pt, lParam); bOutside = ISelFromPt(plb, pt, &dwItem); UserAssert(bOutside == 1 || bOutside == 0); return (LRESULT)MAKELONG(dwItem, bOutside); } case LBCB_CARETON: /* * Internal message for combo box support */ CaretCreate(plb); // Set up the caret in the proper location for drop downs. plb->iSelBase = plb->iSel; xxxLBSetCaret(plb, TRUE); if (FWINABLE()) { if (_IsWindowVisible(pwnd)) { LBEvent(plb, EVENT_OBJECT_FOCUS, plb->iSelBase); } } return(plb->iSel); case LBCB_CARETOFF: /* * Internal message for combo box support */ xxxLBSetCaret(plb, FALSE); xxxCaretDestroy(plb); break; case WM_NCCREATE: if ((pwnd->style & LBS_MULTICOLUMN) && (pwnd->style & WS_VSCROLL)) { DWORD mask = WS_VSCROLL; DWORD flags = 0; if (!TestWF(pwnd, WFWIN40COMPAT)) { mask |= WS_HSCROLL; flags = WS_HSCROLL; } NtUserAlterWindowStyle(hwnd, mask, flags); } goto CallDWP; default: CallDWP: return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi); } /* * Handle translation of ANSI output data and free buffer */ if (lpwsz) { UserLocalFree(lpwsz); } return lReturn; }