You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1781 lines
51 KiB
1781 lines
51 KiB
/***************************** Module Header ******************************\
|
|
* Module Name: ntcftxt.h
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Kernel call forward stubs with text arguments
|
|
*
|
|
* Each function will be created with two flavors Ansi and Unicode
|
|
*
|
|
* 06-Jan-1992 IanJa Moved from cf.h
|
|
* 18-Mar-1995 JimA Ported from cftxt.h
|
|
\**************************************************************************/
|
|
|
|
#ifdef UNICODE
|
|
#define IS_ANSI FALSE
|
|
#ifndef _UNICODE
|
|
#define _UNICODE
|
|
#endif
|
|
#else
|
|
#define IS_ANSI TRUE
|
|
#undef _UNICODE
|
|
#endif
|
|
#include <tchar.h>
|
|
#include "ntsend.h"
|
|
|
|
HWND TEXT_FN(InternalFindWindowEx)(
|
|
HWND hwndParent,
|
|
HWND hwndChild,
|
|
LPCTSTR pClassName,
|
|
LPCTSTR pWindowName,
|
|
DWORD dwFlag)
|
|
{
|
|
IN_STRING strClass;
|
|
IN_STRING strWindow;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strClass.fAllocated = FALSE;
|
|
strWindow.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
FIRSTCOPYLPTSTRIDOPT(&strClass, pClassName);
|
|
COPYLPTSTROPT(&strWindow, pWindowName);
|
|
|
|
retval = (ULONG_PTR)NtUserFindWindowEx(
|
|
hwndParent,
|
|
hwndChild,
|
|
strClass.pstr,
|
|
strWindow.pstr,
|
|
dwFlag);
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPTSTR(strClass);
|
|
CLEANUPLPTSTR(strWindow);
|
|
ENDCALL(HWND);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG4(LOG_GENERAL, HWND, WINUSERAPI, FindWindowExW, HWND, hwndParent, HWND, hwndChild, LPCTSTR, pClassName, LPCTSTR, pWindowName)
|
|
#else
|
|
FUNCLOG4(LOG_GENERAL, HWND, WINUSERAPI, FindWindowExA, HWND, hwndParent, HWND, hwndChild, LPCTSTR, pClassName, LPCTSTR, pWindowName)
|
|
#endif // UNICODE
|
|
HWND FindWindowEx(
|
|
HWND hwndParent,
|
|
HWND hwndChild,
|
|
LPCTSTR pClassName,
|
|
LPCTSTR pWindowName)
|
|
{
|
|
return TEXT_FN(InternalFindWindowEx)(hwndParent, hwndChild, pClassName, pWindowName, FW_BOTH);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG2(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, FindWindowW, LPCTSTR, pClassName, LPCTSTR, pWindowName)
|
|
#else
|
|
FUNCLOG2(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, FindWindowA, LPCTSTR, pClassName, LPCTSTR, pWindowName)
|
|
#endif // UNICODE
|
|
|
|
HWND FindWindow(
|
|
LPCTSTR pClassName,
|
|
LPCTSTR pWindowName)
|
|
{
|
|
return TEXT_FN(InternalFindWindowEx)(NULL, NULL, pClassName, pWindowName, FW_BOTH);
|
|
}
|
|
|
|
BOOL GetClassInfoEx(
|
|
HINSTANCE hmod,
|
|
LPCTSTR pszClassName,
|
|
LPWNDCLASSEX pwc)
|
|
{
|
|
IN_STRING strClassName;
|
|
LPWSTR pszMenuName;
|
|
DWORD Error;
|
|
HMODULE hDllMod = NULL;
|
|
|
|
#ifdef LAZY_CLASS_INIT
|
|
LazyInitClasses();
|
|
#endif
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully.
|
|
*/
|
|
strClassName.fAllocated = FALSE;
|
|
|
|
BEGINCALL_CLASSV()
|
|
|
|
FIRSTCOPYLPTSTRID(&strClassName, lpClassNameVer);
|
|
|
|
TryAgain:
|
|
retval = (DWORD)NtUserGetClassInfoEx(hmod,
|
|
strClassName.pstr,
|
|
(LPWNDCLASSEXW)pwc,
|
|
&pszMenuName,
|
|
IS_ANSI);
|
|
|
|
/*
|
|
* If we failed to find the class specified, let's register it and
|
|
* try again.
|
|
*/
|
|
if (!retval &&
|
|
!bRegistered &&
|
|
lpDllName != NULL &&
|
|
((Error = NtCurrentTeb()->LastErrorValue) == ERROR_CANNOT_FIND_WND_CLASS
|
|
|| Error == ERROR_CLASS_DOES_NOT_EXIST)) {
|
|
|
|
IN_STRING strClassNameNoVer;
|
|
FIRSTCOPYLPTSTRID(&strClassNameNoVer, pszClassName);
|
|
bRegistered = VersionRegisterClass(strClassNameNoVer.pstr->Buffer, lpDllName, lpActivationContext, &hDllMod);
|
|
CLEANUPLPTSTR(strClassNameNoVer);
|
|
if (bRegistered) {
|
|
goto TryAgain;
|
|
}
|
|
}
|
|
|
|
if (!retval && hDllMod != NULL) {
|
|
FREE_LIBRARY_SAVE_ERROR(hDllMod);
|
|
hDllMod = NULL;
|
|
}
|
|
|
|
if (lpActivationContext != NULL) {
|
|
RtlReleaseActivationContext(lpActivationContext);
|
|
lpActivationContext = NULL;
|
|
}
|
|
|
|
if (retval) {
|
|
/*
|
|
* Update these pointers so they point to something real.
|
|
* pszMenuName is actually just the pointer the app originally
|
|
* passed to us.
|
|
*/
|
|
pwc->lpszMenuName = (LPTSTR)pszMenuName;
|
|
pwc->lpszClassName = pszClassName;
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPTSTR(strClassName);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
BOOL GetClassInfo(
|
|
HINSTANCE hmod,
|
|
LPCTSTR pszClassName,
|
|
LPWNDCLASS pwc)
|
|
{
|
|
WNDCLASSEX WndClass;
|
|
BOOL retval;
|
|
|
|
retval = GetClassInfoEx(hmod, pszClassName, &WndClass);
|
|
if (retval) {
|
|
/*
|
|
* Move the info from the WNDCLASSEX to the WNDCLASS structure. On
|
|
* 64-bit plaforms we'll have 32 bits of padding between style and
|
|
* lpfnWndProc in WNDCLASS, so start the copy from the first 64-bit
|
|
* aligned field and hand copy the rest.
|
|
*/
|
|
RtlCopyMemory(&(pwc->lpfnWndProc),
|
|
&(WndClass.lpfnWndProc),
|
|
sizeof(WNDCLASS) - FIELD_OFFSET(WNDCLASS, lpfnWndProc));
|
|
pwc->style = WndClass.style;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG3(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetClipboardFormatNameW, UINT, wFormat, LPTSTR, pFormatName, int, chMaxCount)
|
|
#else
|
|
FUNCLOG3(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetClipboardFormatNameA, UINT, wFormat, LPTSTR, pFormatName, int, chMaxCount)
|
|
#endif // UNICODE
|
|
int GetClipboardFormatName(
|
|
UINT wFormat,
|
|
LPTSTR pFormatName,
|
|
int chMaxCount)
|
|
{
|
|
LPWSTR lpszReserve;
|
|
|
|
BEGINCALL()
|
|
|
|
#ifdef UNICODE
|
|
lpszReserve = pFormatName;
|
|
#else
|
|
lpszReserve = UserLocalAlloc(0, chMaxCount * sizeof(WCHAR));
|
|
if (!lpszReserve) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
retval = (DWORD)NtUserGetClipboardFormatName(wFormat,
|
|
lpszReserve,
|
|
chMaxCount);
|
|
|
|
#ifndef UNICODE
|
|
if (retval) {
|
|
/*
|
|
* Do not copy out more than the requested byte count 'chMaxCount'.
|
|
* Set retval to reflect the number of ANSI bytes.
|
|
*/
|
|
retval = WCSToMB(lpszReserve,
|
|
(UINT)retval,
|
|
&pFormatName,
|
|
chMaxCount - 1,
|
|
FALSE);
|
|
pFormatName[retval] = '\0';
|
|
}
|
|
UserLocalFree(lpszReserve);
|
|
#endif
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(int);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG3(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetKeyNameTextW, LONG, lParam, LPTSTR, pString, int, cchSize)
|
|
#else
|
|
FUNCLOG3(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetKeyNameTextA, LONG, lParam, LPTSTR, pString, int, cchSize)
|
|
#endif // UNICODE
|
|
int GetKeyNameText(
|
|
LONG lParam,
|
|
LPTSTR pString,
|
|
int cchSize)
|
|
{
|
|
LPWSTR lpszReserve;
|
|
|
|
BEGINCALL()
|
|
|
|
#ifdef UNICODE
|
|
lpszReserve = pString;
|
|
#else
|
|
lpszReserve = UserLocalAlloc(0, cchSize * sizeof(WCHAR));
|
|
if (!lpszReserve) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
retval = (DWORD)NtUserGetKeyNameText(
|
|
lParam,
|
|
lpszReserve,
|
|
cchSize);
|
|
|
|
#ifndef UNICODE
|
|
if (retval) {
|
|
/*
|
|
* Do not copy out more than the requested byte count 'nSize'.
|
|
* Set retval to reflect the number of ANSI bytes.
|
|
*/
|
|
retval = WCSToMB(lpszReserve,
|
|
(UINT)retval,
|
|
&pString,
|
|
cchSize - 1,
|
|
FALSE);
|
|
}
|
|
UserLocalFree(lpszReserve);
|
|
((LPSTR)pString)[retval] = '\0';
|
|
#endif
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(int);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, GetMessageW, LPMSG, pmsg, HWND, hwnd, UINT, wMsgFilterMin, UINT, wMsgFilterMax)
|
|
#else
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, GetMessageA, LPMSG, pmsg, HWND, hwnd, UINT, wMsgFilterMin, UINT, wMsgFilterMax)
|
|
#endif // UNICODE
|
|
BOOL APIENTRY GetMessage(
|
|
LPMSG pmsg,
|
|
HWND hwnd,
|
|
UINT wMsgFilterMin,
|
|
UINT wMsgFilterMax)
|
|
{
|
|
BEGINCALL()
|
|
|
|
/*
|
|
* Prevent apps from setting hi 16 bits so we can use them internally.
|
|
*/
|
|
if ((wMsgFilterMin | wMsgFilterMax) & RESERVED_MSG_BITS) {
|
|
/*
|
|
* Backward compatability with Win9x where someone is setting
|
|
* wMsgFilterMax to -1 to get all the messages.
|
|
*/
|
|
if (wMsgFilterMax == (UINT)-1 && !(wMsgFilterMin & RESERVED_MSG_BITS)) {
|
|
wMsgFilterMax = 0;
|
|
} else {
|
|
MSGERRORCODE(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
/*
|
|
* If we have pushed message for DBCS messaging, we should pass this one
|
|
* to Apps at first...
|
|
*/
|
|
GET_DBCS_MESSAGE_IF_EXIST(GetMessage, pmsg, wMsgFilterMin, wMsgFilterMax, TRUE);
|
|
#endif
|
|
|
|
retval = (DWORD)NtUserGetMessage(
|
|
pmsg,
|
|
hwnd,
|
|
wMsgFilterMin,
|
|
wMsgFilterMax);
|
|
|
|
#ifndef UNICODE
|
|
// May have a bit more work to do if this MSG is for an ANSI app
|
|
|
|
// !!! LATER if the unichar translates into multiple ANSI chars
|
|
// !!! then what??? Divide into two messages?? WM_SYSDEADCHAR??
|
|
|
|
if (RtlWCSMessageWParamCharToMB(pmsg->message, &(pmsg->wParam))) {
|
|
WPARAM dwAnsi = pmsg->wParam;
|
|
/*
|
|
* Build DBCS-ware wParam. (for EM_SETPASSWORDCHAR...)
|
|
*/
|
|
BUILD_DBCS_MESSAGE_TO_CLIENTA_FROM_SERVER(pmsg, dwAnsi, TRUE, TRUE);
|
|
} else {
|
|
retval = 0;
|
|
}
|
|
ExitGetMessage:
|
|
#else
|
|
/*
|
|
* Only LOWORD of WPARAM is valid for WM_CHAR (Unicode)....
|
|
* (Mask off DBCS messaging information.)
|
|
*/
|
|
BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_SERVER(pmsg->message,pmsg->wParam);
|
|
#endif // UNICODE
|
|
|
|
#if DBG && defined(GENERIC_INPUT)
|
|
// TEST PURPOSE ONLY
|
|
if (pmsg->message == WM_INPUT) {
|
|
TAGMSG3(DBGTAG_PNP, "GetMessage: WM_INPUT, hwnd=%p, wp=%04x, lp=%08x", pmsg->hwnd, pmsg->wParam, pmsg->lParam);
|
|
}
|
|
#endif // GENERIC_INPUT
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, GetKeyboardLayoutNameW, LPTSTR, pwszKL)
|
|
#else
|
|
FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, GetKeyboardLayoutNameA, LPTSTR, pwszKL)
|
|
#endif // UNICODE
|
|
BOOL GetKeyboardLayoutName(
|
|
LPTSTR pwszKL)
|
|
{
|
|
#ifdef UNICODE
|
|
UNICODE_STRING str;
|
|
PUNICODE_STRING pstr = &str;
|
|
#else
|
|
PUNICODE_STRING pstr = &NtCurrentTeb()->StaticUnicodeString;
|
|
#endif
|
|
|
|
BEGINCALL()
|
|
|
|
#ifdef UNICODE
|
|
str.MaximumLength = KL_NAMELENGTH * sizeof(WCHAR);
|
|
str.Buffer = pwszKL;
|
|
#endif
|
|
|
|
retval = (DWORD)NtUserGetKeyboardLayoutName(pstr);
|
|
|
|
#ifndef UNICODE
|
|
if (retval) {
|
|
/*
|
|
* Non-zero retval means some text to copy out. Do not copy out
|
|
* more than the requested byte count 'chMaxCount'.
|
|
*/
|
|
WCSToMB(pstr->Buffer, -1, &pwszKL, KL_NAMELENGTH, FALSE);
|
|
}
|
|
#endif
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG2(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, MapVirtualKeyW, UINT, wCode, UINT, wMapType)
|
|
#else
|
|
FUNCLOG2(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, MapVirtualKeyA, UINT, wCode, UINT, wMapType)
|
|
#endif // UNICODE
|
|
|
|
UINT MapVirtualKey(
|
|
UINT wCode,
|
|
UINT wMapType)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserMapVirtualKeyEx(
|
|
wCode,
|
|
wMapType,
|
|
0,
|
|
FALSE);
|
|
|
|
#ifndef UNICODE
|
|
if ((wMapType == 2) && (retval != 0)) {
|
|
WCHAR wch = LOWORD(retval);
|
|
retval &= ~0xFFFF;
|
|
RtlUnicodeToMultiByteN((LPSTR)&(retval), sizeof(CHAR),
|
|
NULL, &wch, sizeof(WCHAR));
|
|
}
|
|
#endif
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(UINT);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* MapVirtualKeyEx
|
|
*
|
|
* 21-Feb-1995 GregoryW Created
|
|
\**************************************************************************/
|
|
|
|
#ifndef UNICODE
|
|
static HKL hMVKCachedHKL = 0;
|
|
static UINT uMVKCachedCP = 0;
|
|
#endif
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG3(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, MapVirtualKeyExW, UINT, wCode, UINT, wMapType, HKL, hkl)
|
|
#else
|
|
FUNCLOG3(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, MapVirtualKeyExA, UINT, wCode, UINT, wMapType, HKL, hkl)
|
|
#endif // UNICODE
|
|
|
|
UINT MapVirtualKeyEx(
|
|
UINT wCode,
|
|
UINT wMapType,
|
|
HKL hkl)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserMapVirtualKeyEx(
|
|
wCode,
|
|
wMapType,
|
|
(ULONG_PTR)hkl,
|
|
TRUE);
|
|
|
|
#ifndef UNICODE
|
|
if ((wMapType == 2) && (retval != 0)) {
|
|
WCHAR wch = LOWORD(retval);
|
|
|
|
if (hkl != hMVKCachedHKL) {
|
|
DWORD dwCodePage;
|
|
if (!GetLocaleInfoW(
|
|
HandleToUlong(hkl) & 0xffff,
|
|
LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
|
|
(LPWSTR)&dwCodePage,
|
|
sizeof(dwCodePage) / sizeof(WCHAR)
|
|
)) {
|
|
MSGERROR();
|
|
}
|
|
uMVKCachedCP = dwCodePage;
|
|
hMVKCachedHKL = hkl;
|
|
}
|
|
/*
|
|
* Clear low word which contains Unicode character returned from server.
|
|
* This preserves the high word which is used to indicate dead key status.
|
|
*/
|
|
retval = retval & 0xffff0000;
|
|
if (!WideCharToMultiByte(
|
|
uMVKCachedCP,
|
|
0,
|
|
&wch,
|
|
1,
|
|
(LPSTR)&(retval),
|
|
1,
|
|
NULL,
|
|
NULL)) {
|
|
MSGERROR();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(UINT);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, PostMessageW , HWND, hwnd, UINT, wMsg, WPARAM, wParam, LPARAM, lParam)
|
|
#else
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, PostMessageA , HWND, hwnd, UINT, wMsg, WPARAM, wParam, LPARAM, lParam)
|
|
#endif // UNICODE
|
|
BOOL APIENTRY PostMessage(
|
|
HWND hwnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
BEGINCALL()
|
|
|
|
switch (wMsg) {
|
|
case WM_DROPFILES:
|
|
if (GetWindowProcess(hwnd) != GETPROCESSID()) {
|
|
/*
|
|
* We first send a WM_COPYGLOBALDATA message to get the data into the proper
|
|
* context.
|
|
*/
|
|
HGLOBAL hg;
|
|
|
|
hg = (HGLOBAL)SendMessage(hwnd, WM_COPYGLOBALDATA,
|
|
GlobalSize((HGLOBAL)wParam), wParam);
|
|
if (!hg) {
|
|
MSGERROR();
|
|
}
|
|
wParam = (WPARAM)hg;
|
|
}
|
|
break;
|
|
|
|
case LB_DIR:
|
|
case CB_DIR:
|
|
/*
|
|
* Make sure this bit is set so the client side string gets
|
|
* successfully copied over.
|
|
*/
|
|
wParam |= DDL_POSTMSGS;
|
|
break;
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
/*
|
|
* Setup DBCS Messaging for WM_CHAR...
|
|
*/
|
|
BUILD_DBCS_MESSAGE_TO_SERVER_FROM_CLIENTA(wMsg,wParam,TRUE);
|
|
|
|
RtlMBMessageWParamCharToWCS(wMsg, &wParam);
|
|
#endif
|
|
retval = (DWORD)NtUserPostMessage(
|
|
hwnd,
|
|
wMsg,
|
|
wParam,
|
|
lParam);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, PostThreadMessageW, DWORD, idThread, UINT, msg, WPARAM, wParam, LPARAM, lParam)
|
|
#else
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, PostThreadMessageA, DWORD, idThread, UINT, msg, WPARAM, wParam, LPARAM, lParam)
|
|
#endif // UNICODE
|
|
BOOL APIENTRY PostThreadMessage(
|
|
DWORD idThread,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
BEGINCALL()
|
|
|
|
#ifndef UNICODE
|
|
#ifdef FE_SB // PostThreadMessage()
|
|
/*
|
|
* The server always expects the characters to be unicode so
|
|
* if this was generated from an ANSI routine convert it to Unicode
|
|
*/
|
|
BUILD_DBCS_MESSAGE_TO_SERVER_FROM_CLIENTA(msg,wParam,TRUE);
|
|
#endif // FE_SB
|
|
|
|
RtlMBMessageWParamCharToWCS(msg, &wParam);
|
|
#endif
|
|
|
|
retval = (DWORD)NtUserPostThreadMessage(
|
|
idThread,
|
|
msg,
|
|
wParam,
|
|
lParam);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* StringDuplicate
|
|
*
|
|
* 03-25-96 GerardoB Added Header.
|
|
\**************************************************************************/
|
|
#define StringDuplicate TEXT_FN(StringDuplicate)
|
|
LPTSTR StringDuplicate(LPCTSTR ptszDup) {
|
|
LPTSTR ptsz;
|
|
ULONG cb;
|
|
|
|
cb = (_tcslen(ptszDup) + 1) * sizeof(TCHAR);
|
|
ptsz = UserLocalAlloc(0, cb);
|
|
if (ptsz != NULL) {
|
|
RtlCopyMemory(ptsz, ptszDup, cb);
|
|
}
|
|
return ptsz;
|
|
}
|
|
/**************************************************************************\
|
|
* InitClsMenuName
|
|
*
|
|
* 03-22-96 GerardoB Created.
|
|
\**************************************************************************/
|
|
#define InitClsMenuName TEXT_FN(InitClsMenuName)
|
|
BOOL InitClsMenuName (PCLSMENUNAME pcmn, LPCTSTR lpszMenuName, PIN_STRING pstrMenuName)
|
|
{
|
|
/*
|
|
* We check the high-word because this may be a resource-ID.
|
|
*/
|
|
if (IS_PTR(lpszMenuName)) {
|
|
#ifdef UNICODE
|
|
if ((pcmn->pwszClientUnicodeMenuName = StringDuplicate(lpszMenuName)) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!WCSToMB(lpszMenuName, -1, &(pcmn->pszClientAnsiMenuName), -1, TRUE)) {
|
|
pcmn->pszClientAnsiMenuName = NULL;
|
|
}
|
|
#else
|
|
if ((pcmn->pszClientAnsiMenuName = StringDuplicate(lpszMenuName)) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!MBToWCS(lpszMenuName, -1, &(pcmn->pwszClientUnicodeMenuName), -1, TRUE)) {
|
|
pcmn->pwszClientUnicodeMenuName = NULL;
|
|
}
|
|
#endif // UNICODE
|
|
} else {
|
|
/* Copy the ID */
|
|
pcmn->pszClientAnsiMenuName = (LPSTR)lpszMenuName;
|
|
pcmn->pwszClientUnicodeMenuName = (LPWSTR)lpszMenuName;
|
|
}
|
|
|
|
COPYLPTSTRID(pstrMenuName, lpszMenuName);
|
|
pcmn->pusMenuName = pstrMenuName->pstr;
|
|
|
|
return TRUE;
|
|
|
|
goto errorexit; /* Keep the compiler happy */
|
|
|
|
errorexit: /* Used by COPYLPTSTRID */
|
|
#ifdef UNICODE
|
|
UserLocalFree(pcmn->pwszClientUnicodeMenuName);
|
|
pcmn->pwszClientUnicodeMenuName = NULL;
|
|
#else
|
|
UserLocalFree(pcmn->pszClientAnsiMenuName);
|
|
pcmn->pszClientAnsiMenuName = NULL;
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* SetClassLong
|
|
*
|
|
* 03-22-96 GerardoB Moved from client\cltxt.h & client\ntstubs.c
|
|
\**************************************************************************/
|
|
#ifdef UNICODE
|
|
FUNCLOG3(LOG_GENERAL, ULONG_PTR, APIENTRY, SetClassLongPtrW, HWND, hwnd, int, nIndex, LONG_PTR, dwNewLong)
|
|
#else
|
|
FUNCLOG3(LOG_GENERAL, ULONG_PTR, APIENTRY, SetClassLongPtrA, HWND, hwnd, int, nIndex, LONG_PTR, dwNewLong)
|
|
#endif // UNICODE
|
|
ULONG_PTR APIENTRY SetClassLongPtr(HWND hwnd, int nIndex, LONG_PTR dwNewLong)
|
|
{
|
|
CLSMENUNAME cmn;
|
|
IN_STRING strMenuName;
|
|
|
|
switch (nIndex) {
|
|
case GCLP_MENUNAME:
|
|
if (!InitClsMenuName(&cmn, (LPCTSTR) dwNewLong, &strMenuName)) {
|
|
RIPERR0(ERROR_INVALID_HANDLE, RIP_WARNING, "SetClassLong: InitClsMenuName failed");
|
|
return 0;
|
|
}
|
|
dwNewLong = (ULONG_PTR) &cmn;
|
|
break;
|
|
|
|
case GCLP_HBRBACKGROUND:
|
|
if ((DWORD)dwNewLong > COLOR_ENDCOLORS) {
|
|
/*
|
|
* Let gdi validate the brush. If it's invalid, then gdi
|
|
* will log a warning. No need to rip twice so we'll just
|
|
* set the last error.
|
|
*/
|
|
if (GdiValidateHandle((HBRUSH)dwNewLong) == FALSE) {
|
|
RIPERR0(ERROR_INVALID_HANDLE, RIP_VERBOSE, "");
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
BEGINCALL()
|
|
|
|
retval = (ULONG_PTR)NtUserSetClassLongPtr(hwnd, nIndex, dwNewLong, IS_ANSI);
|
|
|
|
ERRORTRAP(0);
|
|
|
|
/* Clean up */
|
|
switch (nIndex) {
|
|
case GCLP_MENUNAME:
|
|
CLEANUPLPTSTR(strMenuName); /* Initialized by InitClsMenuName */
|
|
/*
|
|
* We free either the old strings (returned by the kernel),
|
|
* or the new ones if the kernel call failed
|
|
*/
|
|
if (IS_PTR(cmn.pszClientAnsiMenuName)) {
|
|
UserLocalFree(KPVOID_TO_PVOID(cmn.pszClientAnsiMenuName));
|
|
}
|
|
if (IS_PTR(cmn.pwszClientUnicodeMenuName)) {
|
|
UserLocalFree(KPVOID_TO_PVOID(cmn.pwszClientUnicodeMenuName));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
ENDCALL(ULONG_PTR);
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
DWORD APIENTRY SetClassLong(HWND hwnd, int nIndex, LONG dwNewLong)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserSetClassLong(hwnd, nIndex, dwNewLong, IS_ANSI);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(DWORD);
|
|
}
|
|
#endif
|
|
|
|
/**************************************************************************\
|
|
* RegisterClassExWOW
|
|
*
|
|
* 03-22-96 GerardoB Added Header
|
|
\**************************************************************************/
|
|
ATOM TEXT_FN(RegisterClassExWOW)(
|
|
WNDCLASSEX *lpWndClass,
|
|
LPDWORD pdwWOWstuff,
|
|
WORD fnid,
|
|
DWORD dwFlags)
|
|
{
|
|
WNDCLASSEX WndClass;
|
|
IN_STRING strClassName;
|
|
IN_STRING strClassNameVer;
|
|
IN_STRING strMenuName;
|
|
DWORD dwExpWinVer;
|
|
CLSMENUNAME cmn;
|
|
TCHAR ClassNameVer[MAX_ATOM_LEN];
|
|
LPTSTR lpClassNameVer;
|
|
PACTIVATION_CONTEXT lpActivationContext = NULL;
|
|
|
|
#ifdef LAZY_CLASS_INIT
|
|
LazyInitClasses();
|
|
#endif
|
|
|
|
strClassName.fAllocated = 0;
|
|
strClassNameVer.fAllocated = 0;
|
|
strMenuName.fAllocated = 0;
|
|
|
|
/*
|
|
* Skip validation for our classes
|
|
*/
|
|
if (fnid != 0) {
|
|
/*
|
|
* This is a hack to bypass validation for DDE classes
|
|
* specifically, allow them to use hmodUser.
|
|
*/
|
|
if (fnid == FNID_DDE_BIT) {
|
|
fnid = 0;
|
|
}
|
|
dwExpWinVer = VER40;
|
|
} else {
|
|
if (lpWndClass->cbSize != sizeof(WNDCLASSEX)) {
|
|
RIPMSG0(RIP_WARNING, "RegisterClass: Invalid cbSize");
|
|
}
|
|
|
|
if (lpWndClass->cbClsExtra < 0 || lpWndClass->cbWndExtra < 0) {
|
|
RIPMSG0(RIP_WARNING, "RegisterClass: invalid cb*Extra");
|
|
goto BadParameter;
|
|
}
|
|
|
|
/*
|
|
* Validate hInstance
|
|
* Don't allow 4.0 apps to use hmodUser
|
|
*/
|
|
if ((lpWndClass->hInstance == hmodUser)
|
|
&& (GetClientInfo()->dwExpWinVer >= VER40)) {
|
|
RIPMSG0(RIP_WARNING, "RegisterClass: Cannot use USER's hInstance");
|
|
goto BadParameter;
|
|
} else if (lpWndClass->hInstance == NULL) {
|
|
/*
|
|
* For 32 bit apps we need to fix up the hInstance because Win 95 does
|
|
* this in their thunk MapHInstLS
|
|
*/
|
|
|
|
lpWndClass->hInstance = GetModuleHandle(NULL);
|
|
RIPMSG1(RIP_VERBOSE, "RegisterClass: fixing up NULL hmodule to %#p",
|
|
lpWndClass->hInstance);
|
|
}
|
|
|
|
dwExpWinVer = GETEXPWINVER(lpWndClass->hInstance);
|
|
|
|
|
|
/*
|
|
* Check for valid style bits and strip if appropriate
|
|
*/
|
|
if (lpWndClass->style & ~CS_VALID40) {
|
|
|
|
if (dwExpWinVer > VER31) {
|
|
RIPMSG0(RIP_WARNING, "RegisterClass: Invalid class style");
|
|
goto BadParameter;
|
|
}
|
|
|
|
/*
|
|
* Old application - strip bogus bits and pass through
|
|
*/
|
|
RIPMSG0(RIP_WARNING, "RegisterClass: Invalid class style, stripping bad styles");
|
|
lpWndClass->style &= CS_VALID40;
|
|
}
|
|
|
|
/*
|
|
* Validate hbrBackground
|
|
*/
|
|
if (lpWndClass->hbrBackground > (HBRUSH)COLOR_MAX
|
|
&& !GdiValidateHandle(lpWndClass->hbrBackground)) {
|
|
|
|
RIPMSG1(RIP_WARNING, "RegisterClass: Invalid class brush:%#p", lpWndClass->hbrBackground);
|
|
if (dwExpWinVer > VER30) {
|
|
goto BadParameter;
|
|
}
|
|
|
|
lpWndClass->hbrBackground = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if (!InitClsMenuName(&cmn, lpWndClass->lpszMenuName, &strMenuName)) {
|
|
return FALSE;
|
|
}
|
|
|
|
BEGINCALL()
|
|
WndClass = *lpWndClass;
|
|
|
|
#ifndef UNICODE
|
|
dwFlags |= CSF_ANSIPROC;
|
|
#endif // UNICODE
|
|
|
|
if (dwExpWinVer > VER31) {
|
|
dwFlags |= CSF_WIN40COMPAT;
|
|
}
|
|
|
|
if (GetClientInfo()->dwTIFlags & TIF_16BIT) {
|
|
/*
|
|
* No Fusion redirection for 16BIT apps.
|
|
*/
|
|
if (!(GetAppCompatFlags2(VERMAX) & GACF2_FORCEFUSION)) {
|
|
dwFlags &= ~CW_FLAGS_VERSIONCLASS;
|
|
}
|
|
}
|
|
|
|
if (dwFlags & CSF_VERSIONCLASS) {
|
|
lpClassNameVer = (LPTSTR)ClassNameToVersion((LPCWSTR)lpWndClass->lpszClassName, (LPWSTR)ClassNameVer, NULL, NULL, IS_ANSI);
|
|
|
|
if (lpClassNameVer == NULL) {
|
|
RIPMSG0(RIP_WARNING, "RegisterClass: Couldn't resolve class name");
|
|
MSGERROR();
|
|
}
|
|
} else {
|
|
lpClassNameVer = (LPTSTR)lpWndClass->lpszClassName;
|
|
}
|
|
|
|
COPYLPTSTRID(&strClassName, (LPTSTR)lpWndClass->lpszClassName);
|
|
COPYLPTSTRID(&strClassNameVer, (LPTSTR)lpClassNameVer);
|
|
|
|
retval = NtUserRegisterClassExWOW(
|
|
&WndClass,
|
|
strClassName.pstr,
|
|
strClassNameVer.pstr,
|
|
&cmn,
|
|
fnid,
|
|
dwFlags,
|
|
pdwWOWstuff);
|
|
|
|
/*
|
|
* Return the atom associated with this class or if earlier
|
|
* than Win 3.1 convert it to a strict BOOL (some apps check)
|
|
*/
|
|
if (GETEXPWINVER(lpWndClass->hInstance) < VER31)
|
|
retval = !!retval;
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPTSTR(strMenuName); /* Initialized by InitClsMenuName */
|
|
CLEANUPLPTSTR(strClassName);
|
|
CLEANUPLPTSTR(strClassNameVer);
|
|
|
|
if (lpActivationContext != NULL) {
|
|
RtlReleaseActivationContext(lpActivationContext);
|
|
lpActivationContext = NULL;
|
|
}
|
|
|
|
if (!retval) {
|
|
if (IS_PTR(cmn.pszClientAnsiMenuName)) {
|
|
UserLocalFree(KPVOID_TO_PVOID(cmn.pszClientAnsiMenuName));
|
|
}
|
|
if (IS_PTR(cmn.pwszClientUnicodeMenuName)) {
|
|
UserLocalFree(KPVOID_TO_PVOID(cmn.pwszClientUnicodeMenuName));
|
|
}
|
|
}
|
|
ENDCALL(BOOL);
|
|
|
|
BadParameter:
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "RegisterClass: Invalid Parameter");
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG1(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, RegisterWindowMessageW , LPCTSTR, pString)
|
|
#else
|
|
FUNCLOG1(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, RegisterWindowMessageA , LPCTSTR, pString)
|
|
#endif // UNICODE
|
|
UINT RegisterWindowMessage(
|
|
LPCTSTR pString)
|
|
{
|
|
IN_STRING str;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
str.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
FIRSTCOPYLPTSTR(&str, (LPTSTR)pString);
|
|
|
|
retval = (DWORD)NtUserRegisterWindowMessage(
|
|
str.pstr);
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPTSTR(str);
|
|
ENDCALL(UINT);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG2(LOG_GENERAL, HANDLE, DUMMYCALLINGTYPE, RemovePropW , HWND, hwnd, LPCTSTR, pString)
|
|
#else
|
|
FUNCLOG2(LOG_GENERAL, HANDLE, DUMMYCALLINGTYPE, RemovePropA , HWND, hwnd, LPCTSTR, pString)
|
|
#endif // UNICODE
|
|
|
|
HANDLE RemoveProp(
|
|
HWND hwnd,
|
|
LPCTSTR pString)
|
|
{
|
|
ATOM atomProp;
|
|
DWORD dwProp;
|
|
|
|
BEGINCALL()
|
|
|
|
if (IS_PTR(pString)) {
|
|
atomProp = GlobalFindAtom(pString);
|
|
if (atomProp == 0)
|
|
MSGERROR();
|
|
dwProp = MAKELONG(atomProp, TRUE);
|
|
} else
|
|
dwProp = MAKELONG(PTR_TO_ID(pString), FALSE);
|
|
|
|
retval = (ULONG_PTR)NtUserRemoveProp(
|
|
hwnd,
|
|
dwProp);
|
|
|
|
if (retval != 0 && IS_PTR(pString))
|
|
GlobalDeleteAtom(atomProp);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(HANDLE);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG6(LOG_GENERAL, BOOL, APIENTRY, SendMessageCallbackW, HWND, hwnd, UINT, wMsg, WPARAM, wParam, LPARAM, lParam, SENDASYNCPROC, lpResultCallBack, ULONG_PTR, dwData)
|
|
#else
|
|
FUNCLOG6(LOG_GENERAL, BOOL, APIENTRY, SendMessageCallbackA, HWND, hwnd, UINT, wMsg, WPARAM, wParam, LPARAM, lParam, SENDASYNCPROC, lpResultCallBack, ULONG_PTR, dwData)
|
|
#endif // UNICODE
|
|
BOOL APIENTRY SendMessageCallback(
|
|
HWND hwnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
SENDASYNCPROC lpResultCallBack,
|
|
ULONG_PTR dwData)
|
|
{
|
|
SNDMSGCALLBACK smcb;
|
|
|
|
BEGINCALL()
|
|
|
|
smcb.dwData = dwData;
|
|
smcb.lpResultCallBack = lpResultCallBack;
|
|
|
|
retval = (DWORD)CsSendMessage(hwnd, wMsg, wParam, lParam,
|
|
(ULONG_PTR)&smcb, FNID_SENDMESSAGECALLBACK, IS_ANSI);
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, SendNotifyMessageW , HWND, hwnd, UINT, wMsg, WPARAM, wParam, LPARAM, lParam)
|
|
#else
|
|
FUNCLOG4(LOG_GENERAL, BOOL, APIENTRY, SendNotifyMessageA , HWND, hwnd, UINT, wMsg, WPARAM, wParam, LPARAM, lParam)
|
|
#endif // UNICODE
|
|
|
|
BOOL APIENTRY SendNotifyMessage(
|
|
HWND hwnd,
|
|
UINT wMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)CsSendMessage(hwnd, wMsg, wParam, lParam,
|
|
0L, FNID_SENDNOTIFYMESSAGE, IS_ANSI);
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetPropW , HWND, hwnd, LPCTSTR, pString, HANDLE, hData)
|
|
#else
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetPropA , HWND, hwnd, LPCTSTR, pString, HANDLE, hData)
|
|
#endif // UNICODE
|
|
|
|
BOOL SetProp(
|
|
HWND hwnd,
|
|
LPCTSTR pString,
|
|
HANDLE hData)
|
|
{
|
|
ATOM atomProp;
|
|
DWORD dwProp;
|
|
|
|
BEGINCALL()
|
|
|
|
if (IS_PTR(pString)) {
|
|
atomProp = GlobalAddAtom(pString);
|
|
if (atomProp == 0)
|
|
MSGERROR();
|
|
dwProp = MAKELONG(atomProp, TRUE);
|
|
} else
|
|
dwProp = MAKELONG(PTR_TO_ID(pString), FALSE);
|
|
|
|
retval = (DWORD)NtUserSetProp(
|
|
hwnd,
|
|
dwProp,
|
|
hData);
|
|
|
|
/*
|
|
* If it failed, get rid of the atom
|
|
*/
|
|
if (retval == FALSE && IS_PTR(pString))
|
|
GlobalDeleteAtom(atomProp);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, UnregisterClassW, LPCTSTR, pszClassName, HINSTANCE, hModule)
|
|
#else
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, UnregisterClassA, LPCTSTR, pszClassName, HINSTANCE, hModule)
|
|
#endif // UNICODE
|
|
BOOL UnregisterClass(
|
|
LPCTSTR pszClassName,
|
|
HINSTANCE hModule)
|
|
{
|
|
IN_STRING strClassName;
|
|
CLSMENUNAME cmn;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strClassName.fAllocated = FALSE;
|
|
|
|
BEGINCALL_CLASSV()
|
|
|
|
FIRSTCOPYLPTSTRID(&strClassName, lpClassNameVer);
|
|
|
|
retval = (DWORD)NtUserUnregisterClass(
|
|
strClassName.pstr,
|
|
hModule,
|
|
&cmn);
|
|
|
|
|
|
/*
|
|
* Check explicity for TRUE so we don't get a !FALSE when
|
|
* converttogui fails and the NtUser returns a status code intead of bool.
|
|
*/
|
|
if (retval == TRUE) {
|
|
/*
|
|
* Free the menu strings if they are not resource IDs
|
|
*/
|
|
if (IS_PTR(cmn.pszClientAnsiMenuName)) {
|
|
UserLocalFree(KPVOID_TO_PVOID(cmn.pszClientAnsiMenuName));
|
|
}
|
|
if (IS_PTR(cmn.pwszClientUnicodeMenuName)) {
|
|
UserLocalFree(KPVOID_TO_PVOID(cmn.pwszClientUnicodeMenuName));
|
|
}
|
|
}
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPTSTR(strClassName);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, VkKeyScanW , TCHAR, cChar)
|
|
#else
|
|
FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, VkKeyScanA , TCHAR, cChar)
|
|
#endif // UNICODE
|
|
|
|
SHORT VkKeyScan(
|
|
TCHAR cChar)
|
|
{
|
|
WCHAR wChar;
|
|
|
|
BEGINCALL()
|
|
|
|
#ifdef UNICODE
|
|
wChar = cChar;
|
|
#else
|
|
#ifdef FE_SB // VkKeyScan()
|
|
/*
|
|
* Return 0xFFFFFFFF for DBCS LeadByte character.
|
|
*/
|
|
if (IsDBCSLeadByte(cChar)) {
|
|
MSGERROR();
|
|
}
|
|
#endif // FE_SB
|
|
|
|
RtlMultiByteToUnicodeN((LPWSTR)&(wChar), sizeof(WCHAR), NULL, &cChar, sizeof(CHAR));
|
|
#endif // UNICODE
|
|
|
|
retval = (DWORD)NtUserVkKeyScanEx(
|
|
wChar,
|
|
0,
|
|
FALSE);
|
|
|
|
ERRORTRAP(-1);
|
|
ENDCALL(SHORT);
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
static HKL hVKSCachedHKL = 0;
|
|
static UINT uVKSCachedCP = 0;
|
|
#endif
|
|
#ifdef UNICODE
|
|
FUNCLOG2(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, VkKeyScanExW, TCHAR, cChar, HKL, hkl)
|
|
#else
|
|
FUNCLOG2(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, VkKeyScanExA, TCHAR, cChar, HKL, hkl)
|
|
#endif // UNICODE
|
|
SHORT VkKeyScanEx(
|
|
TCHAR cChar,
|
|
HKL hkl)
|
|
{
|
|
WCHAR wChar;
|
|
BEGINCALL()
|
|
|
|
#ifdef UNICODE
|
|
wChar = cChar;
|
|
#else
|
|
if (hkl != hVKSCachedHKL) {
|
|
DWORD dwCodePage;
|
|
if (!GetLocaleInfoW(
|
|
HandleToUlong(hkl) & 0xffff,
|
|
LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
|
|
(LPWSTR)&dwCodePage,
|
|
sizeof(dwCodePage) / sizeof(WCHAR)
|
|
)) {
|
|
MSGERROR();
|
|
}
|
|
uVKSCachedCP = dwCodePage;
|
|
hVKSCachedHKL = hkl;
|
|
}
|
|
|
|
#ifdef FE_SB // VkKeyScanEx()
|
|
/*
|
|
* Return 0xFFFFFFFF for DBCS LeadByte character.
|
|
*/
|
|
if (IsDBCSLeadByteEx(uVKSCachedCP,cChar)) {
|
|
MSGERROR();
|
|
}
|
|
#endif // FE_SB
|
|
|
|
if (!MultiByteToWideChar(
|
|
uVKSCachedCP,
|
|
0,
|
|
&cChar,
|
|
1,
|
|
&wChar,
|
|
1)) {
|
|
MSGERROR();
|
|
}
|
|
#endif // UNICODE
|
|
|
|
retval = (DWORD)NtUserVkKeyScanEx(
|
|
wChar,
|
|
(ULONG_PTR)hkl,
|
|
TRUE);
|
|
|
|
ERRORTRAP(-1);
|
|
ENDCALL(SHORT);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumDisplayDevicesW, LPCTSTR, lpszDevice, DWORD, iDevNum, PDISPLAY_DEVICE, lpDisplayDevice, DWORD, dwFlags)
|
|
#else
|
|
FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumDisplayDevicesA, LPCTSTR, lpszDevice, DWORD, iDevNum, PDISPLAY_DEVICE, lpDisplayDevice, DWORD, dwFlags)
|
|
#endif // UNICODE
|
|
BOOL
|
|
EnumDisplayDevices(
|
|
LPCTSTR lpszDevice,
|
|
DWORD iDevNum,
|
|
PDISPLAY_DEVICE lpDisplayDevice,
|
|
DWORD dwFlags)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
PUNICODE_STRING pUnicodeString = NULL;
|
|
NTSTATUS Status;
|
|
DISPLAY_DEVICEW tmpDisplayDevice;
|
|
|
|
//
|
|
// Clear out things to make sure the caller passes in appropriate
|
|
// parameters
|
|
//
|
|
|
|
ZeroMemory(((PUCHAR)lpDisplayDevice) + sizeof(DWORD),
|
|
lpDisplayDevice->cb - sizeof(DWORD));
|
|
|
|
tmpDisplayDevice.cb = sizeof(DISPLAY_DEVICEW);
|
|
|
|
if (lpszDevice) {
|
|
|
|
#ifdef UNICODE
|
|
|
|
RtlInitUnicodeString(&UnicodeString, lpszDevice);
|
|
|
|
#else
|
|
|
|
ANSI_STRING AnsiString;
|
|
|
|
UnicodeString = NtCurrentTeb()->StaticUnicodeString;
|
|
RtlInitAnsiString(&AnsiString, (LPSTR)lpszDevice);
|
|
|
|
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString,
|
|
&AnsiString,
|
|
FALSE))) {
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
pUnicodeString = &UnicodeString;
|
|
}
|
|
|
|
Status = NtUserEnumDisplayDevices(
|
|
pUnicodeString,
|
|
iDevNum,
|
|
&tmpDisplayDevice,
|
|
dwFlags);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
#ifndef UNICODE
|
|
LPSTR psz;
|
|
|
|
if (lpDisplayDevice->cb >= FIELD_OFFSET(DISPLAY_DEVICE, DeviceString)) {
|
|
psz = (LPSTR)&(lpDisplayDevice->DeviceName[0]);
|
|
WCSToMB(&(tmpDisplayDevice.DeviceName[0]), -1, &psz, 32, FALSE);
|
|
}
|
|
|
|
if (lpDisplayDevice->cb >= FIELD_OFFSET(DISPLAY_DEVICE, StateFlags)) {
|
|
psz = (LPSTR)&(lpDisplayDevice->DeviceString[0]);
|
|
WCSToMB(&(tmpDisplayDevice.DeviceString[0]), -1, &psz, 128, FALSE);
|
|
}
|
|
|
|
if (lpDisplayDevice->cb >= FIELD_OFFSET(DISPLAY_DEVICE, DeviceID)) {
|
|
lpDisplayDevice->StateFlags = tmpDisplayDevice.StateFlags;
|
|
}
|
|
|
|
if (lpDisplayDevice->cb >= FIELD_OFFSET(DISPLAY_DEVICE, DeviceKey)) {
|
|
psz = (LPSTR)&(lpDisplayDevice->DeviceID[0]);
|
|
WCSToMB(&(tmpDisplayDevice.DeviceID[0]), -1, &psz, 128, FALSE);
|
|
}
|
|
if (lpDisplayDevice->cb >= sizeof(DISPLAY_DEVICE)) {
|
|
psz = (LPSTR)&(lpDisplayDevice->DeviceKey[0]);
|
|
WCSToMB(&(tmpDisplayDevice.DeviceKey[0]), -1, &psz, 128, FALSE);
|
|
}
|
|
#else
|
|
|
|
//
|
|
// Copy the contents of the tmpDisplayDevice back to the
|
|
// user supplied buffer. Make sure not to overwrite the original
|
|
// size field.
|
|
//
|
|
|
|
RtlMoveMemory((PUCHAR)lpDisplayDevice + sizeof(DWORD),
|
|
((PUCHAR)&tmpDisplayDevice + sizeof(DWORD)),
|
|
lpDisplayDevice->cb - sizeof(DWORD));
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumDisplaySettingsW , LPCTSTR, lpszDeviceName, DWORD, iModeNum, LPDEVMODE, lpDevMode)
|
|
#else
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumDisplaySettingsA, LPCTSTR, lpszDeviceName, DWORD, iModeNum, LPDEVMODE, lpDevMode)
|
|
#endif // UNICODE
|
|
BOOL EnumDisplaySettings(
|
|
LPCTSTR lpszDeviceName,
|
|
DWORD iModeNum,
|
|
LPDEVMODE lpDevMode)
|
|
{
|
|
|
|
//
|
|
// Work-around Win95 problem which does not require the caller
|
|
// to initialize these two fields.
|
|
//
|
|
|
|
lpDevMode->dmDriverExtra = 0;
|
|
lpDevMode->dmSize = FIELD_OFFSET(DEVMODE, dmICMMethod);
|
|
|
|
return EnumDisplaySettingsEx(lpszDeviceName, iModeNum, lpDevMode, 0);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumDisplaySettingsExW, LPCTSTR, lpszDeviceName, DWORD, iModeNum, LPDEVMODE, lpDevMode, DWORD, dwFlags)
|
|
#else
|
|
FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumDisplaySettingsExA, LPCTSTR, lpszDeviceName, DWORD, iModeNum, LPDEVMODE, lpDevMode, DWORD, dwFlags)
|
|
#endif // UNICODE
|
|
BOOL EnumDisplaySettingsEx(
|
|
LPCTSTR lpszDeviceName,
|
|
DWORD iModeNum,
|
|
LPDEVMODE lpDevMode,
|
|
DWORD dwFlags)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
PUNICODE_STRING pUnicodeString = NULL;
|
|
LPDEVMODEW lpDevModeReserve;
|
|
BOOL retval = FALSE;
|
|
WORD size = lpDevMode->dmSize;
|
|
|
|
if (lpszDeviceName) {
|
|
|
|
#ifdef UNICODE
|
|
|
|
RtlInitUnicodeString(&UnicodeString, lpszDeviceName);
|
|
|
|
#else
|
|
|
|
ANSI_STRING AnsiString;
|
|
|
|
UnicodeString = NtCurrentTeb()->StaticUnicodeString;
|
|
RtlInitAnsiString(&AnsiString, (LPSTR)lpszDeviceName);
|
|
|
|
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString,
|
|
&AnsiString,
|
|
FALSE))) {
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
pUnicodeString = &UnicodeString;
|
|
}
|
|
|
|
/*
|
|
* Currently -2 is reserved (undocumented function of the NT api.
|
|
* remove the check is win95 implements this.
|
|
* -> -1 returns the content of the registry at the time of the call
|
|
*
|
|
*
|
|
* if (iModeNum == (DWORD) -2)
|
|
* {
|
|
* return FALSE;
|
|
* }
|
|
*
|
|
*
|
|
* -1 should return the current DEVMODE for the device.
|
|
* This is handled in the kernel part of the function, so we pass it on.
|
|
*
|
|
*
|
|
*
|
|
* We will always request a full DEVMODE from the kernel.
|
|
* So allocate the space needed
|
|
*
|
|
*/
|
|
lpDevModeReserve = UserLocalAlloc(HEAP_ZERO_MEMORY,
|
|
sizeof(DEVMODEW) + lpDevMode->dmDriverExtra);
|
|
if (lpDevModeReserve) {
|
|
|
|
lpDevModeReserve->dmSize = sizeof(DEVMODEW);
|
|
lpDevModeReserve->dmDriverExtra = lpDevMode->dmDriverExtra;
|
|
|
|
/*
|
|
* Get the information
|
|
*/
|
|
retval = (NT_SUCCESS(NtUserEnumDisplaySettings(pUnicodeString,
|
|
iModeNum,
|
|
lpDevModeReserve,
|
|
dwFlags)));
|
|
if (retval) {
|
|
|
|
#ifndef UNICODE
|
|
LPSTR psz;
|
|
#endif
|
|
|
|
/*
|
|
* return only the amount of information requested.
|
|
* For ANSI, this requires a conversion.
|
|
*/
|
|
|
|
/*
|
|
* First, copy the driver extra information
|
|
*/
|
|
|
|
if (lpDevMode->dmDriverExtra && lpDevModeReserve->dmDriverExtra) {
|
|
RtlMoveMemory(((PUCHAR)lpDevMode) + size,
|
|
lpDevModeReserve + 1,
|
|
min(lpDevMode->dmDriverExtra,
|
|
lpDevModeReserve->dmDriverExtra));
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
psz = (LPSTR)&(lpDevMode->dmDeviceName[0]);
|
|
|
|
retval = WCSToMB(lpDevModeReserve->dmDeviceName,
|
|
-1,
|
|
&psz,
|
|
32,
|
|
FALSE);
|
|
|
|
RtlMoveMemory(&lpDevMode->dmSpecVersion,
|
|
&lpDevModeReserve->dmSpecVersion,
|
|
min(size, FIELD_OFFSET(DEVMODE,dmFormName)) -
|
|
FIELD_OFFSET(DEVMODE,dmSpecVersion));
|
|
|
|
lpDevMode->dmSize = size;
|
|
|
|
if (size >= FIELD_OFFSET(DEVMODE,dmFormName)) {
|
|
psz = (LPSTR)&(lpDevMode->dmFormName[0]);
|
|
|
|
retval = WCSToMB(lpDevModeReserve->dmFormName, -1, &psz, 32, FALSE);
|
|
}
|
|
|
|
if (size > FIELD_OFFSET(DEVMODE,dmBitsPerPel)) {
|
|
RtlMoveMemory(&lpDevMode->dmBitsPerPel,
|
|
&lpDevModeReserve->dmBitsPerPel,
|
|
lpDevMode->dmSize +
|
|
lpDevMode->dmDriverExtra -
|
|
FIELD_OFFSET(DEVMODE,dmBitsPerPel));
|
|
}
|
|
|
|
#else
|
|
RtlMoveMemory(lpDevMode, lpDevModeReserve, size);
|
|
|
|
lpDevMode->dmSize = size;
|
|
|
|
#endif
|
|
|
|
if (size != lpDevMode->dmSize) {
|
|
RIPMSG0(RIP_WARNING, "EnumDisplaySettings : Error in dmSize");
|
|
}
|
|
|
|
/*
|
|
* Don't return invalid field flags to the application
|
|
* Add any other new ones here.
|
|
*
|
|
* We assume apps at least have up to dmDisplayFrenquency for
|
|
* now ...
|
|
*/
|
|
|
|
if (size < FIELD_OFFSET(DEVMODE,dmPanningWidth))
|
|
lpDevMode->dmFields &= ~DM_PANNINGWIDTH;
|
|
|
|
if (size < FIELD_OFFSET(DEVMODE,dmPanningHeight))
|
|
lpDevMode->dmFields &= ~DM_PANNINGHEIGHT;
|
|
}
|
|
|
|
UserLocalFree(lpDevModeReserve);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG2(LOG_GENERAL, LONG, DUMMYCALLINGTYPE, ChangeDisplaySettingsW, LPDEVMODE, lpDevMode, DWORD, dwFlags)
|
|
#else
|
|
FUNCLOG2(LOG_GENERAL, LONG, DUMMYCALLINGTYPE, ChangeDisplaySettingsA, LPDEVMODE, lpDevMode, DWORD, dwFlags)
|
|
#endif // UNICODE
|
|
LONG ChangeDisplaySettings(
|
|
LPDEVMODE lpDevMode,
|
|
DWORD dwFlags)
|
|
{
|
|
/*
|
|
* Compatibility.
|
|
*/
|
|
if (lpDevMode) {
|
|
lpDevMode->dmDriverExtra = 0;
|
|
}
|
|
|
|
return ChangeDisplaySettingsEx(NULL, lpDevMode, NULL, dwFlags, NULL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG5(LOG_GENERAL, LONG, DUMMYCALLINGTYPE, ChangeDisplaySettingsExW, LPCTSTR, lpszDeviceName, LPDEVMODE, lpDevMode, HWND, hwnd, DWORD, dwFlags, LPVOID, lParam)
|
|
#else
|
|
FUNCLOG5(LOG_GENERAL, LONG, DUMMYCALLINGTYPE, ChangeDisplaySettingsExA, LPCTSTR, lpszDeviceName, LPDEVMODE, lpDevMode, HWND, hwnd, DWORD, dwFlags, LPVOID, lParam)
|
|
#endif // UNICODE
|
|
LONG ChangeDisplaySettingsEx(
|
|
LPCTSTR lpszDeviceName,
|
|
LPDEVMODE lpDevMode,
|
|
HWND hwnd,
|
|
DWORD dwFlags,
|
|
LPVOID lParam)
|
|
{
|
|
#ifndef UNICODE
|
|
ANSI_STRING AnsiString;
|
|
#endif
|
|
|
|
UNICODE_STRING UnicodeString;
|
|
PUNICODE_STRING pUnicodeString = NULL;
|
|
LONG status = DISP_CHANGE_FAILED;
|
|
LPDEVMODEW lpDevModeW;
|
|
|
|
if (hwnd != NULL) {
|
|
return DISP_CHANGE_BADPARAM;
|
|
}
|
|
|
|
if (lpszDeviceName) {
|
|
#ifdef UNICODE
|
|
RtlInitUnicodeString(&UnicodeString, lpszDeviceName);
|
|
#else
|
|
UnicodeString = NtCurrentTeb()->StaticUnicodeString;
|
|
RtlInitAnsiString(&AnsiString, (LPSTR)lpszDeviceName);
|
|
|
|
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString,
|
|
&AnsiString,
|
|
FALSE))) {
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
pUnicodeString = &UnicodeString;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
lpDevModeW = lpDevMode;
|
|
#else
|
|
lpDevModeW = NULL;
|
|
|
|
if (lpDevMode) {
|
|
lpDevModeW = GdiConvertToDevmodeW(lpDevMode);
|
|
if (lpDevModeW == NULL) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
status = NtUserChangeDisplaySettings(pUnicodeString,
|
|
lpDevModeW,
|
|
dwFlags,
|
|
lParam);
|
|
|
|
#ifndef UNICODE
|
|
if (lpDevMode) {
|
|
UserLocalFree(lpDevModeW);
|
|
}
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, CallMsgFilterW , LPMSG, pmsg, int, nCode)
|
|
#else
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, CallMsgFilterA , LPMSG, pmsg, int, nCode)
|
|
#endif // UNICODE
|
|
BOOL CallMsgFilter(
|
|
LPMSG pmsg,
|
|
int nCode)
|
|
{
|
|
PCLIENTINFO pci;
|
|
MSG msg;
|
|
|
|
BEGINCALLCONNECT()
|
|
|
|
/*
|
|
* If we're not hooked, don't bother going to the server
|
|
*/
|
|
pci = GetClientInfo();
|
|
if (!IsHooked(pci, (WH_MSGFILTER | WH_SYSMSGFILTER))) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Don't allow apps to use the hiword of the message parameter.
|
|
*/
|
|
if (pmsg->message & RESERVED_MSG_BITS) {
|
|
MSGERRORCODE(ERROR_INVALID_PARAMETER);
|
|
}
|
|
msg = *pmsg;
|
|
|
|
#ifndef UNICODE
|
|
switch (pmsg->message) {
|
|
#ifdef FE_SB // CallMsgFilter()
|
|
case WM_CHAR:
|
|
case EM_SETPASSWORDCHAR:
|
|
#ifndef LATER
|
|
/*
|
|
* we should not return "TRUE" everytime for DBCS leadbyte character...
|
|
* but should convert DBCS character to Unicode correctly.. How I can do ??
|
|
* then ,finally, we just take what we did in NT 3.51, it means do nothing..
|
|
*/
|
|
#else
|
|
/*
|
|
* Build DBCS-aware message.
|
|
*/
|
|
BUILD_DBCS_MESSAGE_TO_SERVER_FROM_CLIENTA(pmsg->message,pmsg->wParam,TRUE);
|
|
/*
|
|
* Fall through.....
|
|
*/
|
|
#endif // LATER
|
|
#else
|
|
case WM_CHAR:
|
|
case EM_SETPASSWORDCHAR:
|
|
#endif // FE_SB
|
|
case WM_CHARTOITEM:
|
|
case WM_DEADCHAR:
|
|
case WM_SYSCHAR:
|
|
case WM_SYSDEADCHAR:
|
|
case WM_MENUCHAR:
|
|
#ifdef FE_IME // CallMsgFilter()
|
|
case WM_IME_CHAR:
|
|
case WM_IME_COMPOSITION:
|
|
#endif // FE_IME
|
|
|
|
RtlMBMessageWParamCharToWCS( msg.message, &(msg.wParam));
|
|
break;
|
|
}
|
|
#endif //!UNICODE
|
|
|
|
retval = (DWORD)NtUserCallMsgFilter(
|
|
&msg,
|
|
nCode);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG7(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DrawCaptionTempW, HWND, hwnd, HDC, hdc, LPCRECT, lprc, HFONT, hFont, HICON, hicon, LPCTSTR, lpText, UINT, flags)
|
|
#else
|
|
FUNCLOG7(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DrawCaptionTempA, HWND, hwnd, HDC, hdc, LPCRECT, lprc, HFONT, hFont, HICON, hicon, LPCTSTR, lpText, UINT, flags)
|
|
#endif // UNICODE
|
|
BOOL DrawCaptionTemp(
|
|
HWND hwnd,
|
|
HDC hdc,
|
|
LPCRECT lprc,
|
|
HFONT hFont,
|
|
HICON hicon,
|
|
LPCTSTR lpText,
|
|
UINT flags)
|
|
{
|
|
HDC hdcr;
|
|
IN_STRING strText;
|
|
|
|
/*
|
|
* Make sure cleanup will work successfully
|
|
*/
|
|
strText.fAllocated = FALSE;
|
|
|
|
BEGINCALL()
|
|
|
|
if (IsMetaFile(hdc)) return FALSE;
|
|
|
|
hdcr = GdiConvertAndCheckDC(hdc);
|
|
if (hdcr == (HDC)0)
|
|
return FALSE;
|
|
|
|
FIRSTCOPYLPTSTRIDOPT(&strText, lpText);
|
|
|
|
retval = (DWORD)NtUserDrawCaptionTemp(
|
|
hwnd,
|
|
hdc,
|
|
lprc,
|
|
hFont,
|
|
hicon,
|
|
strText.pstr,
|
|
flags);
|
|
|
|
ERRORTRAP(0);
|
|
CLEANUPLPTSTR(strText);
|
|
ENDCALL(BOOL);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
FUNCLOG3(LOG_GENERAL, UINT, WINUSERAPI, RealGetWindowClassW, HWND, hwnd, LPTSTR, ptszClassName, UINT, cchClassNameMax)
|
|
#else
|
|
FUNCLOG3(LOG_GENERAL, UINT, WINUSERAPI, RealGetWindowClassA, HWND, hwnd, LPTSTR, ptszClassName, UINT, cchClassNameMax)
|
|
#endif // UNICODE
|
|
|
|
WINUSERAPI UINT WINAPI
|
|
RealGetWindowClass(
|
|
HWND hwnd,
|
|
LPTSTR ptszClassName,
|
|
UINT cchClassNameMax)
|
|
{
|
|
UNICODE_STRING strClassName;
|
|
int retval;
|
|
|
|
strClassName.MaximumLength = (USHORT)(cchClassNameMax * sizeof(WCHAR));
|
|
|
|
#ifndef UNICODE
|
|
strClassName.Buffer = UserLocalAlloc(0, strClassName.MaximumLength);
|
|
if (!strClassName.Buffer) {
|
|
return 0;
|
|
}
|
|
#else
|
|
strClassName.Buffer = ptszClassName;
|
|
#endif
|
|
|
|
retval = NtUserGetClassName(hwnd, TRUE, &strClassName);
|
|
|
|
#ifndef UNICODE
|
|
if (retval || (cchClassNameMax == 1)) {
|
|
/*
|
|
* Copy the result
|
|
*/
|
|
retval = WCSToMB(strClassName.Buffer,
|
|
retval,
|
|
&ptszClassName,
|
|
cchClassNameMax - 1,
|
|
FALSE);
|
|
ptszClassName[retval] = '\0';
|
|
}
|
|
UserLocalFree(strClassName.Buffer);
|
|
#endif
|
|
|
|
return retval;
|
|
}
|
|
|
|
WINUSERAPI BOOL WINAPI GetAltTabInfo(
|
|
HWND hwnd,
|
|
int iItem,
|
|
PALTTABINFO pati,
|
|
LPTSTR pszItemText,
|
|
UINT cchItemText OPTIONAL)
|
|
{
|
|
BEGINCALL()
|
|
|
|
retval = (DWORD)NtUserGetAltTabInfo(hwnd,
|
|
iItem,
|
|
pati,
|
|
(LPWSTR)pszItemText,
|
|
cchItemText,
|
|
IS_ANSI);
|
|
|
|
ERRORTRAP(0);
|
|
ENDCALL(BOOL);
|
|
}
|