WinApi - How to obtain SHELLDLL_DefView - c++

I am trying to obtain handle to SHELLDLL_DefView.
So, I have this code.
HWND hProgman = FindWindow(L"Progman", NULL);
HWND hWnd = FindWindowEx(hProgman, 0, L"SHELLDLL_DefView", NULL);
Eveyrtihing works OK, until I change in Windows desktop brackground to slideshow. Then when I search with spy++ hierarchy of the windows, than SHELLDLL_DefView has another parent. Now it is #32769 (Desktop) -> WorkerW -> SHELLDLL_DefView. So I can't find it. Problem is that when I try
HWND desktop = GetDesktopWindow();
HWND hWnd = FindWindowEx(desktop , 0, L"WorkerW", NULL);
HWND hWnd = FindWindowEx(hWnd, 0, L"SHELLDLL_DefView", NULL);
Than SHELLDLL_DefView is not found. WorkerW yes.
Can anybody help?

Your code only works on some Windows versions as "SHELLDLL_DefView" can be found under "WorkerW" or "Progman" and as you discovered there can be many windows under the "WorkerW" class (normal in Win7).
Microsoft Docs report EnumWindows() is more reliable than calling GetWindow()/FindWindowEx() functions in loops, so more universal code (tested on Windows 98/Windows 7) would look like this (say you want to refresh the desktop):
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
HWND hNextWin;
hNextWin = FindWindowExA(hwnd, 0, "SHELLDLL_DefView", 0);
if ( hNextWin ) {
// The correct desktop shell window under Progman/WorkerW will have only 1 child window!
if ( GetNextWindow(hNextWin, GW_HWNDNEXT) || GetNextWindow(hNextWin, GW_HWNDPREV) )
return true;
// We found correct handle
PostMessageA(hNextWin, WM_KEYDOWN, VK_F5, 0);
return false;
}
return true;
}
void main() {
EnumWindows(&EnumWindowsProc, 0);
}

I found the answer. Need to iterate through all WorkerW.
HWND destop = GetDesktopWindow();
HWND hWorkerW = NULL;
HWND hShellViewWin = NULL;
do
{
hWorkerW = FindWindowEx(destop, hWorkerW, L"WorkerW", NULL);
hShellViewWin = FindWindowEx(hWorkerW, 0, L"SHELLDLL_DefView", 0);
} while (hShellViewWin == NULL && hWorkerW != NULL);

Related

Minimalist CreateWindowEx fails

