18

I have an executable (that I created using Visual C++ 10), and I need to use its capabilities from another program I wrote (same environment). Due to complex deployment requirements which I won't go into, building a DLL from the required functionality and loading it in both programs is not something I can do.

So I thought that I can __declspec(dllexport) some functions in the EXE, and then LoadLibrary() will let me GetProcAddress() them.

Obviously this can't be done, though when I started looking at it - it looked feasible.

Specifically, when you __declspec(dllexport) functions in an EXE project, Visual C++ also generates a lib file for dynamic linking - so you don't even need to use LoadLibrary() - just link against the resulting lib and call the functions.

Unfortunately, the main problem is that when you declare the resulting file as an EXE, Visual C++ adds the "CRTmain" entry point into the resulting file, instead of the "CRTDLLmain" that a DLL gets. When Windows (automatically) LoadLibrary() the EXE from your main program, it doesn't call the the "CRTDLLmain" entry point (because it doesn't exist), the C runtime for the module doesn't get initialized, and as a result all interesting work (such as memory allocation) fails with interesting(*) runtime exceptions.

So as follows, my question is: is there a way to cause Visual C++ to build into the resulting file both the "CRTmain" entry point and the "CRTDLLmain" entry point?

(*) "Interesting" as in an old Chinese curse.

Guss
  • 30,470
  • 17
  • 104
  • 128
  • Can you expose an "init" function in the exe which explicitly does the initialization of the C runtime? – Asaf Oct 01 '13 at 08:01
  • https://en.wikipedia.org/wiki/May_you_live_in_interesting_times – Prof. Falken Oct 01 '13 at 08:16
  • @Asaf: I wouldn't know how - this is something that the compiler does automatically and as far as I know has no public interface. – Guss Oct 01 '13 at 13:29
  • 1
    If you'll debug your 'main' function in the exe, I think you'll see the exact function that is called for initializing the CRT (main() is called within some function which code is exposed). But another idea - if DLL's are not possible, why not extract the functionality to a static library and link this into both exe's? – Asaf Oct 01 '13 at 20:30
  • 1) Yes, but the CRT initialization sequence is deep VC++ private internals - I rather not duplicate it, especially without understanding, especially in the face of future upgrades to newer compilers. I think I can't use an API unless it is public. – Guss Oct 02 '13 at 09:25
  • 2) Using a static library is not possible because of my weird deployment requirements, which I won't go into except that the main requirement is that an end user can replace a single file to get updated functionality. By using a static lib, I'm forcing the user to update the whole installation to get new functionality. – Guss Oct 02 '13 at 09:26

3 Answers3

18

Yes it is possible.

http://www.codeproject.com/Articles/1045674/Load-EXE-as-DLL-Mission-Possible

The idea is a) to patch the IAT and b) to call the CRT before calling your exports.

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
  • 3
    Wow, that's some deep magic there. I'm no longer working on that project but that would have been interesting to try, though I didn't understand half of what was going on in the IAT patching code. – Guss Nov 11 '15 at 21:36
-1

Simply no! The Problem is that the CRT and in the EXE you want load, uses some globle variables. You main EXE does the same. So how should Memory allocation work?

If you want to use such a structure you must use a DLL to be Aware of meulti threading, CRT initialization ans all this other stuff. You need this!

But what about COM Automation? Wouldn't tis be an easy solution to use your code in one EXE from another?

xMRi
  • 14,982
  • 3
  • 26
  • 59
  • 1
    I don't see how your comment is relevant to the discussion. Generally speaking, DLLs (standard ones, not EXEs masquerading as such) can have global variables just fine - because each module in Windows has a different heap. Also, I don't see how multi-threading has any bearing on the issue. – Guss Oct 01 '13 at 13:31
  • Regarding COM automation - you mean having my reusable code as a COM server? Interesting approach but as far as I understand COM automation, this will preclude using the EXE as a tool that can be run, with its own `main` that does something useful. – Guss Oct 01 '13 at 13:32
  • @Guss, I know several years have passed, but you can use a single EXE for a COM server and a normal client. Microsoft Word is a perfect example. Run it normally, you get a UI. Create an instance of `Word.Application` and you will find a process started with `winword.exe -Embedding`. [The `-Embedding` flag is passed by COM](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683844(v=vs.85).aspx). – Mitch Oct 31 '16 at 15:31
  • I'm aware of the option of building a COM server, but I don't want to expose the functionality as a COM module because of deployment requirements, API requirements and security. But regardless, I'm no longer in a position were this is relevant for me. – Guss Oct 31 '16 at 18:40
-3

The short answer, is "no". After looking far and wide, there is no way to get VC++ to do what I want, and quite likely not any other compiler.

The main issue is that the main() entry point most people know and love is not the real entry point in C++ executables: the compiler needs to do a lot of initialization work to get the "C++ Run Time library" to a usable state, as well as initialize globals, statics and the likes. This initialization uses different code in shared libraries than in executables and there is no way to one to behave like another.

One thing that possibly can be done, is to build the shared functionality into a DLL, and for the primary executable to embed the DLL as a resource, and load it from a memory mapped region of the executable file (there are several code samples how to do this with VC++ on stackoverflow and elsewhere on the web). Now another program can do the same thing by loading the DLL from the bundling executable.

Guss
  • 30,470
  • 17
  • 104
  • 128