CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 19
  1. #1
    Join Date
    May 2002
    Posts
    1,798

    How to call a C++ dll function at runtime ?

    Despite an enormous amount of information available on runtime dynamic linking of DLLs, I cannot get things to work using Win 7 / VS 2010. While there are many pitfalls, my current problem is how to find the 'decorated' names. Here is a snippet of a header file for my dll (lap.dll):
    Code:
    #ifdef LAP_EXPORTS
    #define LAP_API __declspec(dllexport)
    #else
    #define LAP_API __declspec(dllimport)
    #endif
    
    #include "Parser.h"
    
    
    // This class is exported from the LAP.dll
    class LAP_API Clap {
    public:
    	Clap(void);
    	~Clap(void);
    
    // Attributes
    protected:
    	char * m_pList;
    	double ** m_fMatrix;
    	CParser * m_pParser;
    
    // Operations
    public:
    	void PutMatrix(double ** pMatrix);
    	double ** GetMatrix();
    	void DumpMatrix(double ** pMatrix);
    	double **CreateMatrix(int nRows, int nCols);
    	void FreeMatrix(double ** pMatrix);
    	double ** Parse(char * expr);
    	int GetOpMode();
    	int SaveVariableMap(char * sfile);
    	int LoadVariableMap(char * sfile);
    	char * GetKeyList();
    	char * GetVarList();
    	char * GetFunList();
    	void AddVariable(TNT::Matrix<double> Mc, char * svarnam);
    	int EraseAllVariables();
    	int RunScript(char * sfile);
    	int ProcessScript(char* sscript);
    	
    };
    and here is the lap.def file:
    Code:
    LIBRARY
    
    EXPORT
    
    	PutMatrix
    	GetMatrix;
    	DumpMatrix
    	CreateMatrix
    	FreeMatrix
    	Parse
    	GetOpMode
    	SaveVariableMap
    	LoadVariableMap
    	GetKeyList
    	GetVarList
    	GetFunList
    	AddVariable
    	EraseAllVariables
    	RunScript
    	ProcessScript
    Both lap.dll and the test app compile, but I cannot figure out how to define the correct function prototypes in the test file.

    Here's a fragment of the test file. The handle comes back as valid, but I cannot get the proc address correctly:
    Code:
    #include "stdafx.h"
    
    #include <windows.h> 
    #include <stdio.h> 
    
    typedef double ** PARSEPROC(LPSTR);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	cout << "Normal Beginning" << endl << endl;
    
        HINSTANCE hinstLib; 
        PARSEPROC ProcAdd; 
        BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; 
     
        // Get a handle to the DLL module.
     
        hinstLib = LoadLibrary(TEXT("lap.dll")); 
     
        if (hinstLib != NULL) 
        { 
    		printf("\nHandle is valid\n");
    
    		ProcAdd = (PARSEPROC) GetProcAddress(hinstLib, "Parse"); 
            // If the function address is valid, call the function.
     
            if (NULL != ProcAdd) 
            {
    			printf("\nProcAdd is not NULL\n\n");
    
                fRunTimeLinkSuccess = TRUE;
            }
            // Free the DLL module.
     
            fFreeResult = FreeLibrary(hinstLib); 
        } 
    
        // If unable to call the DLL function, use an alternative.
        if (! fRunTimeLinkSuccess) 
            //printf("Message printed from executable\n"); 
    		printf("Unable to call the DLL function\n");
    
    	printf("\n\nNormal Termination\n\n");
    
    
    	getchar(); 
    
    	return 0;
    }
    All my efforts have failed to capture the procedure address. In fact, the way the test app is written here, it will not compile as it will not allow assignment (or casting) of the GetProcAddress, even though GetProcAddress(hinstLib, "Parse"); by itself will compile and run. I am uncertain whether this problem is due to name decoration, test app syntax, def file syntax, or some other problem.

    There used to be a way to set the compiler to generate docorated names file when compiling a dll, but I can not find such a tool in VS 2010. The DumpBin.exe tool needed to have the path to mspdb100.dll set. When run against lap.dll, it DumpBin produces the following :
    Code:
    File Type: DLL
    
      Summary
    
            2000 .data
            3000 .idata
           18000 .rdata
            7000 .reloc
            1000 .rsrc
           BA000 .text
           59000 .textbss
    which I have no clue as to what it means.

    Any help greatly appreciated. But I've looked at a number of tutorials and most are either outdated or deal only with C declared function. It is worth noting that lap.dll has performed flawlessly when used as a staically bound dll.
    Last edited by Mike Pliam; July 30th, 2011 at 10:02 PM.
    mpliam

  2. #2
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: How to call a C++ dll function at runtime ?

    most are either outdated or deal only with C declared function
    I deal with dlls since 1996. And I'm still not aware of a way how to wire up a pure C++ class from dll dynamically, what actually you're trying to do.

    Well, the available options are:
    • wrap the class into COM class
    • expose a needed subset of class functions as interface

    In other words, you have to re-design the dll to let it be linked at runtime. Or make a proxy dll with plain C exports which links the dll statically (the way most of plugins do).
    Last edited by Igor Vartanov; July 30th, 2011 at 10:35 PM.
    Best regards,
    Igor

  3. #3
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: How to call a C++ dll function at runtime ?

    While there are many pitfalls, my current problem is how to find the 'decorated' names.
    Well, your current problem looks pretty trivial comparing to what you gonna face to with the rest of "many pitfalls."
    Best regards,
    Igor

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449

    Re: How to call a C++ dll function at runtime ?

    Quote Originally Posted by Mike Pliam View Post
    The handle comes back as valid, but I cannot get the proc address correctly:
    Instead of going through trial and error with calling GetProcAddress, you should know that this function works in a very simple manner. In addition you can use the GUI tool Dependency Walker to get the list of exported names, and those exported names are the only valid ones that GetProcAddress will work with.

    As to GetProcAddress, whatever name you state in the second parameter must match exactly with the name that is exported from the DLL. This includes casing, any special characters such as @, ?, etc. So if the exported function is "SomeClass@Parse@@int??" or some other weird name, then that is the name you must use for GetProcAddress to work. GetProcAddress doesn't know anything about name mangling, non-mangled names, def files, nothing. All it knows about is that final name that shows up in the export table of the DLL, and that is the name you must use to return a valid address.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; July 30th, 2011 at 11:00 PM.

  5. #5
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: How to call a C++ dll function at runtime ?

    Mike, in addition to what Paul just said. I believe you don't see a difference between global C++ function and C++ class member function. Suppose you obtained the function address, what you could do with that? Calling it directly gonna crash your app for 100&#37;. To be called properly, the Clap object should be created first. Which means Clap constructor should be resolved and called properly. And so on and so forth...
    Best regards,
    Igor

  6. #6
    Join Date
    May 2002
    Posts
    1,798

    Re: How to call a C++ dll function at runtime ?

    Igor asked:
    what actually you're trying to do.
    I want to give an application interface away for free, then charge for modular updates. I think the runtime dynamic linking dll is the way to go here. 1) Your client only needs to download and install a new dll and not the whole program interface 2) if the dll called by the client is not available (he didnt purchase it yet), the program can handle it and it will still run(unlike what happens if a static dll is missing). To accomplish this, the main app interface needs to be able to call the new dll function(s). Since there are only a few functions in the dll that serve as a gateways to the dll library, this shouldnt be much of a problem. I think that this is the method used by many programs to provide updates, add-ons, and plug-ins.

    Paul, I downloaded and employed DependencyWalker, dragging lap.dll onto it's main window, and was quickly able to obtain a complete list of the decorated function names. THANKS! With that, I am able to obtain a Proc Address that is presumably valid. Now, how to use that address to execute the desired function in the test app?

    Code:
    #include "stdafx.h"
    
    #include <windows.h> 
    #include <stdio.h> 
    
    typedef double ** PARSEPROC(LPSTR);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        HINSTANCE hinstLib; 
    	FARPROC ParseProcAddr;
        BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; 
     
        // Get a handle to the DLL module.
     
        hinstLib = LoadLibrary(TEXT("lap.dll")); 
     
        if (hinstLib != NULL) 
        { 
    		printf("\nHandle is valid\n");
    
    		ParseProcAddr = GetProcAddress(hinstLib, "?Parse@Clap@@QAEPAPANPAD@Z");  // Tochiba
    		
    		if (ParseProcAddr == NULL) { printf("ParseProcAddr is NULL\n"); }
    
            // If the function address is valid, call the function.
     
            if (NULL != ParseProcAddr) 
            {
    			printf("\nParseProcAddr is not NULL\n\n");
    
                fRunTimeLinkSuccess = TRUE;
     
    			double ** pMatrix;
    			//pMatrix = (double **)(ParseProcAddr)("x = 3");
          }
            // Free the DLL module.
     
            fFreeResult = FreeLibrary(hinstLib); 
        } 
    
        // If unable to call the DLL function, use an alternative.
        if (! fRunTimeLinkSuccess) 
     		printf("Unable to call the DLL function\n");
    
    	return 0;
    }
    Output:
    Handle is valid

    ParseProcAddr is not NULL

    So the problem now becomes, given a function prototype definition, double ** PARSEPROC(LPSTR), and given a presumably valid dll procedure address, FARPROC ParseProcAddr, how do I use these to execute the procedure and retrieve the double ** ? That which I have commented out above will not compile for reasons of both assignment and casting errors.
    mpliam

  7. #7
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: How to call a C++ dll function at runtime ?

    Why not use COM where the interface is compiler and platform independent?

    Trying to expose C++ classes is a pain due to name decoration. And the real problem is the decoration could change between compiler versions or even compiler update.

    For this to work reliably, you'll need to build the app and the new plugins with the same compiler. I would avoid that situation if I were you.

  8. #8
    Join Date
    Apr 1999
    Posts
    27,449

    Re: How to call a C++ dll function at runtime ?

    Quote Originally Posted by Mike Pliam View Post
    Paul, I downloaded and employed DependencyWalker, dragging lap.dll onto it's main window, and was quickly able to obtain a complete list of the decorated function names. THANKS!
    However, I agree with Arjay. You do not want to get into the business of using mangled names, as that can change very easily (and is not compiler independent).

    Either you use COM, or you use non-mangled names and create 'C' exported functions (similar to how most professional non-COM DLL's are done).

    For the latter, you probably have to rethink your design in terms of trying to export a class. Instead you need to create a "Matrix API" that creates, destroys, and manipulates a Matrix, without having the client to even know there is a class internal to the DLL that is working behind the scenes.

    Regards,

    Paul McKenzie

  9. #9
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: How to call a C++ dll function at runtime ?

    Quote Originally Posted by Mike Pliam
    I want to give an application interface away for free, then charge for modular updates.
    Then your approach of native exporting C++ class is wrong. What you need is "expose a needed subset of class functions as interface". Of course additionally you'll need some API for object creation/destruction, like Paul already said. The technique is really mature and proven to be safe and effective. With certain effort your dll becomes even cross language compatible and this way installable in third party apps, letting you reach clients beyond C++. As I mentioned, most of plugins go this way.
    Last edited by Igor Vartanov; August 1st, 2011 at 02:36 AM.
    Best regards,
    Igor

  10. #10
    Join Date
    May 2002
    Posts
    1,798

    Re: How to call a C++ dll function at runtime ?

    OK. I get the point. I have abandoned the idea of exporting class members and have began to experiment with writing simple C language DLL exports. I have attached a small demo that shows how to use runtime dynamic dll linking to export functions that return integers, doubles, and double pointers. But the pointers present a problem that Paul helped me to solve some time ago. Namely, once memory is allocated in the dll space, how does one deallocate that memory. With static linking and using class member exports, one could take advantage of the class destructor to free allocated memory and thus avoid memory leaks. But I cannot figure out how to do memory cleanup using only C. Note that the attached demo works but with considerable memory leak.
    Attached Files Attached Files
    mpliam

  11. #11
    Join Date
    Apr 1999
    Posts
    27,449

    Re: How to call a C++ dll function at runtime ?

    Quote Originally Posted by Mike Pliam View Post
    But the pointers present a problem that Paul helped me to solve some time ago. Namely, once memory is allocated in the dll space, how does one deallocate that memory
    There should be another exported function that the client calls to clean up the memory and do any other housekeeping to remove the Matrix.

    In addtion, the client shouldn't know the internals of how to clean up or properly destroy the Matrix. Today it could be delete[], tomorrow it could be GlobalFree(), next year it could be some other function internally -- the client shouldn't need to know this (or care).

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; August 1st, 2011 at 12:07 PM.

  12. #12
    Join Date
    May 2002
    Posts
    1,798

    Re: How to call a C++ dll function at runtime ?

    Not so easy though, Paul. I think you and I have been down this road before.

    Say the dll code contains the following declarations:
    Code:
    extern MY_API double * pVector;
    
    // Get rid of name mangeling
    extern "C"
    {
    ...
    	MY_API double * fvec(void);
    ...
    	MY_API void cleanup(void);
    ...
    }
    and in the implementation file:
    Code:
    MY_API double * pVector;
    
    double * CreateVector(int nSize)
    {
    	// Allocate memory including leading size containing byte
    	pVector = new double [nSize + 1];
    
    	memset(pVector, 0x00, nSize+1);
    
    	return pVector;
    
    }// CreateVector(int nSize)
    
    void FreeVector(double * pVector)
    {
        delete [] pVector; 
    	pVector = NULL;
    
    }// FreeVector()
    
    ...
    
    MY_API double * fvec(void)
    {
    	pVector = CreateVector(5);
    	pVector[0] = 5.0;
    	pVector[1] = 6.432;
    	pVector[2] = 1.543;
    	pVector[3] = 2.654;
    	pVector[4] = 3.765;
    	pVector[5] = 5.876;
    	return pVector;
    }
    
    ...
    
    MY_API void cleanup(void)
    {
    	if(pVector != NULL) { FreeVector(pVector); pVector = NULL; }
    	_RPT0(0, "cleanup ran ok\n");
    }
    Then if I execute the vector producing function and the cleanup using runtime dynamic linking in the test app,
    Code:
    typedef double *(*FVEC)();
    typedef void (*CLEANUP)();
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int iOrg = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);	
    	_CrtSetDbgFlag(iOrg | _CRTDBG_LEAK_CHECK_DF);
    
    	cout << "Normal Beginning" << endl << endl;
    
        	HINSTANCE hinstLib; 
       	 BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; 
    
    	FVEC _MYVEC = NULL;
    	CLEANUP _MYCLEANUP = NULL;
    
        	// Get a handle to the DLL module.
     
       	 hinstLib = LoadLibrary(TEXT("my.dll")); 
     
       	 if (hinstLib != NULL) 
       	 { 
    		_MYVEC = (FVEC)GetProcAddress(hinstLib, "fvec");
    		_MYCLEANUP = (CLEANUP)GetProcAddress(hinstLib, "cleanup");
    
            		// If the function address is valid, call the function.
     		if (NULL != _MYVEC) 
    		{
    			printf("\n_MYVEC is not NULL\n\n");
    
               			 fRunTimeLinkSuccess = TRUE;
     
    
    			printf("%0.0f\n", _MYVEC()[0]);
    			for(int i=1; i <= _MYVEC()[0]; i++)
    			{
    				printf("%0.3f  ", _MYVEC()[i]);
    			}
    			printf("\n");
    		}
    
    		if (NULL != _MYCLEANUP) 
    		{
    			printf("\n_MYCLEANUP is not NULL\n\n");
    
               			 fRunTimeLinkSuccess = TRUE;
     
    			_MYCLEANUP();
    		}
    
           		 // Free the DLL module.
            		fFreeResult = FreeLibrary(hinstLib); 
        } 
    
        // If unable to call the DLL function, use an alternative.
        if (! fRunTimeLinkSuccess) 
     	printf("Unable to call the DLL function\n");
    
    	return 0;
    }
    the test application compiles and runs just fine, and I can see that the 'cleanup ran ok', yet there remains a memory leak corresponding to the memory allocated for the vector.

    What am I doing wrong?
    mpliam

  13. #13
    Join Date
    May 2005
    Location
    Estonia
    Posts
    235

    Re: How to call a C++ dll function at runtime ?

    I use Notepad, to see decorated stuff.
    No third party tools needed.

    Rate my post if i it was useful!

  14. #14
    Join Date
    Feb 2002
    Posts
    4,640

    Re: How to call a C++ dll function at runtime ?

    Where does the "decorated stuff" start and end? It's a lot easier to use a tool that will tell you *exactly* what the decorated name is (instead of making guesses).

    Viggy

  15. #15
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: How to call a C++ dll function at runtime ?

    Quote Originally Posted by Mike Pliam View Post
    What am I doing wrong?
    If I counted correctly, you're calling _MYVEC() (and in turn fvec() and CreateVector() inside the DLL) a total of 12 times. Each of these calls except the first one not only allocates a new vector, it also overwrites the pointer to the previous one. When you finally call _MYCLEANUP(), this merely deallocates the last vector you allocated. Hence there are 11 vector memory blocks leaking.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured