Necuima Posted November 21, 2014 Share Posted November 21, 2014 Hi, Can someone please help me with this code which just calls a DLL. The code works perfectly in the Dev-C++ IDE but gives me an error indicating that the LoadLibrary/GetProcessAddress fails when I try to execute it in the MS Visual C++ (2008 express) IDE. // A simple program that uses LoadLibrary and // GetProcAddress to access the printString function from HelloWorld_CPP.dll. // It also calls the function in the DLL passing a string to it. #include <stdafx.h> #include <windows.h> #include <stdio.h> #include <iostream> #include <string> #include <comdef.h> // needed to use LPCSTR typedef int (__cdecl *MYPROC)(LPCSTR); /* LP == long pointer. Just think pointer or char* C = const in this case I think they mean the character string is a const, not the pointer being const. STR is string (UTF-8 I think (one byte per character)) */ LPCSTR getInputString(void) { std::string theString; // define the variable to hold the string // std::cin.ignore(100, '\n'); // clear out the input buffer std::cout << "Enter the string\n"; std::getline(std::cin, theString); // get a whole sentence LPCSTR newString = theString.c_str(); // convert the entered string to LPCSTR format return newString; } int main(void) { HINSTANCE hinstLib; MYPROC ProcAdd; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; // Get a handle to the DLL module. hinstLib = LoadLibrary(TEXT("E:\\Documents\\Visual Studio 2008\\Projects\\DLL_Test\\HelloWorld_CPP.dll")); // If the handle is valid, try to get the function address. if (hinstLib != NULL) { ProcAdd = (MYPROC) GetProcAddress(hinstLib, "printString"); // If the function address is valid, call the function. if (NULL != ProcAdd) { fRunTimeLinkSuccess = TRUE; // OK, now get the string from the user console LPCSTR aString = getInputString(); (ProcAdd) (aString); // (ProcAdd) ("Message sent to the DLL function"); // the string that gets 'sent' to the function in the dll } // 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\n"); std::cin.get(); return 1; } } The environment is Windows 7, 64 bit. Any assistance will be most appreciated. Best regards, Necuima. Link to comment Share on other sites More sharing options...
Larry Posted November 21, 2014 Share Posted November 21, 2014 Could you please share the complete error? Link to comment Share on other sites More sharing options...
Necuima Posted November 21, 2014 Author Share Posted November 21, 2014 Hi Larry, It compiles OK but the execution fails with the "Unable to call the dll" message. I have tried single forward slashes in the LoadLibrary statement instead of the double back-slashes but the outcome is the same. In the Dev-C++ version it uses forward slashes but the Visual C++ seems to need the double back-slashes. I have triple-checked and the DLL is definitely there. My admittedly meagre understanding of DLLs is that it does not matter how they were created as long as they function correctly and are called correctly. The DLL called by the code above was developed on my PC in Dev-C++ and simply prints out the string passed to it in a message-box. I did this to try and learn a little about DLLs - how they are created and how they are used. Please correct me if my understanding is not correct, e.g., do I need to compile the DLL in Visual C++ as well? I will keep pursuing this as it's a complete mystery to me!! Again, any advice/suggestions will be most welcome. Cheers from Oz. Link to comment Share on other sites More sharing options...
Larry Posted November 22, 2014 Share Posted November 22, 2014 Compiling DLLs is not something I have much experience with. I was hoping the complete error message would be useful. Link to comment Share on other sites More sharing options...
Necuima Posted November 22, 2014 Author Share Posted November 22, 2014 Hi Larry, OK, I set a break point and ran it in debug mode and lo and behold the LoadLibrary statement fails with error "CXX0030: Error: expression cannot be evaluated". It is a bit of a mystery to me why the Dev-C++ executable, which executes exactly the same LoadLibrary statement as the Visual Studio version, works just fine yet the VS one gives this error. I will Google it further. Cheers from Oz. Link to comment Share on other sites More sharing options...
Necuima Posted November 22, 2014 Author Share Posted November 22, 2014 Hi again, Just a point of clarity - the error is not occurring in the DLL, it is occurring in the module (code above) which tries to call the DLL. If I can get past this, then we'll see if the DLL works OK when called by a MS Visual C++ executable rather than the one created by Dev-C++ (which as mentioned, works fine). Cheers, and thanks for the interest. Link to comment Share on other sites More sharing options...
Necuima Posted November 23, 2014 Author Share Posted November 23, 2014 Further thought - I suppose that it is possible that the Express version of Visual C++ 2008, which I am trying to use, does not support this?? But I can't find any evidence to support that conjecture! To quote the King of Siam 'Tis a puzzlement" !! Cheers. Link to comment Share on other sites More sharing options...
DiaDraw Posted November 25, 2014 Share Posted November 25, 2014 Hi Necuima, The way you call LoadLibrary looks reasonable and certainly works in Visual C++ (2010 Express). Provided it's LoadLibrary that fails, one possible cause might be that the DLL and your executable don’t match in terms of being 32-bit or 64-bit. A quick way to check that would be to add a line like this in your code: int numBytes = sizeof( void* ); then check if the value of numBytes is the same in Visual C++ project and in your Dev-C++ project. Maybe your Dev-C++ project luckily matches the DLL, but the Visual C++ one doesn’t. Another possibility is that one has been built with unicode support and the other one - without. You can check that in the project settings. If you have the code for it, your best bet would be to rebuild the DLL in Visual C++ and make sure its settings match your app project settings. Also, the error message you get looks like a red herring. Try adding GetLastError right after you call LoadLibrary and see if that gives you more useful information. Good luck, Radoslava, easynativeextensions.com Link to comment Share on other sites More sharing options...
Necuima Posted November 26, 2014 Author Share Posted November 26, 2014 Hi Radoslava, Many thanks for your reply and advice. I am trying to re-build the dll in VC++ 2008 EE but to be honest do not really know what I'm doing!! Here's my code: #include "stdafx.h" #define export extern "C" __declspec (dllexport) // this is the entry point to the dll BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ , DWORD reason /* Reason this function is being called. */ , LPVOID reserved /* Not used. */ ) { switch (reason) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } /* Returns TRUE on success, FALSE on failure */ return TRUE; } //Tell the c++ compiler to switch to standard C compiling so exported function names are not mangled extern "C" { //passing incoming string to MessageBox export double printString(LPCWSTR string) { //Return the string that the calling program passed to this function in a MessageBox. return (double) MessageBox(0,string,L"Sample Print String Function", 0); } } //end of C extern I got this code from another post somewhere - it worked for me once but now I can't even get it to compile in the Dev-C++ IDE!! My lack of knowledge in this area would fill volumes! The compiler error that I'm getting is unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup and .......\VS_2008_DLL\Debug\VS_2008_DLL.exe : fatal error LNK1120: 1 unresolved externals Any help will be most appreciated! Cheers from Oz. Link to comment Share on other sites More sharing options...
Necuima Posted November 26, 2014 Author Share Posted November 26, 2014 OK, I finally found a step-by-step guide on creating a DLL and then using it for a Visual C++ IDE. And it works!! Sorry if I have wasted anyone's time - please ignore the post above! If you're interested the link I found is http://msdn.microsoft.com/en-us/library/ms235636.aspx The example uses implicit linking - I will now try and modify it to use explicit linking!! Cheers from Oz. Link to comment Share on other sites More sharing options...
Necuima Posted November 26, 2014 Author Share Posted November 26, 2014 Re the explicit linking call to the dll - I feel (hopefully not being delusional) that I'm close. At least the LoadLibrary is loading the dll now. But I'm having trouble getting the address of a function in the dll. I can see that the dll indeed has functions (from the MSDN C++ IDE) but I can't seem to get the function name OK. Here's a code snippet of my GetProcAddress try: ProcAdd = (MYPROC) GetProcAddress(hinstLib, "MathFuncs::MyMathFuncs::Add"); // If the function address is valid, call the function. if (NULL != ProcAdd) { ...... I've tried "Add" on its own and various other combinations. Here's the .h file which I understand defines the function to the outside world: // MathFuncsDll.h #ifdef MATHFUNCSDLL_EXPORTS #define MATHFUNCSDLL_API __declspec(dllexport) #else #define MATHFUNCSDLL_API __declspec(dllimport) #endif namespace MathFuncs { // This class is exported from the MathFuncsDll.dll class MyMathFuncs { public: // Returns a + b static MATHFUNCSDLL_API double Add(double a, double ; // Returns a - b static MATHFUNCSDLL_API double Subtract(double a, double ; // Returns a * b static MATHFUNCSDLL_API double Multiply(double a, double ; // Returns a / b // Throws const std::invalid_argument& if b is 0 static MATHFUNCSDLL_API double Divide(double a, double ; }; } As always, any suggestions will be most welcomed! Cheers from Oz. Link to comment Share on other sites More sharing options...
Necuima Posted November 27, 2014 Author Share Posted November 27, 2014 Hi again, as far as I can see, I am doing things right but GetLastError() indicates that the procedure name can't be found - the exact error is "GetProcAdsdress failed with error 127: the specified procedure could not be found". OK, that's clear enough, but when I look at the dll file with DLL Export Viewer, it shows that a procedure with this name is there. The exact name that DLL Export Viewer shows is "public static double __cdecl MathFuncs::MyMathFuncs::Add(double, double)" with ordinal 1. Surely I don't have to key all that in? I have also tried to get the address of the procedure using the ordinal approach and while something is found, it does not seem to be the "Add" function in the dll as 10 + 10 = -SomeHugeNumber!! To use the ordinal approach I followed some advice in StackOverflow: int ordinal = 1; and then in the GetProcAddress: ProcAdd = (MYPROC) GetProcAddress(hinstLib, (LPCSTR) ordinal); Again, any help/ideas will be most appreciated! This is starting to drive me insane!! Link to comment Share on other sites More sharing options...
Necuima Posted November 30, 2014 Author Share Posted November 30, 2014 OK, I have managed to prove that the general approach works fine for a different dll file so it must be something to do with this specific dll and the ::s in "MathFuncs::MyMathFuncs::Add". I just don't understand this well enough I guess but at least I've been able to show that the general explicit call approach can work in my environment (Windows 7, 64bit). Thanks for anyone who looked at this and pondered how to help! Cheers from Oz. Link to comment Share on other sites More sharing options...
Larry Posted November 30, 2014 Share Posted November 30, 2014 Thanks for sharing your progress. Unfortunately, I've never created a DLL in C++ (I don't think), so I have absolutely no idea how one would help here. Sorry! Link to comment Share on other sites More sharing options...
Necuima Posted December 1, 2014 Author Share Posted December 1, 2014 Thanks Larry. My plan is to go back to basics and properly learn C++ (from your book and one which specifically targets the Visual C++ IDE that I am starting to use). If I ever figure it out, with your permission I could post the solution! Best wishes from Oz. Link to comment Share on other sites More sharing options...
Larry Posted December 1, 2014 Share Posted December 1, 2014 Please, please, do post the solution! Visual C++ is not something I ever touched, so anything you can share along those lines would be awesome. Good luck with it! Link to comment Share on other sites More sharing options...
Necuima Posted December 5, 2014 Author Share Posted December 5, 2014 OK, I bypassed the problem. I still don't know exactly what the problem was but it certainly is to do with the 'funny' function name "MathFuncs::MyMathFuncs::Add". My 'bypass' was to develop another DLL without the class structure of the MSDN example and it works just fine :-) I learned a few things along the way! To create a Windows DLL in Visual C++ there are a couple of pointers to note: - after all the normal includes, you 'tell the world' that this module is exporting a function for use by others. At first the term 'export' confused me but it seems to just mean that the function will be available to the outside world. The statement in my case is: #define export extern "C" __declspec (dllexport) - You can have functions within your DLL that are not visible to the outside world and they are just 'ordinary' C++ functions. - The function that needs to be made visible to the outside world, i.e. the one that is to be 'exported' needs to have it's name so that it won't get 'mangled' by the C++ compiler. So you include all that function's code within an 'extern' statement - in my case: extern "C" { then the beginning of the function itself: export int functionName(LPCSTR fileName, int param1 = 80, int param2 = 1000) .... ... and at the end: } //end of C extern The module that will call this dll function also needs some 'special' code - note that I am calling the dll explicitly - calling it implicitly is different and an example can be found in the MSDN tutorial mentioned above. So for the explicit call, after the usual includes I have: typedef int (__cdecl *MYPROC)(LPCSTR, int, int); As far as I understand, it states that this module will use an explicitly called DLL which will receive an LPCSTR and two ints as inputs and will return an int. I hope that this will be of help to some poor soul who, like me, Googled for literally weeks before finally getting this to work, and there was a lot of trial and error involved. But it's nice to have gained some understanding of DLLs and their use:-) Cheers from Oz. P.S., my environment for this is Windows 7, 64 bit and Visual C++ 2008 Express Edition. Link to comment Share on other sites More sharing options...
Larry Posted December 6, 2014 Share Posted December 6, 2014 Very cool! Sincerest kudos for figuring all that out and thanks for sharing what you learned! Link to comment Share on other sites More sharing options...
casinook99 Posted January 28, 2015 Share Posted January 28, 2015 OK! Thanks Larry. Link to comment Share on other sites More sharing options...
Recommended Posts