this is just a minimalist console application that should show a windows created on the fly :
#include <windows.h>
void main()
{
WNDCLASSEX _c4w = {0};
_c4w.cbSize = sizeof(WNDCLASSEX);
//_c4w.hCursor = ::LoadCursor(0, IDC_APPLICATION);
//_c4w.hIcon = ::LoadIcon(0, IDI_APPLICATION);
_c4w.hInstance = 0;
_c4w.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
_c4w.lpszClassName = "c4w";
HWND _h;
if(!::RegisterClassEx(&_c4w))
{ _h = ::CreateWindowEx( 0, "c4w",
"Minimal Windows Application",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480,
HWND_DESKTOP,
0,
::GetModuleHandle(0), NULL
);
::ShowWindow(_h, SW_SHOW);
}
....
}
unfortunatlity the RegisterClassEx function actually always fails...
I am using C++ Builder 5 and compiling a console Application optioned as MultiThreaded but no VCL...
As #WhozCraig said Your window class doesn't have a wndproc. If you want to use winapi well, please study according to the official documentation. Your program needs a wndproc.
Here is how to create a blank window in MSDN.
Notice that the program does not explicitly call the WindowProc
function, even though we said this is where most of the application
logic is defined. Windows communicates with your program by passing it
a series of messages.
In the code, wc.lpfnWndProc = WindowProc specifies the process callback function.
I understood that a normal Win32 application using HWND and WNDPROC is not what I have done, but here is my solution :
HWND GetSTD()
{ static
HWND _result(0);
static
bool _lock(false);
static
bool _setup(false);
while(_lock) ::Sleep(0);
if(_setup == false)
{ _lock = true;
OSVERSIONINFO _os;
_os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
::GetVersionEx(&_os);
if(_os.dwPlatformId != VER_PLATFORM_WIN32s)
{ char _title[1024];
::GetConsoleTitle(_title, sizeof(_title));
_result = ::FindWindow(0, _title);
if(_os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{ _result = ::GetWindow(_result, GW_CHILD);
if(_result != 0)
{ char _class[128];
::GetClassName(_result, _class, sizeof(_class));
while(::strcmp(_class, "ttyGrab") != 0)
{ _result = ::GetNextWindow(_result, GW_HWNDNEXT);
if(_result != 0)
::GetClassName(_result, _class, sizeof(_class));
}
}
}
}
_setup = true;
_lock = false;
}
return _result;
}
Using the resulting HWND, we could draw over the console with the ::GetDC() and ::ReleaseDC() mechanism...
NB : static variables are used to ensure to return only 1 STD handle per call...

EnumChildWindows never calls its callback

I'm trying to manipulate a specific Internet Explorer 11 window. Using WinSpy++ I find that
The top level window's class is an IEFrame with the title of the document as the text (as returned by GetWindowText)
The actual web view class is called "Internet Explorer_Server" and is a child of the former.
I wrote a simple test case for finding the web view of IE11 opened on "https://encrypted.google.com/" in three different ways:
HWND FindIE_A()
{
// Use FindWindow, works!
HWND hWndTop = ::FindWindowA( NULL, "Google - Internet Explorer" );
// Find the web view window, the callback (FindIEServer) is NEVER called!
HWND hWnd = NULL;
::EnumChildWindows( hWndTop, &FindIEServer, (LPARAM)&hWnd );
return hWnd;
}
HWND FindIE_B()
{
// Use EnumChildWindows with NULL as parent, works!
HWND hWndTop = NULL;
::EnumChildWindows( NULL, &FindIEMain, (LPARAM)&hWndTop );
// Find the web view window, the callback (FindIEServer) is NEVER called!
HWND hWnd = NULL;
::EnumChildWindows( hWndTop, &FindIEServer, (LPARAM)&hWnd );
return hWnd;
}
HWND FindIE_C()
{
// Simple EnumWindows, works!
HWND hWndTop = NULL;
::EnumWindows( &FindIEMain, (LPARAM)&hWndTop );
// Find the web view window, the callback (FindIEServer) is NEVER called!
HWND hWnd = NULL;
::EnumChildWindows( hWndTop, &FindIEServer, (LPARAM)&hWnd );
return hWnd;
}
The callbacks that are very simple; get a property from the window and compare against a hard-coded value:
BOOL CALLBACK FindIEServer( HWND hWnd, LPARAM lParam )
{
char className[64];
::GetClassNameA( hWnd, className, sizeof(className) );
if ( !strcmp( className, "Internet Explorer_Server" ) )
{
*(HWND*)lParam = hWnd;
return FALSE;
}
return TRUE;
}
BOOL CALLBACK FindIEMain( HWND hWnd, LPARAM lParam )
{
char text[128];
::GetWindowTextA( hWnd, text, sizeof(text) );
if ( !strcmp( text, "Google - Internet Explorer" ) )
{
*(HWND*)lParam = hWnd;
return FALSE;
}
return TRUE;
}
EnumChildWindows failed (by not calling the callback AT ALL!) every time when provided with a parent window. Why?
The problem is that when I look for the window title, I was assuming there was only one window with that title. However Internet Explorer does some shenanigans and creates multiple windows with the same title however only one of them has the class IEFrame.
It just so happens that the first window found was the wrong one, it didn't have any children (and thus EnumChildWindows doesn't have anything to iterate over). Just adding an extra check for title + class works.
However as #wakjah suggested, it is better integrate IE (or any other browser) directly into your code. With google I found lots of documentation on how to do this with both IE and Chrome.

CreateWindow - window is not shown in IE

I have this BHO in C++ that I'm writing,
Basically what I'm trying to do is open a window, but it is not shown, I think it might have something to do with the HINSTANCE I passed to it. This is the code I use, anyone recognizing what's not right in this snippet?
Thanks :)
IServiceProvider* pServiceProvider = NULL;
if (SUCCEEDED(m_pWebBrowser->QueryInterface(
IID_IServiceProvider,
(void**)&pServiceProvider)))
{
IOleWindow* pWindow = NULL;
if (SUCCEEDED(pServiceProvider->QueryService(
SID_SShellBrowser,
IID_IOleWindow,
(void**)&pWindow)))
{
HWND hwndBrowser = NULL;
if (SUCCEEDED(pWindow->GetWindow(&hwndBrowser)))
{
HWND g_hwndMain;
g_hwndMain = CreateWindow(TEXT ("AnxJTest Class"),TEXT("My Window"),WS_POPUP | WS_VISIBLE,0, 0, 200, 300,NULL, NULL, (HINSTANCE)hwndBrowser, NULL);
ShowWindow(g_hwndMain, SW_SHOW);
}
pWindow->Release();
}
pServiceProvider->Release();
}

Add tooltip to a CStatic

