3

Windows has an utility called rundll32.exe that can execute native dynamic link libraries as applications.

Say I have a piece of code that prints "Hello World!" to the console. Is it possible to write a library in C++ (preferably Visual C++) that can be executed using rundll32.exe and will run this code? If so, how?

Bart
  • 19,692
  • 7
  • 68
  • 77
Michael Bikovitsky
  • 903
  • 2
  • 10
  • 20
  • 4
    You know, google "rundll32", check the **DOCUMENTATION** (i.e., RTFM), and just do it. OK, I will do just that and present result as an "answer". But really, finding out such things is very much part of what programming is about, it is a fundamental skill, which you should train! – Cheers and hth. - Alf Aug 11 '12 at 19:07
  • @Alf, only undocummented stuff should be asked on SO? – Petter Nordlander Aug 11 '12 at 20:15
  • @Petter: I think, a question about something one does not understand is good. A question about where to find the relevant info when one is stuck, is also goode. But a question which simply offloads the work of reading the documentation, to someone else, is bad. However, apparently most SO denizens disagree with this view. The more "difficult" questions are regularly closed as "not constructive" or "not possible to answer" (quite often with some definitive answer already given). – Cheers and hth. - Alf Aug 11 '12 at 20:25
  • @Alf, I guess you have a point in this case, but in general, I think a question is a question and the rest is just a matter if it get's answered in detail or just with a lmgtfy link to it. – Petter Nordlander Aug 11 '12 at 20:40
  • possible duplicate of [Running a full windows app in a dll via rundll32](http://stackoverflow.com/questions/11908541/running-a-full-windows-app-in-a-dll-via-rundll32) – Raymond Chen Aug 12 '12 at 00:15
  • @Raymond: the possible duplicate you found concerns presenting a GUI, while this question concerns console text presentation. There are additional problems for the latter (see my answer). So, this question is **not a duplicate**, and additionally the question you found has no answer and will probably never get one (since the OP described that he didn't actually have any problem with getting his function called). – Cheers and hth. - Alf Aug 12 '12 at 03:34

4 Answers4

10

Googling "rundll32", the 3rd hit was a link to documentation,

http://support.microsoft.com/kb/164787

According to that documentation, rundll32 calls a user-specified function with signature like wWinMain (except the first argument here is a window handle instead of an instance handle),

void CALLBACK
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);

So, trying this out:

// File [foo.def]
EXPORTS
    sayHello
// File [foo.cpp]
#include <iostream>

namespace myCode {

    void sayHello()
    {
        using namespace std;
        cout << "Hello, world!" << endl;
    }

}    // namespace myCode

#undef UNICODE
#define UNICODE
#include <windows.h>

extern "C" 
__declspec( dllexport )
void CALLBACK sayHello( HWND, HINSTANCE, wchar_t const*, int )
{
    AllocConsole();
    freopen( "CONIN$", "r", stdin ); 
    freopen( "CONOUT$", "w", stdout ); 
    freopen( "CONOUT$", "w", stderr ); 

    DWORD const infoBoxOptions = MB_ICONINFORMATION | MB_SETFOREGROUND;
    MessageBox( 0, L"Before call...", L"DLL message:", infoBoxOptions );
    myCode::sayHello();
    MessageBox( 0, L"After call...", L"DLL message:", infoBoxOptions );
}

Building & running:

[d:\dev\test]
> cl foo.cpp foo.def user32.lib /MD /LD /D _CRT_SECURE_NO_WARNINGS
foo.cpp
   Creating library foo.lib and object foo.exp

[d:\dev\test]
> rundll32 foo.dll,sayHello

[d:\dev\test]
> _

The output is presented in its own console window, created via AllocConsole, which is generally necessary since rundll32 is a GUI subsystem program (this is also the reason for the freopen calls).

To present the output in an existing console window one can just omit the calls to AllocConsole and freopen, and redirect standard output of rundll32 to a pipe. E.g. standard output can be piped through Windows’ more when the output is just a few lines, or through some *nix-utility cat for more lines. However, in the standard command interpreter [cmd.exe] it doesn’t work to just redirect the output to con.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • @Alf: Your "build & running" does not actually show the expected output. – wilx Aug 11 '12 at 21:04
  • @wilx: you can just try it, you know. – Cheers and hth. - Alf Aug 11 '12 at 21:06
  • I need to be more humble. Stumbling on this answer again I had to try it in order to notice the `AllocConsole` call in there. The output is presented in its own console window, which is necessary since `rundll32` is a GUI subsystem program. Updating the answer to explain this. Grumble... – Cheers and hth. - Alf Feb 06 '14 at 10:26
3

http://support.microsoft.com/kb/164787

This MSDN article I believe is still accurate; you define an entrypoint as

  void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
Joe
  • 41,484
  • 20
  • 104
  • 125
2

While it is possible to use rundll32 to run a properly-designed function in a DLL, it is not recommended. Doing so means that your DLL is at the mercy of rundll32's process settings (large address awareness, terminal service awareness, DPI awareness, elevation manifest, etc.) Even worse: If some other rundll32 process triggers an application compatibility behavior (such as low fragmentation heap), then that will affect all rundll32 processes including yours.

Just write a separate EXE.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
0

Like said by Joe and yourself, use something like this:

 void CALLBACK func(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) 
 { 
   std::cout << "Hello world!" << std::endl; 
 }

However, CALLBACK = __stdcall, which, when your "func" is exported will changed to _func@16

You could change this name, http://support.microsoft.com/kb/140485

so, you might want to try something similar to this:

rundll32.exe DLLTest.dll,_func@16 
Petter Nordlander
  • 22,053
  • 5
  • 50
  • 84
  • -1 doesntwork. Hm, how about *trying* your answer before posting it? – Cheers and hth. - Alf Aug 11 '12 at 19:52
  • 1
    well, according to the documentation (Joe and you, Alf posted a link to it) it would export by default to _EntryPoint@16 if no .def file was used. My idea was that this small change was what was what was missing. However, I now noticed that it applied to C code only, not C++ complied code. I should perhaps remove this post anyway since you have such a nice answer. – Petter Nordlander Aug 11 '12 at 20:12
  • One problem is that `rundll32` is a GUI subsystem program, at least in Windows 7, so by default there's no console. Ordinarily one can just redirect standard output to work around that, but in this case the standard library is not loaded by the main program, but by the DLL. So it needs a bit of a workaround: nothing fancy though, and googling finds easy recipes (which I just followed). – Cheers and hth. - Alf Aug 11 '12 at 20:19