Does anyone have an example of building a complete WIN32 Windows app as a dll?
I'd like to export a function, call it via rundll32, and have a complete Windows app with decorations, a menu, accelerators, and everything pop up.
I know about the calling convention for rundll32:
void CALLBACK TestEntryW(HWND hWnd, HINSTANCE hInst, LPWSTR pszCmdLine, int nCmdShow);
I can pull up a MessageBox from that function via the command: rundll32.exe test3.dll,TestEntry other params and args
I can load resources from my DLL by getting the DLL's handle via GetModuleHandle("test3.dll") and using that as hInst in my LoadString calls. That seems to be working for LoadIcon and LoadAccelerators as well, but I don't have working yet (baby steps..).
I can register a Windows class via RegisterClassEx using those strings and icons, but I must use the parent hInst or I get ERROR_CANNOT_FIND_WND_CLASS when calling CreateWindow. I think that's expected.
However, When I try to use that class in CreateWindow, it returns NULL, and so does GetLastError.
I can retrieve the window class of the hInst passed from rundll32 using GetWindowsLong(hWnd, GWL_ATOM). Using that for lpClassName, I can pull up a decorated window minus menus and accelerators, but it's a bit funky, as rundll's window class is normally only used for its message queue. I tried subclassing the window using SetWindowsLong to replace the WndProc and calling CallWindowProc instead of DefWindowProc in my dll's WndProc.
I'm hampered by being unable to debug it in MSVC++ 2010 Express. I replaced the project's command and command arguments with the appropriate entries so it launches it correctly, but it complains about no debugging info for rundll32.exe, and breakpoints etc. don't work.
Any ideas? Am I on the right track?
Related
I am creating a program in GoLang that has an optional console window. During normal operation, the window will be completely hidden (including the task bar) and I the user will interact with it through the system tray. I want to have an option that shows / hides the console window when the user presses a button in the tray. I've done this before in C# by doing this:
using System.Runtime.InteropServices;
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_HIDE = 0;
const int SW_SHOW = 5;
var handle = GetConsoleWindow();
// Hide
ShowWindow(handle, SW_HIDE);
// Show
ShowWindow(handle, SW_SHOW);
In order to do this in Go, I used this package: https://github.com/lxn/win. This package is a WinAPI wrapper for Go that will let me use all the same commands. Here is the code I used to do the same thing as the C# code above:
win.ShowWindow(win.GetConsoleWindow(), win.SW_SHOW)
Now this actually worked perfectly as intended on Windows 10, which does NOT use Windows Terminal by default. I'm running Windows 11 which does use Windows terminal, so I assume that's the reason this is not hiding. Instead, it simply minimizes the window instead of hiding it. Is it possible for me to either force my Go program to NOT use Windows Terminal or preferably get the Windows Terminal to hide like it does with Command Prompt?
Thank you for any help
EDIT: In Windows Terminal, you can go to the settings and set the default terminal application to "Windows Console Host" and that will use command prompt, but this is computer wide. This does fix the problem though. I would like this to just be for my program alone, so the problem still stands, but just making note of it.
I have an NPAPI plugin which makes use of SetWindowsHookEx under the hood to do some screen scraping. This plugin seems to run successfully on most machines I've tested. However, on one machine (32-bit Windows 7), when I'm running the plugin under Chrome (26.0.1410.43m), the call to SetWindowsHookEx crashes the process in which the plugin is hosted. It's not that SetWindowsHookEx returns an error - it simply crashes the process. And again, this only happens on one machine: it works fine on all the others we've tested.
But here's the weird thing. As you may know, Chrome has several ways of locating plugins. Normally, our setup.exe creates some registry entries that point to the plugin, like so (from the NSIS installer):
WriteRegStr HKLM "Software\MozillaPlugins\#alanta.com/WinVncCtl\" "Path" "$INSTDIR\npWinVnc.dll"
WriteRegStr HKLM "Software\MozillaPlugins\#alanta.com/WinVncCtl\" "ProductName" "Alanta Remote Desktop Server"
WriteRegStr HKLM "Software\MozillaPlugins\#alanta.com/WinVncCtl\MimeTypes\application/x-alanta-vnc" "Description" "Alanta's VNC Server NPAPI Plugin"
When Chrome loads the plugin from that location, it crashes on the SetWindowsHookEx call.
However, if I uninstall the plugin, then copy exactly the same DLL to %ProgramFiles%\Mozilla Firefox\Plugins\, then Chrome loads and runs the plugin just fine, and the call to SetWindowsHookEx() succeeds.
For what it's worth, here's the actual (pretty bog-standard) call:
// Add the CallWnd hook
hCallWndHook = SetWindowsHookEx(
WH_CALLWNDPROC, // Hook in before msg reaches app
(HOOKPROC) CallWndProc, // Hook procedure
hInstance, // This DLL instance
0L // Hook in to all apps
// GetCurrentThreadId() // DEBUG : HOOK ONLY WinVNC
);
The debugger indicates that all the parameters are pointing to legitimate, valid things.
Any suggestions for troubleshooting this? Anybody aware of any weirdnesses in SetWindowsHookEx that might show up in this scenario?
EDIT: The CallWndProc looks like this:
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// Do we have to handle this message?
if (nCode == HC_ACTION)
{
// Process the hook if the WinVNC thread ID is valid
if (vnc_thread_id)
{
CWPSTRUCT *cwpStruct = (CWPSTRUCT *) lParam;
HookHandle(cwpStruct->message, cwpStruct->hwnd, cwpStruct->wParam, cwpStruct->lParam);
}
}
// Call the next handler in the chain
return CallNextHookEx (hCallWndHook, nCode, wParam, lParam);
}
Breakpoints in the CallWndProc don't seem to get hit, so I suspect that the crash is happening during the setting of the hook rather than during its later processing.
If the same DLL behaves differently when placed in a different directory, it suggests this is changing the order in which plugins load.
(The directory a DLL loads from does not affect the search path used to locate and load its dependencies)
I would certainly take a look at other plugins being loaded on the same system and see if their presence is triggering (or perhaps even responsible for) your crash.
After that, I suggest uninstalling and reinstalling Chrome, possibly in a new directory, in case one of the Chrome binaries is corrupted or subverted.
Turns out that it was an aggressive security program. Apparently its heuristics allowed some DLLs through while not allowing others. It was killing the hosting process as soon as it saw the call to SetWindowsHookEx(). Replacing it with something reasonable fixed the problem.
I'm loading 3rd party DLLs and sometimes they open MessageBox windows that stops the flow of the application, I want to be able to detect when such thing happens.
I'm trying to use SetWindowsHookEx with WH_CBT but my callback does not get called.
I tried calling it this way:
SetWindowsHookEx (WH_CBT, myCallback, NULL, 0);
But it didn't worked.
What should be the right call for this function?
You may use the WM_ENTERIDLE message to detect if there's any MessageBox window, simply check with FindWindowEx().
This is C# but idea doesn't change:
http://social.msdn.microsoft.com/forums/en-US/winforms/thread/d3f89686-e4d0-4bb1-9052-31abef2a9d2a
I'm trying allow drag and drop to the tray icon on my application.
I know it's impossible to do this with the higher level C# WindowsForms API, since NotifyIcon doesn't support drag events.
So with a little help of a more windows-experienced friend I set out to try this via Win32 API. The idea was registering a hook in the tray window handler (after setting DragAcceptFiles(hWnd,TRUE); on the "SysPager" window handler).
The hooking and dropping part is working from the tray to the DLL.
LRESULT CALLBACK myHookProc (int code, WPARAM wParam, LPARAM lParam){
if (code == HC_ACTION)
{
PMSG msg = (PMSG) lParam;
switch(msg->message){
case WM_DROPFILES:
::MessageBox(NULL, L"Dropped files!", L"Test", MB_OK);
// call my app's registered hook
break;
}
return CallNextHookEx(oldHookProc, code, wParam, lParam);
}
As expected I get the message box popping up.
The problem is that I now need to call a function on my C# (WindowsForms) application to notify of this event. Here's where I ran into brick wall.
When I register the callback from my application in the DLL, I store it; but when myHookProc is called, it's value is NULL.
Turns out I was misunderstanding how DLLs work; there isn't a shared instance between my application and the tray area (they're copied or each has its own "instance" if you could call it that) so I can't use any static variables or anything like that to hold the callback reference back to my application.
Spent a couple of hours investigating this and the only solution seems to be shared memory (tried the #pragma data_seg I ran into in some forum, but to no avail), but it starts to feel too much of an overkill for such a "simple" use case.
So the million dollar questions are:
Is it really necessary to offload the hooking to a DLL?
Do I really need to resort to shared memory to accomplish this?
(Bonus question) WM_DROPFILES only works for files; how can I get a drop event fired for text?
Please keep in mind this is my first shot with .NET, C# and Win32 (less than a week); detailed answers explaining why - rather than just stating - will be greatly appreciated!
Thanks.
Yes, you really need to do those things because the window is owned by another process. Global hooks require a DLL that can be injected. Full D+D support requires RegisterDragDrop and COM code. Icky COM code.
And no, you really should not do this because somebody else might have already had the same idea as you. And got his program shipped first. The appcompat team at MSFT must have a nightmare with it. Careful with Raymond Chen, he's got a Bad Temper.
I am creating a shell extension in C++ (ATL 9) using Visual Studio 2008. The Shell Extension creates a global MSXML2::IXMLDOMDocumentPtr object m_XmlDoc in the module class. This m_XmlDoc is then used in the extension by all classes to read xml document.
The problem that I am facing is with Internet explorer. When the Shell Extension is active and I open/close internet explorer, I get a debug dialog and IE crashes. The error message says "Unhandled exception at 0x6aac30f1 in iexplore.exe: 0xC0000005: Access violation reading location 0x03050970."
When I click "break" on the message window, It takes me to the "Release" method of COM Smart Pointer and the error seems to be on
m_pInterface->Release();
This call was made from Module's destructor and also the value of m_pInterface is not NULL. I think maybe internet explorer is using the XML DOM and the call to Release creates some problem in it.
MSXML2::IXMLDOMDocumentPtr m_XmlDoc;
In _AtlModule.Init() method
::CoInitialize(NULL);
m_XmlDoc.CreateInstance(MSXML2::CLSID_DOMDocument40);
dllMain code:
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
::CoInitialize(NULL);
if (dwReason == DLL_PROCESS_ATTACH)
{
_AtlModule.Init();
CreateImageLists();
::DisableThreadLibraryCalls(hInstance);
}
hInstance;
return _AtlModule.DllMain(dwReason, lpReserved);
}
the use of DisableThreadLibraryCalls is discouraged, you seen it?
There are at least two problems with your code as posted:
You're calling CoInitialize in DllMain.
You're creating a COM object in DllMain.
It wouldn't surprise me if you're doing something in CreateImageLists() which you also shouldn't be doing in DllMain.
Also, the reason that your crash was "fixed" by not using the smart pointer is because now you're not actually releasing the object anymore. Your code is broken, and not releasing the reference isn't a valid way to fix anything.
I would suggest that you read, and then re-read, the documentation for DllMain paying particular attention to the things you should never do within your implementation of the function. As you'll see right up front:
Warning There are serious limits on what you can do in a DLL entry point. To provide more complex initialization, create an initialization routine for the DLL. You can require applications to call the initialization routine before calling any other routines in the DLL.
I suspect once you read it, and fix your code to create the COM object at a valid time, and release it at a valid time, your shell extension will stop crashing.
The problem was because of the COM Smart Pointer used for XmlDomDocument. I changed it to a normal pointer and it is working fine even in Vista.
This problem has a different behaviour in XP and Vista. In XP, I was getting an unhandled exception when I closed Internet Explorer. In Vista, I was not able to browse the virtual drive.