I haven't been able to find a concise chunk of code that allows me to add/display tooltips to a CStatic (and CLed) control. Obviously, the standard code to do so does not apply for this type of control. Can someone post code snippets?
I hope this code will solve your problem .One important thing make NOTIFY property of CStatic =TRUE.
if( !m_ToolTip.Create(this))
{
TRACE0("Unable to create the ToolTip!");
}
else
{
CWnd* pWnd = GetDlgItem(IDC_STATIC_MASTER_PWD);
m_ToolTip.AddTool(pWnd,"Ok");
m_ToolTip.Activate(TRUE);
}
Let me know if any problem.
I don't know if this is still needed, but here's what I used to solve the problem:
just add SS_NOTIFY to dwStyle when creating the static label. (or simply set "Nofity" "True" in the properties). That worked fine for me.
When I add CStatic on Dialog based autocreated mfc application, tooltips don't show until I add RelayEvent in pretranslate dialog message
BOOL CTooltipStaticDlg::PreTranslateMessage(MSG* pMsg)
{
m_ToolTip.RelayEvent(pMsg);
return CDialog::PreTranslateMessage(pMsg);
}
I've had success with multiline tooltips using this simple class:
Create a class for ToolTips:
class ToolTip
{
public:
static HWND CreateToolTip(int toolID, HWND hDlg, UINT id);
};
Next, implement a tooltip creation function:
HWND ToolTip::CreateToolTip(int toolID, HWND hDlg, UINT id)
{
if (!toolID || !hDlg || !id)
{
return FALSE;
}
CString strTTText;
strTTText.LoadString( id );
// Get the window handle of the control to attach the TT to.
HWND hwndTool = ::GetDlgItem(hDlg, toolID);
// Create the tooltip window
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP |TTS_ALWAYSTIP,// | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL,
AfxGetInstanceHandle() , NULL);
if (!hwndTool || !hwndTip)
{
return (HWND)NULL;
}
// Associate the tooltip with the tool.
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hDlg;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hwndTool;
toolInfo.lpszText = (char*)(LPCTSTR)strTTText;
::SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
::SendMessageA(hwndTip, TTM_SETMAXTIPWIDTH, 0, 40); // force multi-line
return hwndTip;
}
Call it somewhere in your InitDialog:
CMyDialog::InitDialog()
{
ToolTip::CreateToolTip( PickAUniqueNumber, m_hWnd, IDS_MY_RESOURCE_STRING );
}
I've had on my dialog label with assigned custom ID IDC_PATH. I needed to turn on Notify flag (SS_NOTIFY) of the label and I needed to overload CWnd method OnToolHitTest and handle tooltip hit test like this:
INT_PTR CPath::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
INT_PTR r = CWnd::OnToolHitTest(point,pTI);
this->ClientToScreen(&point);
CRect rcLbl;
GetDlgItem(IDC_PATH)->GetWindowRect(&rcLbl);
if( rcLbl.PtInRect(point) )
{
pTI->uFlags |= TTF_IDISHWND;
pTI->uFlags &= ~TTF_NOTBUTTON;
pTI->uId = (UINT_PTR)GetDlgItem(IDC_PATH)->m_hWnd;
return IDC_PATH;
}
return r;
}
Then my dialog started to receive TTN_NEEDTEXT notification, which I handled and dynamicaly set text for tooltip.
BOOL CPath::OnTtnNeedText(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
{
UNREFERENCED_PARAMETER(id);
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT_PTR nID = pNMHDR->idFrom;
BOOL bRet = FALSE;
if (pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if(nID == IDC_PATH)
{
pTTT->lpszText = (LPSTR)(LPCTSTR)m_FullDestPath;
bRet = TRUE;
}
}
*pResult = 0;
return bRet;
}

How to get handles to all windows of another application

in my application i have timer, in TimerProc i want to get handles of all windows(main and child) of the another application that has focus. I have no idea how to do that because i don't understand functions like GetNextWindow or GetParent and Z-oder of windows and i can't find anywhere very detailed explanation of how this functions works(i dont understand explanation on msdn). Please can you give me some advice or block of code which do that? Many thanks for answer.
Use GetForegroundWindow() function - it returns the HWND of the window the user currently is working with.
Then having this handle you can retrieve childs in such a way:
HWND a_hWnd = (HWND)hParent;
HWND a_FirstChild = NULL;
a_FirstChild = ::GetWindow(a_hWnd, GW_CHILD);
if (a_FirstChild != NULL)
{
HWND a_NextChild = NULL;
do
{
a_NextChild = ::GetWindow(a_FirstChild, GW_HWNDNEXT);
if (a_NextChild != NULL)
{
a_FirstChild = a_NextChild;
}
}
while (a_NextChild != NULL);
}
GetForeGroundWindow to get the current foreground window/dialog
GetParent until you get NULL (that gets you to the top level window)**
EnumChildWindows to get to all the dependent windows
** Note that an application can have more than one top level window, though this isn't usual.
Code:
void Ccpp_testDlg::DoWalk ()
{
HWND hCurrent;
HWND hNew;
hCurrent = ::GetForegroundWindow ();
hNew = hCurrent;
while (hNew != NULL)
{
hNew = ::GetParent (hCurrent);
if (hNew != NULL)
{
hCurrent = hNew;
}
}
EnumChildWindows (hCurrent, EnumProc, 0);
}
BOOL CALLBACK EnumProc (HWND hwnd,LPARAM lParam)
{
TCHAR szText [MAX_PATH];
GetWindowText (hwnd, szText, sizeof(szText));
// do something with text
return TRUE;
}