1

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?

Rohan
  • 52,392
  • 12
  • 90
  • 87
petiepooo
  • 218
  • 1
  • 6
  • 4
    You don't need (and shouldn't use) the host window's instance handle. Register the class against your own instance (obtained from DllMain) and create your window against that. – Raymond Chen Aug 10 '12 at 20:16
  • 2
    Note also that rundll32 is not a recommended engineering practice. You are at the mercy of rundll32's DPI scaling, TS-awareness, large-address-space, and other settings. Also, if any rundll32-based task triggers the fault tolerant heap, then all rundll32-based tasks will use the fault tolerant heap. – Raymond Chen Aug 10 '12 at 22:05
  • Thanks. I was able to get it working with that advice. I'm using the hModule passed in DllMain for the hInstance when retrieving resources.I also had to manually instantiate my menu rather than specifying the resource in the window class. – petiepooo Aug 13 '12 at 17:41
  • Eg: `hMenu = LoadMenu(hDllMainMod, MAKEINTRESOURCE(IDC_TEST3));` and `hWnd = CreateWindowEx(WS_EX_APPWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, hParentWnd, hMenu, hInstance, NULL);` – petiepooo Aug 13 '12 at 17:53
  • @RaymondChen can you please expand on the limitations you mentioned: For my application, I don't think I need TS-awareness, but I'm curious about the other limitations. For context, I'm trying to put a CPlApplet, Win32 service, an installer, and a systray app all into a single DLL. Since the apps will be launched via shortcut or batchfile, having to call via rundll32 shouldn't matter. I'm also running into issues using svchost, but I'll save that discussion for a different post... – petiepooo Aug 13 '12 at 17:58
  • To clarify, I guess it wasn't your advice that got it working for me. I had to use the parent's hInst in registering the class and creating the window. If I used the DLL's module handle, 'CreateWindow()' fails with 'ERROR_CANNOT_FIND_WND_CLASS' or worse. However, if I used the parent's instance handle, then it succeeds, but I still have to use the DLL's handle to load resources. FWIW, it's just a basic SDI form with an about box for now, but everything seems to be working in Win8RP (without TS-awareness, DPI-scaling, etc.) – petiepooo Aug 13 '12 at 18:23
  • The point is not that you don't need TS-awareness. The point is that rundll32 is marked `/TSAWARE` ("I promise to follow all Terminal Services rules"). It also promises that it is compatible with the /3GB switch. These are just examples. There are other promises that Rundll32 makes, and future promises may be added in the future. Your DLL must adhere to all of them. (As for the class registration: If you are getting `ERROR_CANNOT_FIND_WND_CLASS` then you are doing something wrong.) – Raymond Chen Aug 13 '12 at 19:36

0 Answers0