none
DllImport .exe, How to initialize run-time library

    Question

  • I 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

    Thursday, November 20, 2008 10:21 PM

Answers

  • 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.
    Friday, November 28, 2008 3:44 AM

All replies

  • 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);  
        }  
    Saturday, November 22, 2008 6:08 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
    Tuesday, November 25, 2008 3:18 AM
  • 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.
    Friday, November 28, 2008 3:44 AM