I am doing an RT simulator in VC++ 6.0. whenever it is executed, without the Open Architecture Computer(OAC,it is the Bus Controller in the Flight) switched on, the program executes properly. But with the OAC ON, the program is giving Debug assertion failed- in Debug/.exe/wincore.cpp at line no. 980. what may be the problem? Please provide with the solution if possible.
This is the copmlete DestroyWindow function.
BOOL CWnd::DestroyWindow()
{
if (m_hWnd == NULL)
return FALSE;
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);
#ifdef _DEBUG
HWND hWndOrig = m_hWnd;
#endif
#ifdef _AFX_NO_OCC_SUPPORT
BOOL bResult = ::DestroyWindow(m_hWnd);
#else //_AFX_NO_OCC_SUPPORT
BOOL bResult;
if (m_pCtrlSite == NULL)
bResult = ::DestroyWindow(m_hWnd);
else
bResult = m_pCtrlSite->DestroyControl();
#endif //_AFX_NO_OCC_SUPPORT
// Note that 'this' may have been deleted at this point,
// (but only if pWnd != NULL)
if (pWnd != NULL)
{
// Should have been detached by OnNcDestroy
#ifdef _DEBUG
//////////////////////////////HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!///////////////////
ASSERT(pMap->LookupPermanent(hWndOrig) == NULL); //line 980
#endif
}
else
{
#ifdef _DEBUG
ASSERT(m_hWnd == hWndOrig);
#endif
// Detach after DestroyWindow called just in case
Detach();
}
return bResult;
}
I think this problem has something to do with using CWnd::FromHwnd inappropriately, like storing the resulting pointer, and using it later. If something must be stored, it should be HWND, not CWnd*.
Another issue might be creating window in one thread and destroying it in another.
The problem is most likely that somewhere you are calling CWnd::GetSafeHwnd(), and still using that HWND handle at the time the window is being destroyed. In other words, you're destroying a CWnd whose handle is still active somewhere else.
One solution is to override virtual BOOL DestroyWindow(), and make sure you release your handle there.
For example, if you're showing a modal dialog box from an Acrobat plug-in, you have to pass your window handle to Acrobat, to let it know that you're in modal mode:
int CMyDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// Put Acrobat into modal dialog mode
m_AVdlgWin = AVWindowNewFromPlatformThing(AVWLmodal, 0, NULL, gExtensionID, GetSafeHwnd());
AVAppBeginModal(m_AVdlgWin);
AVWindowBecomeKey(m_AVdlgWin);
return 0;
}
Of course you need to perform the opposite in DestroyWindow, to make sure the internal handle is released:
BOOL CMyDialog::DestroyWindow()
{
// Take Acrobat out of modal dialog mode, and release our HWND
AVAppEndModal();
AVWindowDestroy(m_AVdlgWin);
return CDialog::DestroyWindow();
}
This example assumes CMyDialog is always modal.
If you fail to release a handle obtained by GetSafeHwnd, that's when you get the assertion failure. What exactly releasing a handle means depends on what you did with it. One can only guess.
Related
How can I have a Windows tray notification icon for an out-of-process COM server, developed using VS2019?
So far I have tried just adding one with Shell_NotifyIconA(NIM_ADD, &n); as per the MSDN documentation. .However if I set the NOTIFYICONDATA::m_hWnd to 0 then this call is rejected with 0x80004005 (Invalid handle).
So I have to specify a window handle that the icon's messages will go to, but the application currently doesn't have any windows. It does have a message pump which is found at ATL::CAtlExeModule<T>::RunMessageLoop() (that's part of the ATL boilerplate code) but I can't see any mention of where a window handle is to send messages to this loop.
I've tried using a Message-only Window created with CWindowImpl::Create, however when the program runs, the behaviour is unexpected. A blank space appears in the notification tray (the icon does not show properly), and mousing or clicking on the space does not cause the message handler to be entered. The log message appears indicating Shell_NotifyIcon() succeeded and the handles are valid, but no further log messages.
What's the right way to do this in VS2019? (I have done it before in C++Builder which lets you simply add a form, mark it as the main form, and add a notification icon component to it).
Code for the ATLExeModule (this is the boilerplate code plus my modifications):
class CNotifyWnd : public CWindowImpl<CNotifyWnd>
{
public:
BEGIN_MSG_MAP(CMyCustomWnd)
MESSAGE_HANDLER(WM_USER+1, OnMsg)
END_MSG_MAP()
LRESULT OnMsg(UINT, WPARAM, LPARAM, BOOL&)
{
DEBUG_LOG("Received notification");
return 0;
}
};
static void create_notifyicon()
{
auto * pw = new CNotifyWnd;
HWND hwnd = pw->Create(HWND_MESSAGE);
auto hInst = GetModuleHandle(NULL);
NOTIFYICONDATAA n{};
n.cbSize = sizeof n;
n.hIcon = LoadIcon(NULL, IDI_SHIELD);
#pragma warning(disable : 4996)
strcpy(n.szTip, "Tooltip string");
n.dwInfoFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
n.uVersion = NOTIFYICON_VERSION;
n.hWnd = hwnd;
n.uID = 1234;
n.uCallbackMessage = WM_USER + 1;
int hr = Shell_NotifyIconA(NIM_ADD, &n);
DEBUG_LOG("Shell_NotifyIcon = {}; Icon handle {}, window {}",
hr, (uint64_t)n.hIcon, (uint64_t)n.hWnd);
}
class CMyProjectModule : public ATL::CAtlExeModuleT< CMyProjectModule >
{
public :
DECLARE_LIBID(LIBID_MyProjectLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYPROJECT, "{d0d2e9f7-8578-412a-9311-77ff62291751}")
using Parent = ATL::CAtlExeModuleT< CMyProjectModule >;
HRESULT PreMessageLoop(int nShowCmd) throw()
{
HRESULT hr = Parent::PreMessageLoop(nShowCmd);
create_notifyicon();
return hr;
}
};
CMyProjectModule _AtlModule;
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd)
{
return _AtlModule.WinMain(nShowCmd);
}
The code in the question is mostly correct, however dwInfoFlags should be uFlags. After making that change the notify icon worked as intended.
Thanks to commentors who suggested ways to simplify the original code in the question, and the idea of a "message-only window" created by setting the parent to HWND_MESSAGE.
I'm trying to create an application that will be notified about each active window change in Windows so it could do some tasks like detecting window titles, therefore "punishing" bad people accessing bad content on our PC machines. So, this is really important for the application because it's purpose is to log "bad" applications from history.
So, in my main function, I started a thread for my WindowLogger.
windowThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) WindowLogger,
(LPVOID) argv[0], 0, NULL );
if (windowThread)
{
// Also a bit of protection here..
return WaitForSingleObject(windowThread, INFINITE);
}
Then, here is my WindowLogger procedure:
// Function called by main function to install hook
DWORD WINAPI
WindowLogger(LPVOID lpParameter)
{
HHOOK hWinHook;
HINSTANCE hExe = GetModuleHandle(NULL);
if (!hExe)
{
return 1;
}
else
{
hWinHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) CBTProc, hExe, 0);
MSG msg;
// I AM UNSURE ABOUT THIS PART..
// Probably wrong code :D ..
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
if (msg.message == HCBT_ACTIVATE) {
// my code to log the window name
}
}
UnhookWindowsHookEx(hWinHook);
}
return 0;
}
And finally, my CBTProc callback function, it logs the windows using my log() function:
LRESULT CALLBACK
CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (nCode)
{
case HCBT_ACTIVATE:
{
HWND foreground = GetForegroundWindow();
char window_title[50];
if (foreground)
GetWindowText(foreground, window_title, 25);
log("|");
log(&window_title[0]);
log("|");
}
}
}
So I had debugged the program and what I figured out is that hWinHook becomes NULL after SetWindowsHookEx() -- this is what probably causes my program to mailfunction..
.. Can you help me out with this?
Thanks in advance.
Passing 0 for the dwThreadId parameter to SetWindowsHookEx is used to register a hook for all threads in the system, i.e. a global hook. However to do this, your hook code needs to be located within a DLL (so that the DLL can be mapped into the address space of other processes). Since your hook code is in your main executable rather than a DLL the call is failing.
I have a fairly complex requirement. My STA COM object is implemented in a DLL (can't move it to out-of-process EXE). By the means of DllSurrogate I am hosting my object in a dllhost.exe process. My object has an UI attached to it (a plain modeless dialog) but I need the PreTranslateAccelerator mechanism in order for some shortcuts to work, etc. Since COM activates my object and hosts it in the default dllhost.com, I am obviously not controlling the message pump.
Is there still a way to pre-translate messages in this scenario? I doubt COM has foreseen such a specific scenario but maybe I am missing something.
Okay here it is. I hope I didn't leave out anything important. Basically, I have created a custom CMyComCreator instead of the default one. Instead of just creating a COM object and returning an interface pointer, I spin a worker UiThread. I use MyData structure to pass data across threads. Once the worker thread has finished setting up, I use the CComGITPtr to transfer the marshalled interface pointer from the UiThread back to the main. The consumers (out-of-process) end up with interface pointers that talk directly to the UiThread bypassing the main thread. You may think of CMyDialog as a modeless dialog which sends a PostQuitMessage on destruction to terminate the message loop. That's all. May look cumbersome but it works good.
struct MyData
{
ATL::CComGITPtr<IUnknown> Unk;
ATL::CEvent Event;
HRESULT hr;
MyData() : hr(E_OUTOFMEMORY), Event(FALSE, FALSE) { }
};
static CMessageLoop * MessageLoop;
class CMyComCreator
{
public:
static HRESULT WINAPI CreateInstance(
_In_opt_ void* pv,
_In_ REFIID riid,
_COM_Outptr_ LPVOID* ppv)
{
ATLASSERT(ppv != NULL);
if (ppv == NULL)
return E_POINTER;
*ppv = NULL;
HRESULT hRes = E_OUTOFMEMORY;
MyData* data = NULL;
ATLPREFAST_SUPPRESS(6014 28197)
/* prefast noise VSW 489981 */
ATLTRY(data = _ATL_NEW MyData)
ATLPREFAST_UNSUPPRESS()
if (data != NULL)
{
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, UiThread, (void *)data, 0, NULL);
if (thread)
{
WaitForSingleObject(data->Event, INFINITE);
CloseHandle(thread);
hRes = data->hr;
if (SUCCEEDED(hRes))
{
ATL::CComPtr<IUnknown> unk;
hRes = data->Unk.CopyTo(&unk);
if (SUCCEEDED(hRes))
{
hRes = unk->QueryInterface(riid, ppv);
}
}
}
delete data;
}
return hRes;
}
};
typedef CMyComCreator _CreatorClass;
static unsigned __stdcall UiThread(void * param)
{
CoInitializeEx(0, COINIT_APARTMENTTHREADED);
MyData * data = (MyData *)param;
ATL::CComObject<CMyDialog> * bb;
data->hr = ATL::CComObject<CMyDialog>::CreateInstance(&bb);
ATL::CComPtr<IUnknown> unk((IDispatch *) bb);
data->Unk = unk;
unk.Release();
data->Event.Set();
if (SUCCEEDED(data->hr))
{
CMessageLoop theLoop;
MessageLoop = &theLoop;
int nRet = theLoop.Run();
MessageLoop = NULL;
}
CoUninitialize();
return 0;
}
I needed to pack everything in a single DLL.
In which case, DllSurrogate is not the only way of doing this. There's also Rundll32:
INFO: Windows Rundll and Rundll32 Interface
This would allow you to run your own message loop inside the DLL's EntryPoint and have complete control over message processing, including PreTranslateMessage. You can copy the message loop logic from an ATL EXE server.
Bear in mind, there's still 32-bit and 64-bit version of "RunDll32.exe" in every 64-bit Windows OS. Use the one which matches the bit-ness of your DLL.
I would like to write a program, which lets me change a values in text box of different program, or automatically copy a values from one program to another.
I found a way to get hWnd to most (no idea if all of them) of controls in targer program, and to point them with mouse cursor. I made a simple struct to do so, and an array of it
struct hWndpointer
{
HWND hWnd;
AnsiString text;
};
hWndpointer tbl[250];
The EnumWindowProc and EnumChildWindowProc loads handles and text of the window into the array and into the list control in my program, so i can click an item on the list (or select it with keyboard) and the cursor points the control (like button or textbox) like expected... Unfortunately there are some controls with no text (or rather GetWindowText returns no text) so there is no way to identify the control.
The question is:
Is there any way to get/read a NAME of the control?
Is there any way to get/read and set a specyfic value like 'enabled' or 'text' or 'value'?
Thanks in advance
PS: Sorry for my english ;)
You can use SendMessage and PostMessage to send WM_GETTEXT, WM_SETTEXT, WM_ENABLE to windows owned by other processes. (SendMessage for queries, PostMessage for write-only actions)
Often the child ID will be used to identify subwindows (especially in a dialog), but it's also possible for a program to rely purely on the dynamic HWND values, in which case you'll have to fall back to window positions to differentiate.
From the Win32 API's perspective, UI controls do not have Names, so you cannot ask the API to return the Name of a UI control in another process because such a value does not exist. Names are strictly a feature of the UI framework being used by the app (VCL in the case of C++Builder), and you cannot directly access frameworks across process boundaries. You would need cooperation from the control's owning app.
For instance, one way would be to have both apps call RegisterWindowMessage() to register a custom window message, then your app can post that message to the other app specifying the desired control's HWND and your own HWND as parameters. The other app can then SendMessage() the control's Name back to your app's HWND using the WM_COPYDATA message, which you can use to update your list accordingly.
In the VCL framework, you can convert an HWND to a TWinControl* pointer using the FindControl() function. It will return NULL if the HWND does not belong to the calling process, otherwise you can then copy the value from its Name property. For example:
const UINT WM_GETCONTROLNAME = RegisterWindowMessage("WM_GetControlName");
const UINT WM_GETCONTROLNAME_RESULT = RegisterWindowMessage("WM_GetControlName_Result");
#include <pshpack1.h>
struct sControlName
{
HWND hWnd;
int Length;
char Value[1];
};
#include <poppack.h>
void __fastcall TMyForm::WndProc(TMessage &Message)
{
if ((Message.Msg == WM_COPYDATA) && (WM_GETCONTROLNAME_RESULT != 0))
{
LPCOPYDATASTRUCT cds = (LPCOPYDATASTRUCT) Message.LParam;
if (cds->dwData == WM_GETCONTROLNAME_RESULT)
{
sControlName *pName = (sControlName*) cds->lpData;
AnsiString sName(pName->Value, pName->Length);
// locate pName->hWnd in your list and assign sName to it as needed...
return;
}
}
TForm::WndProc(Message);
}
void ___fastcall TMyForm::FillList()
{
...
if (WM_GETCONTROLNAME != 0)
{
HWND TheControlHWND = ...;
HWND OtherAppHWND = ...;
PostMessage(OtherAppHWND, WM_GETCONTROLNAME, (WPARAM)TheControlHWND, (LPARAM)this->Handle);
}
...
}
.
const UINT WM_GETCONTROLNAME = RegisterWindowMessage("WM_GetControlName");
const UINT WM_GETCONTROLNAME_RESULT = RegisterWindowMessage("WM_GetControlName_Result");
#include <pshpack1.h>
struct sControlName
{
HWND hWnd;
int Length;
char Value[1];
};
#include <poppack.h>
void __fastcall TMyForm::WndProc(TMessage &Message)
{
if ((Message.Msg == WM_GETCONTROLNAME) && (WM_GETCONTROLNAME != 0) && (WM_GETCONTROLNAME_RESULT != 0))
{
HWND hWnd = (HWND) Message.WParam;
TWinControl *Ctrl = FindControl(hWnd);
if (Ctrl)
{
AnsiString sName = Ctrl->Name;
std::vector<unsigned char> buffer((sizeof(sControlName) - 1) + sName.Length());
sControlName *pName = (sControlName*) &buffer[0];
pName->hWnd = hWnd;
pName->Length = sName.Length();
strncpy(pName->Value, sName.c_str(), pName->Length);
COPYDATASTRUCT cds = {0};
cds.dwData = WM_GETCONTROLNAME_RESULT;
cds.cdData = buffer.size();
cds.lpData = pName;
SendMessage((HWND)Message.LParam, WM_COPYDATA, (WPARAM)this->Handle, (LPARAM)&cds);
}
return;
}
TForm::WndProc(Message);
}
I am trying to subclass the window that currently has focus. I do this by monitoring for HCBT_ACTIVATE events using a CBT hook, and set and unset the WndProc of the focused and previously focused windows.
The problem is that it only works whenever I have a breakpoint set somewhere in the code.
If there is no breakpoint, once my application exits, all the windows that I have subclassed crashes in order, even though I have removed the subclassing and restored the original WndProc.
I have verified that Unsubclass() is called whenever my application shuts down.
// code extracts
HINSTANCE hInst;
HHOOK hHook;
#pragma data_seg(".shared")
HWND hWndSubclass = 0;
FARPROC lpfnOldWndProc = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:.shared,rws")
void Unsubclass()
{
// if the window still exists
if (hWndSubclass != 0 && IsWindow(hWndSubclass))
{
SetWindowLongPtr(hWndSubclass, GWLP_WNDPROC, (LPARAM)lpfnOldWndProc);
hWndSubclass = 0;
}
}
static LRESULT CALLBACK SubClassFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_MOVING)
{
// this is just test code so I can see it works (it does)
RECT* r = (RECT*)lParam;
r->right = r->left + 500;
r->bottom = r->top + 500;
return TRUE;
}
else if (message == WM_DESTROY)
{
Unsubclass();
}
return CallWindowProc((WNDPROC)lpfnOldWndProc, hWndSubclass, message, wParam, lParam);
}
void SubclassWindow(HWND hWnd)
{
// remove the subclassing for the old window
Unsubclass();
// subclass the new window
lpfnOldWndProc = (FARPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)SubClassFunc);
hWndSubclass = hWnd;
}
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_ACTIVATE)
{
SubclassWindow((HWND)wParam);
}
return 0;
}
// ... code that initializes the CBT proc
__declspec(dllexport) BOOL Setup()
{
hHook = SetWindowsHookEx(WH_CBT, CBTProc, hInst, 0);
}
__declspec(dllexport) BOOL Teardown()
{
UnhookWindowsHookEx(hHook);
Unsubclass();
}
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD Reason,
LPVOID Reserved
)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
return TRUE;
case DLL_PROCESS_DETACH:
Unsubclass();
return TRUE;
}
return TRUE;
}
Your problems hinge on several fronts:
UnHookWindowsHook does not unload injected dlls, all it does is remove the hook proc. If the dlls need to be unloaded its up to them to invent some kind of unloading mechanism.
SetWindowLongPtr typically fails when called from a process other than the process that owns the window.
The nett result of this is, its very difficult to safely remove windows hooks. First thing, your OldWindowProc pointer should not be stored in the shared data area. Next, in order to remove the subclass, you need to be able to co-erce the (currently) subclassed process to perform the un-subclassing.
What you could do is, first, register a new unique message id and place it in your shared area using RegisterWindowMessage. WM_REMOVE_HOOK.
UINT idWM_REMOVE_HOOK = RegisterWindowMessage("WM_REMOVE_HOOK");
Now, whenever you need to remove a hook,
SendMessage(hWndSubClass,idWM_REMOVE_HOOK,0,0);
In your subclass proc:
if(uMsg == WM_DESTROY || uMsg == idWM_REMOVE_HOOK)
{
Unsubclass(hwnd);
}
Remove the call to UnSubClass in DLL_PROCESS_DETATCH. Its a dangerous race condition thats going to cause your dll being unloaded in some random process to trash the hook data of a potentially valid hook in another process.
lpfnOldWndProc and hWndSubclass are global pointers. Seems like you've got only one per process. What if a process creates more than one window?
Then you will unsubclass only the last one.
EDIT: Also, why do you tear down in Process DETACH?
You are creating a global system-wide hook in a DLL. You need to store the HHOOK handle and your subclassing information in a block of shared memory so all instances of your DLL in all running processes can have access to them. Your variables are declared global in code, but each individual instance of the DLL will have its own local copy of them, and thus they will not be not initialized in all but 1 of your DLL instances (the one that calls Setup()). They need to be shared globally within the entire system instead.
You also should not be calling TearDown() in DLL_PROCESS_DETACH, either. Every instance of the DLL is going to call TearDown() when their respective processes terminate, but only the single instance that actually called Setup() should be the one to call Teardown().
If the debugger will cause the process to succeed by adding a breakpoint then most likely, this is a timing issue.
What possibly happens is that your main application is closing itself and freeing resources just before the subclassed windows get the messages they need to remove the subclass again. You might want to give them a few processing cycles to handle their own messages between the unhooking and the unsubclassing. (In Delphi you could do this by calling Application.ProcessMessages but in your C++ version? Don't know the answer to that.