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.
558 lines
16 KiB
558 lines
16 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: clenum
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* For enumeration functions
|
|
*
|
|
* 04-27-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
#define IEP_UNICODE 0x1 // Convert Atom to unicode string (vs ANSI)
|
|
#define IEP_ENUMEX 0x2 // Pass lParam back to callback function (vs no lParam)
|
|
|
|
HWND *phwndCache = NULL;
|
|
|
|
|
|
/***************************************************************************\
|
|
* InternalEnumWindows
|
|
*
|
|
* Calls server and gets back a window list. This list is enumerated, for each
|
|
* window the callback address is called (into the application), until either
|
|
* end-of-list is reached or FALSE is return ed. lParam is passed into the
|
|
* callback function for app reference.
|
|
*
|
|
*
|
|
* If any windows are returned (cHwnd > 0) the caller is responsible for
|
|
* freeing the window buffer when done with the list
|
|
*
|
|
* 04-27-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
DWORD BuildHwndList(
|
|
HDESK hdesk,
|
|
HWND hwndNext,
|
|
BOOL fEnumChildren,
|
|
DWORD idThread,
|
|
HWND **pphwndFirst)
|
|
{
|
|
UINT cHwnd;
|
|
HWND *phwndFirst;
|
|
NTSTATUS Status;
|
|
int cTries;
|
|
|
|
/*
|
|
* Allocate a buffer to hold the names.
|
|
*/
|
|
cHwnd = 64;
|
|
phwndFirst = (HWND *)InterlockedExchangePointer(&(PVOID)phwndCache, 0);
|
|
if (phwndFirst == NULL) {
|
|
phwndFirst = UserLocalAlloc(0, cHwnd * sizeof(HWND));
|
|
if (phwndFirst == NULL) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Status = NtUserBuildHwndList(hdesk,
|
|
hwndNext,
|
|
fEnumChildren,
|
|
idThread,
|
|
cHwnd,
|
|
phwndFirst,
|
|
&cHwnd);
|
|
|
|
/*
|
|
* If the buffer wasn't big enough, reallocate the buffer and try again.
|
|
*/
|
|
cTries = 0;
|
|
while (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
UserLocalFree(phwndFirst);
|
|
|
|
/*
|
|
* If we can't seem to get it right, call it quits.
|
|
*/
|
|
if (cTries++ == 10) {
|
|
return 0;
|
|
}
|
|
|
|
phwndFirst = UserLocalAlloc(0, cHwnd * sizeof(HWND));
|
|
if (phwndFirst == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
Status = NtUserBuildHwndList(hdesk,
|
|
hwndNext,
|
|
fEnumChildren,
|
|
idThread,
|
|
cHwnd,
|
|
phwndFirst,
|
|
&cHwnd);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status) || cHwnd <= 1) {
|
|
UserLocalFree(phwndFirst);
|
|
return 0;
|
|
}
|
|
|
|
*pphwndFirst = phwndFirst;
|
|
return cHwnd - 1;
|
|
}
|
|
|
|
BOOL InternalEnumWindows(
|
|
HDESK hdesk,
|
|
HWND hwnd,
|
|
WNDENUMPROC lpfn,
|
|
LPARAM lParam,
|
|
DWORD idThread,
|
|
BOOL fEnumChildren)
|
|
{
|
|
UINT i;
|
|
UINT cHwnd;
|
|
HWND *phwndT;
|
|
HWND *phwndFirst;
|
|
BOOL fSuccess = TRUE;
|
|
|
|
/*
|
|
* Get the hwnd list. It is returned in a block of memory allocated with
|
|
* UserLocalAlloc.
|
|
*/
|
|
if ((cHwnd = BuildHwndList(hdesk, hwnd, fEnumChildren, idThread,
|
|
&phwndFirst)) == -1) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* In Win 3.1 it was not an error if there were no windows in the thread.
|
|
*/
|
|
if (cHwnd == 0) {
|
|
if (idThread == 0) {
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Loop through the windows, call the function pointer back for each
|
|
* one. End loop if either FALSE is return ed or the end-of-list is
|
|
* reached.
|
|
*/
|
|
phwndT = phwndFirst;
|
|
for (i = 0; i < cHwnd; i++) {
|
|
|
|
/*
|
|
* Call ValidateHwnd instead of RevalidateHwnd so that restricted
|
|
* processes don't see handles they aren't supposed to.
|
|
*/
|
|
if (ValidateHwnd(*phwndT)) {
|
|
if (!(fSuccess = (*lpfn)(*phwndT, lParam))) {
|
|
break;
|
|
}
|
|
}
|
|
phwndT++;
|
|
}
|
|
|
|
/*
|
|
* Free up buffer and return status - TRUE if entire list was enumerated,
|
|
* FALSE otherwise.
|
|
*/
|
|
phwndT = (HWND *)InterlockedExchangePointer(&(PVOID)phwndCache, phwndFirst);
|
|
if (phwndT != NULL) {
|
|
UserLocalFree(phwndT);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* EnumWindows
|
|
*
|
|
* Enumerates all top-level windows. Calls back lpfn with each hwnd until
|
|
* either end-of-list or FALSE is return ed. lParam is passed into callback
|
|
* function for app reference.
|
|
*
|
|
* 04-27-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, WINAPI, EnumWindows, WNDENUMPROC, lpfn, LPARAM, lParam)
|
|
BOOL WINAPI EnumWindows(
|
|
WNDENUMPROC lpfn,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumWindows(NULL, NULL, lpfn, lParam, 0L, FALSE);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* EnumChildWindows
|
|
*
|
|
* Enumerates all children of the passed in window. Calls back lpfn with each
|
|
* hwnd until either end-of-list or FALSE is return ed. lParam is passed into
|
|
* callback function for app reference.
|
|
*
|
|
* 04-27-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, WINAPI, EnumChildWindows, HWND, hwnd, WNDENUMPROC, lpfn, LPARAM, lParam)
|
|
BOOL WINAPI EnumChildWindows(
|
|
HWND hwnd,
|
|
WNDENUMPROC lpfn,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumWindows(NULL, hwnd, lpfn, lParam, 0L, TRUE);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* EnumThreadWindows
|
|
*
|
|
* Enumerates all top level windows created by idThread. Calls back lpfn with
|
|
* each hwnd until either end-of-list or FALSE is return ed. lParam is passed
|
|
* into callback function for app reference.
|
|
*
|
|
* 06-23-91 ScottLu Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumThreadWindows, DWORD, idThread, WNDENUMPROC, lpfn, LPARAM, lParam)
|
|
BOOL EnumThreadWindows(
|
|
DWORD idThread,
|
|
WNDENUMPROC lpfn,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumWindows(NULL, NULL, lpfn, lParam, idThread, FALSE);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* EnumDesktopWindows
|
|
*
|
|
* Enumerates all top level windows on the desktop specified by hdesk.
|
|
* Calls back lpfn with each hwnd until either end-of-list or FALSE
|
|
* is returned. lParam is passed into callback function for app reference.
|
|
*
|
|
* 10-10-94 JimA Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnumDesktopWindows, HDESK, hdesk, WNDENUMPROC, lpfn, LPARAM, lParam)
|
|
BOOL EnumDesktopWindows(
|
|
HDESK hdesk,
|
|
WNDENUMPROC lpfn,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumWindows(hdesk, NULL, lpfn, lParam, 0, FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* InternalEnumProps
|
|
*
|
|
* Calls server and gets back a list of props for the specified window.
|
|
* The callback address is called (into the application), until either
|
|
* end-of-list is reached or FALSE is return ed.
|
|
* lParam is passed into the callback function for app reference when
|
|
* IEP_ENUMEX is set. Atoms are turned into UNICODE string if IEP_UNICODE
|
|
* is set.
|
|
*
|
|
* 22-Jan-1992 JohnC Created.
|
|
\***************************************************************************/
|
|
|
|
#define MAX_ATOM_SIZE 512
|
|
#define ISSTRINGATOM(atom) ((WORD)(atom) >= 0xc000)
|
|
|
|
INT InternalEnumProps(
|
|
HWND hwnd,
|
|
PROPENUMPROC lpfn,
|
|
LPARAM lParam,
|
|
UINT flags)
|
|
{
|
|
DWORD ii;
|
|
DWORD cPropSets;
|
|
PPROPSET pPropSet;
|
|
WCHAR awch[MAX_ATOM_SIZE];
|
|
PVOID pKey;
|
|
INT iRetVal;
|
|
DWORD cchName;
|
|
NTSTATUS Status;
|
|
int cTries;
|
|
|
|
/*
|
|
* Allocate a buffer to hold the names.
|
|
*/
|
|
cPropSets = 32;
|
|
pPropSet = UserLocalAlloc(0, cPropSets * sizeof(PROPSET));
|
|
if (pPropSet == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
Status = NtUserBuildPropList(hwnd, cPropSets, pPropSet, &cPropSets);
|
|
|
|
/*
|
|
* If the buffer wasn't big enough, reallocate the buffer and try again.
|
|
*/
|
|
cTries = 0;
|
|
while (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
UserLocalFree(pPropSet);
|
|
|
|
/*
|
|
* If we can't seem to get it right, call it quits.
|
|
*/
|
|
if (cTries++ == 10) {
|
|
return -1;
|
|
}
|
|
|
|
pPropSet = UserLocalAlloc(0, cPropSets * sizeof(PROPSET));
|
|
if (pPropSet == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
Status = NtUserBuildPropList(hwnd, cPropSets, pPropSet, &cPropSets);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
UserLocalFree(pPropSet);
|
|
return -1;
|
|
}
|
|
|
|
for (ii = 0; ii < cPropSets; ii++) {
|
|
if (ISSTRINGATOM(pPropSet[ii].atom)) {
|
|
pKey = (PVOID)awch;
|
|
if (flags & IEP_UNICODE) {
|
|
cchName = GlobalGetAtomNameW(pPropSet[ii].atom,
|
|
(LPWSTR)pKey,
|
|
MAX_ATOM_SIZE);
|
|
} else {
|
|
cchName = GlobalGetAtomNameA(pPropSet[ii].atom,
|
|
(LPSTR)pKey,
|
|
sizeof(awch));
|
|
}
|
|
|
|
/*
|
|
* If cchName is zero, we must assume that the property belongs
|
|
* to another process. Because we can't get the name, just skip
|
|
* it.
|
|
*/
|
|
if (cchName == 0) {
|
|
continue;
|
|
}
|
|
} else {
|
|
pKey = (PVOID)pPropSet[ii].atom;
|
|
}
|
|
|
|
if (flags & IEP_ENUMEX) {
|
|
iRetVal = (*(PROPENUMPROCEX)lpfn)(hwnd, pKey,
|
|
pPropSet[ii].hData, lParam);
|
|
} else {
|
|
iRetVal = (*lpfn)(hwnd, pKey, pPropSet[ii].hData);
|
|
}
|
|
|
|
if (!iRetVal) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
UserLocalFree(pPropSet);
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* EnumProps
|
|
*
|
|
* This function enumerates all entries in the property list of the specified
|
|
* window. It enumerates the entries by passing them, one by one, to the
|
|
* callback function specified by lpEnumFunc. EnumProps continues until the
|
|
* last entry is enumerated or the callback function return s zero.
|
|
*
|
|
* 22-Jan-1992 JohnC Created.
|
|
\***************************************************************************/
|
|
FUNCLOG2(LOG_GENERAL, INT, WINAPI, EnumPropsA, HWND, hwnd, PROPENUMPROCA, lpfn)
|
|
INT WINAPI EnumPropsA(
|
|
HWND hwnd,
|
|
PROPENUMPROCA lpfn)
|
|
{
|
|
return InternalEnumProps(hwnd, (PROPENUMPROC)lpfn, 0, 0);
|
|
}
|
|
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, INT, WINAPI, EnumPropsW, HWND, hwnd, PROPENUMPROCW, lpfn)
|
|
INT WINAPI EnumPropsW(
|
|
HWND hwnd,
|
|
PROPENUMPROCW lpfn)
|
|
{
|
|
return InternalEnumProps(hwnd, (PROPENUMPROC)lpfn, 0, IEP_UNICODE);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* EnumPropsEx
|
|
*
|
|
* This function enumerates all entries in the property list of the specified
|
|
* window. It enumerates the entries by passing them, one by one, to the
|
|
* callback function specified by lpEnumFunc. EnumProps continues until the
|
|
* last entry is enumerated or the callback function return s zero.
|
|
*
|
|
* 22-Jan-1992 JohnC Created.
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, WINAPI, EnumPropsExA, HWND, hwnd, PROPENUMPROCEXA, lpfn, LPARAM, lParam)
|
|
BOOL WINAPI EnumPropsExA(
|
|
HWND hwnd,
|
|
PROPENUMPROCEXA lpfn,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumProps(hwnd, (PROPENUMPROC)lpfn, lParam, IEP_ENUMEX);
|
|
}
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, WINAPI, EnumPropsExW, HWND, hwnd, PROPENUMPROCEXW, lpfn, LPARAM, lParam)
|
|
BOOL WINAPI EnumPropsExW(
|
|
HWND hwnd,
|
|
PROPENUMPROCEXW lpfn,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumProps(hwnd, (PROPENUMPROC)lpfn, lParam, IEP_UNICODE|IEP_ENUMEX);
|
|
}
|
|
|
|
|
|
|
|
BOOL InternalEnumObjects(
|
|
HWINSTA hwinsta,
|
|
NAMEENUMPROCW lpfn,
|
|
LPARAM lParam,
|
|
BOOL fAnsi)
|
|
{
|
|
PNAMELIST pNameList;
|
|
DWORD i;
|
|
UINT cbData;
|
|
PWCHAR pwch;
|
|
PCHAR pch;
|
|
CHAR achTmp[MAX_PATH];
|
|
BOOL iRetVal;
|
|
NTSTATUS Status;
|
|
int cTries;
|
|
|
|
/*
|
|
* Allocate a buffer to hold the names. The size of the buffer is
|
|
* determined by the maximum size for a window station name defined
|
|
* in ntstubs.c.
|
|
*/
|
|
cbData = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
|
|
pNameList = UserLocalAlloc(0, cbData);
|
|
if (pNameList == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Status = NtUserBuildNameList(hwinsta, cbData, pNameList, &cbData);
|
|
|
|
/*
|
|
* If the buffer wasn't big enough, reallocate the buffer and try again.
|
|
*/
|
|
cTries = 0;
|
|
while (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
UserLocalFree(pNameList);
|
|
|
|
/*
|
|
* If we can't seem to get it right, call it quits.
|
|
*/
|
|
if (cTries++ == 10) {
|
|
return FALSE;
|
|
}
|
|
|
|
pNameList = UserLocalAlloc(0, cbData);
|
|
if (pNameList == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Status = NtUserBuildNameList(hwinsta, cbData, pNameList, &cbData);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
UserLocalFree(pNameList);
|
|
return FALSE;
|
|
}
|
|
|
|
pwch = pNameList->awchNames;
|
|
pch = achTmp;
|
|
|
|
for (i = 0; i < pNameList->cNames; i++) {
|
|
if (fAnsi) {
|
|
if (WCSToMB(pwch, -1, &pch, sizeof(achTmp), FALSE) ==
|
|
sizeof(achTmp)) {
|
|
|
|
/*
|
|
* The buffer may have overflowed, so force it to be
|
|
* allocated.
|
|
*/
|
|
if (WCSToMB(pwch, -1, &pch, -1, TRUE) == 0) {
|
|
iRetVal = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
iRetVal = (*(NAMEENUMPROCA)lpfn)(pch, lParam);
|
|
if (pch != achTmp) {
|
|
UserLocalFree(pch);
|
|
pch = achTmp;
|
|
}
|
|
} else {
|
|
iRetVal = (*(NAMEENUMPROCW)lpfn)(pwch, lParam);
|
|
}
|
|
if (!iRetVal) {
|
|
break;
|
|
}
|
|
|
|
pwch = pwch + wcslen(pwch) + 1;
|
|
}
|
|
|
|
UserLocalFree(pNameList);
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, WINAPI, EnumWindowStationsA, WINSTAENUMPROCA, lpEnumFunc, LPARAM, lParam)
|
|
BOOL WINAPI EnumWindowStationsA(
|
|
WINSTAENUMPROCA lpEnumFunc,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumObjects(NULL, (NAMEENUMPROCW)lpEnumFunc, lParam, TRUE);
|
|
}
|
|
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, WINAPI, EnumWindowStationsW, WINSTAENUMPROCW, lpEnumFunc, LPARAM, lParam)
|
|
BOOL WINAPI EnumWindowStationsW(
|
|
WINSTAENUMPROCW lpEnumFunc,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumObjects(NULL, (NAMEENUMPROCW)lpEnumFunc, lParam, FALSE);
|
|
}
|
|
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, WINAPI, EnumDesktopsA, HWINSTA, hwinsta, DESKTOPENUMPROCA, lpEnumFunc, LPARAM, lParam)
|
|
BOOL WINAPI EnumDesktopsA(
|
|
HWINSTA hwinsta,
|
|
DESKTOPENUMPROCA lpEnumFunc,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumObjects(hwinsta, (NAMEENUMPROCW)lpEnumFunc, lParam, TRUE);
|
|
}
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, BOOL, WINAPI, EnumDesktopsW, HWINSTA, hwinsta, DESKTOPENUMPROCW, lpEnumFunc, LPARAM, lParam)
|
|
BOOL WINAPI EnumDesktopsW(
|
|
HWINSTA hwinsta,
|
|
DESKTOPENUMPROCW lpEnumFunc,
|
|
LPARAM lParam)
|
|
{
|
|
return InternalEnumObjects(hwinsta, (NAMEENUMPROCW)lpEnumFunc, lParam, FALSE);
|
|
}
|