Thread: Loading a DLL at runtime

  1. #1
    Registered User filler_bunny's Avatar
    Join Date
    Feb 2003
    Posts
    87

    Loading a DLL at runtime

    Hi all,

    I have a problem with this DLL... I am trying to load the DLL at runtime but it is causing an error when the function pointer pfnEdrCent is called.

    This is driving me mad because it looks very similar to the code that I have seen on the net and in the Petzold book and I am sure that the DLL is loading correctly. The only thing that I can assume is that the function pointer is pointing nowhere, but I can't see why.

    Thanks.

    FB

    The windows proc:
    Code:
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HDC					hdc;
    	PAINTSTRUCT			ps;
    	RECT				rect;
    	// Typedef - create a typedef for the pointer to a function
    	typedef BOOL (WINAPI * EDRCENT) (HDC, PRECT, PCSTR);
    	static HINSTANCE	hLibrary;
    	EDRCENT		pfnEdrCent;
    
    	switch(message)
    	{
    	case WM_CREATE:
    		{
    			if ((hLibrary = LoadLibrary(TEXT("edrlib.dll"))) == NULL)
    			{
    				MessageBox (hwnd, TEXT("Cant load edrlib.dll"), TEXT("Error"), 0);
    				return -1;
    			}
    		}
    		return 0;
    
    	case WM_PAINT:
    				
    		hdc = BeginPaint(hwnd, &ps);
    		GetClientRect (hwnd, &rect);
    				
    		pfnEdrCent = (EDRCENT) GetProcAddress(hLibrary, TEXT("EdrCenterText"));
    
    		((pfnEdrCent)(hdc, &rect, TEXT("This is a string")));
    
    		EndPaint(hwnd, &ps);
    		
    		return 0;
    
    	case WM_DESTROY:
    		if (hLibrary)
    			FreeLibrary(hLibrary);
    
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hwnd, message, wParam, lParam);
    }
    The DLL header:
    Code:
    //
    //EDRLIB.H Header file
    //				
    
    #ifdef __cplusplus
    #define EXPORT extern "C" __declspec (dllexport)
    #else
    #define EXPORT __declspec (dllexport)
    #endif
    
    EXPORT BOOL CALLBACK EdrCenterTextA (HDC, PRECT, PCSTR);
    EXPORT BOOL CALLBACK EdrCenterTextW (HDC, PRECT, PCWSTR);
    
    #ifdef UNICODE
    #define EdrCenterText EdrCenterTextW
    #else
    #define EdrCenterText EdrCenterTextA
    #endif
    and the DLL source:
    Code:
    //
    // EDRLIB.C -- Easy drawing routines
    //
    
    #include <windows.h>
    #include "edrlib.h"
    
    int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
    {
    	return TRUE;
    }
    
    EXPORT BOOL CALLBACK EdrCenterTextA (HDC hdc, PRECT prc, PCSTR pString)
    {
    	int iLength;
    	SIZE size;
    
    	iLength = lstrlenA (pString);
    
    	GetTextExtentPoint32A (hdc, pString, iLength, &size);
    
    	return TextOutA (hdc, (prc->right - prc->left - size.cx) / 2,
    						  (prc->bottom - prc->top - size.cy) / 2,
    				     pString, iLength);
    }
    
    EXPORT BOOL CALLBACK EdrCenterTextW (HDC hdc, PRECT prc, PCWSTR pString)
    {
    	int iLength;
    	SIZE size;
    
    	iLength = lstrlenW (pString);
    
    	GetTextExtentPoint32W(hdc, pString, iLength, &size);
    
    	return TextOutW(hdc, (prc->right - prc->left - size.cx) / 2,
    						 (prc->bottom - prc->top - size.cy) / 2,
    					pString, iLength);
    }
    Visual C++ .net
    Windows XP profesional

  2. #2
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Code:
    #ifdef UNICODE
    #define EdrCenterText EdrCenterTextW
    #else
    #define EdrCenterText EdrCenterTextA
    #endif
    This is fine but....

    Code:
    pfnEdrCent = (EDRCENT) GetProcAddress(hLibrary, TEXT("EdrCenterText"));
    The conditional definition does not apply to the exported symbols....

    Ask for EdrCenterTextA or EdrCenterTextW......

    And ALWAYS check the return of GetProcAddress for NULL.....one slipup will crash your prog.

  3. #3
    Registered User filler_bunny's Avatar
    Join Date
    Feb 2003
    Posts
    87
    Geez your fast at replying Fordy!

    Thanks.

    I have tried your suggestion and I asked for EdrCenterTextW (and EdrCenterTextA), however it still caused the same problem. So I did the sensible thing and checked the return value of GetProcAddress, and sure enough it is returning NULL.
    Code:
    	pfnEdrCent = (EDRCENT) GetProcAddress(hLibrary, TEXT("EdrCenterTextW"));
    	if (pfnEdrCent == NULL)
    	    MessageBox(NULL, TEXT("Error: GetProcAddress returned NULL"), TEXT("Error!"), 0);
    But I cannot see why.
    Visual C++ .net
    Windows XP profesional

  4. #4
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    So call GetLastError() and see why it returned NULL.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  5. #5
    Registered User filler_bunny's Avatar
    Join Date
    Feb 2003
    Posts
    87
    So call GetLastError() and see why it returned NULL.
    Yup. Good point.

    I have since simplified the code such that there isn't too much crap to look through. In calling GetLastError I have determined that GetProcAddress() is returning error 127 or ERROR_PROC_NOT_FOUND. Which I presume means GetProcAddress cannot resolve the request for a function called EdrCenterText.

    But the fact is I still can't determine what the error is.

    Any thoughts?
    DLL Header file
    Code:
    //
    //EDRLIB.H
    //				
    
    #ifdef __cplusplus
    #define EXPORT extern "C" __declspec (dllexport)
    #else
    #define EXPORT __declspec (dllexport)
    #endif
    
    EXPORT BOOL EdrCenterTextA (HDC, PRECT, PCSTR);
    DLL Source
    Code:
    //
    // EDRLIB.C
    //
    
    #include <windows.h>
    #include "edrlib.h"
    
    int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
    {
    	return TRUE;
    }
    
    EXPORT BOOL EdrCenterTextA (HDC hdc, PRECT prc, PCSTR pString)
    {
    	int iLength;
    	SIZE size;
    
    	iLength = lstrlenA (pString);
    
    	GetTextExtentPoint32A (hdc, pString, iLength, &size);
    
    	return TextOutA (hdc, (prc->right - prc->left - size.cx) / 2,
    						  (prc->bottom - prc->top - size.cy) / 2,
    						   pString, iLength);
    }
    Windows procedure source
    Code:
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HDC					hdc;
    	PAINTSTRUCT			ps;
    	RECT				rect;
    	// Typedef - create a typedef for the pointerto a function
    	typedef BOOL (WINAPI * EDRCENT) (HDC, PRECT, PCSTR);
    	// Create two variables
    	static HINSTANCE	hLibrary;
    	EDRCENT		pfnEdrCent;
    	TCHAR		buffer[10];
    
    	switch(message)
    	{
    	case WM_CREATE:
    		{
    			if ((hLibrary = LoadLibrary(TEXT("edrlib.dll"))) == NULL)
    			{
    				MessageBox (hwnd, TEXT("Cant load edrlib.dll"), TEXT("Error"), 0);
    				return -1;
    			}
    		}
    		return 0;
    
    	case WM_PAINT:
    				
    		hdc = BeginPaint(hwnd, &ps);
    		GetClientRect (hwnd, &rect);
    				
    		pfnEdrCent = (EDRCENT) GetProcAddress(hLibrary, TEXT("EdrCenterTextA"));
    		if (pfnEdrCent == NULL)
    		{
    			sprintf (buffer, "Error: %u", GetLastError());
    			MessageBox(NULL, buffer, TEXT("Error"), 0);
    		}
    
    		((pfnEdrCent)(hdc, &rect, TEXT("This is a centered string")));
    
    		EndPaint(hwnd, &ps);
    		
    		return 0;
    
    	case WM_DESTROY:
    		if (hLibrary)
    			FreeLibrary(hLibrary);
    
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hwnd, message, wParam, lParam);
    }
    Visual C++ .net
    Windows XP profesional

  6. #6
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Try

    Code:
    #define EXPORT extern "C" __declspec (dllexport)
    Without any of the #ifdef __cplusplus stuff...see if that works

  7. #7
    Registered User filler_bunny's Avatar
    Join Date
    Feb 2003
    Posts
    87
    Thanks fordy - I would have thought that would give an indication of what could be wrong..

    Using the other define (for C++) it will compile, but give the error as before.
    Code:
    //
    //EDRLIB.H
    //				
    
    #define EXPORT extern "C" __declspec (dllexport)
    
    EXPORT BOOL CALLBACK EdrCenterTextA(HDC, PRECT, PCSTR);
    I tried this - and I did not get the results I expected. The compiler gives me this error:

    error C2059: syntax error: 'string'

    I can't see any glaring syntax errors.
    Visual C++ .net
    Windows XP profesional

  8. #8
    ¡Amo fútbol!
    Join Date
    Dec 2001
    Posts
    2,138
    Originally posted by filler_bunny

    Windows procedure source
    Code:
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HDC					hdc;
    	PAINTSTRUCT			ps;
    	RECT				rect;
    	// Typedef - create a typedef for the pointerto a function
    	typedef BOOL (WINAPI * EDRCENT) (HDC, PRECT, PCSTR);
    	// Create two variables
    	static HINSTANCE	hLibrary;
    	EDRCENT		pfnEdrCent;
    	TCHAR		buffer[10];
    
    	switch(message)
    	{
    	case WM_CREATE:
    		{
    			if ((hLibrary = LoadLibrary(TEXT("edrlib.dll"))) == NULL)
    			{
    				MessageBox (hwnd, TEXT("Cant load edrlib.dll"), TEXT("Error"), 0);
    				return -1;
    			}
    		}
    		return 0;
    
    	case WM_PAINT:
    				
    		hdc = BeginPaint(hwnd, &ps);
    		GetClientRect (hwnd, &rect);
    				
    		pfnEdrCent = (EDRCENT) GetProcAddress(hLibrary, TEXT("EdrCenterTextA"));
    		if (pfnEdrCent == NULL)
    		{
    			sprintf (buffer, "Error: %u", GetLastError());
    			MessageBox(NULL, buffer, TEXT("Error"), 0);
    		}
    
    		((pfnEdrCent)(hdc, &rect, TEXT("This is a centered string")));
    
    		EndPaint(hwnd, &ps);
    		
    		return 0;
    
    	case WM_DESTROY:
    		if (hLibrary)
    			FreeLibrary(hLibrary);
    
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hwnd, message, wParam, lParam);
    }
    Check out your function pointer? Did you try making it static or global? Shouldn't it go out of scope after the WM_CREATE message? Therefore, you'll have a new, empty pointer for the WM_PAINT messages.

  9. #9
    Registered User filler_bunny's Avatar
    Join Date
    Feb 2003
    Posts
    87
    Check out your function pointer? Did you try making it static or global? Shouldn't it go out of scope after the WM_CREATE message? Therefore, you'll have a new, empty pointer for the WM_PAINT messages.
    Yeah - I will have a look at that. My most immediate problem though is that the DLL wont compile (as per my previous post). This has me stuffed as this code is exactly what I have seen in tutorials - so am I perhaps forgetting a compiler option?

    Has anyone who has MSCV 7.0 tried compiling something similar to this? (Just the DLL component). It definitely appears to be barfing on the typedef....

    FB

  10. #10
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Ok...here's a complete working exampl of both the dll and the app...

    This compiles and works......build the dll...build the app...then copy the dll into the debug dir of the app project...then run the app.......

    One other potential baddy that I got rid of was this...


    Code:
    typedef BOOL (WINAPI* EDRCENT) (HDC, LPRECT, LPCSTR);
    Now basically, WINAPI is a define for __stdcall which is the calling convention adopted by 99% of the API functions available to windows, so if you want to import an API, use WINAPI. But if you are creating the dll yourself in a C Compiler, all functions default to __cdecl (the C calling convention).....now the func can still be called, but the __cdecl needs a bit more work in the code created for it to work...and without this, your stack will be in a pretty sorry state after a few seconds (the debug build will crash anyway).....so if you are importing one of your own funcs, loose the WINAPI in the declaration

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Loading a DLL that is not in the same directory as the executable
    By starcatcher in forum Windows Programming
    Replies: 10
    Last Post: 12-13-2008, 07:05 AM
  2. Loading Struct from dll
    By peyman_k in forum C++ Programming
    Replies: 2
    Last Post: 08-15-2008, 03:12 PM
  3. Explicit DLL loading
    By true_organs in forum Windows Programming
    Replies: 6
    Last Post: 05-24-2008, 01:26 PM
  4. .lib vs .h vs .dll
    By Shadow12345 in forum C++ Programming
    Replies: 13
    Last Post: 01-01-2003, 05:29 AM