DllImport .exe, How to initialize run-time library
-
Thursday, November 20, 2008 10:21 PMI would like to treat an .exe like a .dll and use a couple of functions from it. I created a simple char.dll and char.exe from this code:
char.h
__declspec
(dllexport) extern char toUpperCase(char c);char.c
#include
<ctype.h>
#include "char.h"
char toUpperCase(char c){ return toupper(c); }
int main(){ return 0; }
I then call it from .NET, in this case F#:
[<DllImport(
"char.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)>]
extern char toUpperCase(char c)
let
a = toUpperCase('a')
It works just fine when I use "char.dll", but when I use "char.exe", I get an error like this:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I believe the error is because the C Run-Time is not being initiallized when the .exe is loaded. Is there any way to make the .exe behave like the .dll and initialize the CRT when it is loaded? I've been reading about the Run-Time Library Behavior here: http://msdn.microsoft.com/en-us/library/988ye33t.aspx but I'm not sure what to do yet.
Cameron
All Replies
-
Saturday, November 22, 2008 6:08 AM
I've almost got it working. My solution was to compile with /BASE set so that pinvoke would look up the entry point for the exe(acting as a dll) correctly. I'm attempting to create a custom entry point that calls the exe startup function if it is exe or the dll startup function if it is loaded as a dll (in this case by pinvoke). When used as a dll, it appears to be calling EntryPoint() appears to be called more than once.
Any ideas why EntryPoint() is called more than once. My assumption is that it calls it for both DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH. Any way to find out what the dll process should be pass it to _DllMainCRTStartup instead of the hardcoded DLL_PROCESS_ATTACH. Current code:
int mainCRTStartup(); int __stdcall _DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved); int EntryPoint(){ void * hExe; void * hThis; hExe = GetModuleHandle(NULL); hThis = NULL; GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, EntryPoint, &hThis); if( hThis == hExe ){ return mainCRTStartup(); } else { return _DllMainCRTStartup(hThis, DLL_PROCESS_ATTACH, NULL); } } -
Tuesday, November 25, 2008 3:18 AM
I set the Entry Point and Base Address in project settings (Linker > Advanced), but the custom entry point is not being executed when the compiled as an .exe and loaded as a .dll. I thought that was working last week, but I must have been mistaken.
This may or may not be the reason:
http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-08/0119.html
Anyone know how to get a custom entry point to execute when an .exe is loaded from pinvoke?
If that worked, then this would be a solution:/* An exe and a dll are both Portable Executable (PE) files [1]. Depending on which configuration type you choose, Visual C++ will compile in different default initialization functions [2]. The main thing the functions do is initialize and clean up the C Run-Time (CRT). Required C/C++ Project Settings: C/C++ Code Generation > Runtime Library: /MD for Release, /MDd for Debug, [5] page 159 Linker > Advanced > Entry Point & Base Address I used EntryPoint as my function name at the default exe base address of 0x00400000. The base address needs to be explicitly defined since the default dll base address is 0x1000000. Other resources: [3] [4] [5] [1] http://en.wikipedia.org/wiki/Portable_Executable [2] Visual Studio 9.0\VC\crt\src crtexe.c crtdll.c [3] Visual C++ Run-Time Library Behavior http://msdn.microsoft.com/en-us/library/988ye33t.aspx [4] How To Use the C Run-Time http://support.microsoft.com/kb/94248 [5] Windows via C/C++, 5th Ed Chapter 4 Processes, especially pages 74-75 Chapter 20 DLL Advanced Techniques, The DLL's Entry-Point Function */ #include <windows.h> int WinMainCRTStartup(); // GUI ANSI, [5] page 69 BOOL WINAPI _DllMainCRTStartup( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ); // crtdll.c BOOL WINAPI DllMain( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ){ return TRUE; } static BOOL attached = FALSE; int EntryPoint(){ HMODULE hExe; HMODULE hThis = NULL; hExe = GetModuleHandle(NULL); GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)EntryPoint, &hThis); if( hThis == hExe ){ // as exe return WinMainCRTStartup(); } else { // as dll if(attached == FALSE){ if( _DllMainCRTStartup(hThis, DLL_PROCESS_ATTACH, NULL) == TRUE ){ attached = TRUE; return 0; // no errors } } else { if( _DllMainCRTStartup(hThis, DLL_PROCESS_DETACH, NULL) == TRUE ){ attached = FALSE; return 0; // no errors } } } return 1; // error }
Cameron- Edited by ctaggart Tuesday, November 25, 2008 3:20 AM spelling error
-
Friday, November 28, 2008 3:44 AMModerator
Hi,
Based on my understanding,
1.When you are using "char.exe", char.exe is running as a standalone process. So, unless you are writing some interprocess communicating codes, from another .NET process, you can not access the exported function in it?
2.When you are using "char.dll", the .NET process will load this native dynamical link library into its virtual memory space. So, it can call the exported function correctly.
The recommendation way is putting all exported functions in a dll(char.dll). Then you can share its functionility from other applications. In this case, your native char.exe can use the char.dll to perform the ToUpperCase(). Meantime, you can also use PInvoke to call the ToUppderCase() function from .NET site.
Thanks,
Ji
Please remember to mark the replies as answers if they help and unmark them if they provide no help.- Marked As Answer by Ji.ZhouModerator Friday, November 28, 2008 3:44 AM

