• Advertisement
Sign in to follow this  

Loading Functions from a DLL

This topic is 4255 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I've been looking into using DLLs and calling functions from them, but I've hit a problem. the tutorial i was using http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=6813&lngWId=3 has a bug in it, or an oversight, or something, in any case it won't work properly. The program can use a function from the DLL that takes no parameters with no issue, but a function with paramaters throws up Debug Error: "The value of ESP was not properly saved accross a function call. This is usually the result of calling a function pointer declared with a different calling convention" i took that to mean that its expecting a return value, or i've messed up the parameters or something but from what i can see i've done everything right. compiled in visual c++ 6.0
// Loader.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <mmsystem.h>
#include <string.h>

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;								// current instance

TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// The title bar text

/////////////////////////////////////////
//////DLL STUFF
///////////////////////////////////////////

//Define DLL Callbacks (for the two functions we wrote in our DLL.
//Because function 1 has no parameters, its void.  Function 2 takes char* as
//a paramter so we put LPCSTR
typedef UINT (CALLBACK* LPFNDLLFUNC1)(VOID);
typedef UINT (CALLBACK* LPFNDLLFUNC2)(LPCSTR);
typedef UINT (CALLBACK* LPFNDLLFUNC3)(int);

HINSTANCE hDLL;		//Self explanitory          
LPFNDLLFUNC1 MyFunc1;		//Here we define variables for the callback functions
LPFNDLLFUNC2 MyFunc2;
LPFNDLLFUNC2 MyFunc3;
UINT  uReturnVal;


char buffer[5];
int variable = 0;


// Foward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_DLFOSHO, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Load DLL into memory and store the pointer in hDLL
	hDLL = LoadLibrary("c:\\MyProject.dll");

	if (hDLL != NULL)	//if the DLL loaded sucessfully
	{
		//Get the pointers to the functions
		MyFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,"MyDLLFunc1");
		MyFunc2 = (LPFNDLLFUNC2)GetProcAddress(hDLL,"MyDLLFunc2");
		MyFunc3 = (LPFNDLLFUNC2)GetProcAddress(hDLL,"MyDLLFunc3");
		//If either fails
		if (!MyFunc1 || !MyFunc2 || !MyFunc3)
		{
			//Show error message
			FreeLibrary(hDLL);       
			return false;
		}

	/*	//Otherwise call them
		else
		{
			uReturnVal = MyFunc1();
			uReturnVal = MyFunc2("HELLO WORLD!");
		}*/

	}




	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow)) 
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_DLFOSHO);

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage is only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_DLFOSHO);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= (LPCSTR)IDC_DLFOSHO;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	TCHAR szHello[MAX_LOADSTRING];
	LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

	switch (message) 
	{
		case WM_COMMAND:
			wmId    = LOWORD(wParam); 
			wmEvent = HIWORD(wParam); 
			// Parse the menu selections:
			switch (wmId)
			{
				case IDM_ABOUT:
				   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
				   break;
				case IDM_EXIT:
				   DestroyWindow(hWnd);
				   break;
				default:
				   return DefWindowProc(hWnd, message, wParam, lParam);
			}
			break;

			case WM_KEYDOWN:
		       switch (wParam) 
            { 

				case VK_SPACE: 
					MyFunc1();
                    break; 	

				case 'V':
					MyFunc2("ARGLEBARGLE");
					break;

/*				case 'B':
					variable = MyFunc3(variable);
					sprintf(buffer,"%d", variable);
					MessageBox(NULL, buffer, NULL, MB_OK);					
					break;
*/
			   }
				break;

		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			// TODO: Add any drawing code here...
			RECT rt;
			GetClientRect(hWnd, &rt);
			DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
			EndPaint(hWnd, &ps);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_INITDIALOG:
				return TRUE;

		case WM_COMMAND:
			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
			{
				EndDialog(hDlg, LOWORD(wParam));
				return TRUE;
			}
			break;
	}
    return FALSE;
}

MyDll
// MyProject.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    return TRUE;
}

void MyDLLFunc1() 
{
	MessageBox(NULL,"My DLL Function 1","",MB_OK);
}

int MyDLLFunc2(char *TEXT) 
{
	MessageBox(NULL,TEXT,"",MB_OK);
	return true;
} 

void MyDLLFunc3(int a)
{
//	return a++;

}

MyDll.def
LIBRARY MyProject
DESCRIPTION This is my DLL file!

EXPORTS
    	MyDLLFunc1	@1
		MyDLLFunc2	@2
		MyDLLFunc3  @3

Share this post


Link to post
Share on other sites
Advertisement
In the dll you are using the default calling (which is __cdecl) convention and in your applciation you're using the CALLBACK convention which is defined as __stdcall (??).

Changing this:


typedef UINT (CALLBACK* LPFNDLLFUNC1)(VOID);
typedef UINT (CALLBACK* LPFNDLLFUNC2)(LPCSTR);
typedef UINT (CALLBACK* LPFNDLLFUNC3)(int);


to this:


typedef UINT (*LPFNDLLFUNC1)(VOID);
typedef UINT (*LPFNDLLFUNC2)(LPCSTR);
typedef UINT (*LPFNDLLFUNC3)(int);


Should do it.

Read up on calling conventions: click

Share this post


Link to post
Share on other sites
[edit]Ah yea, and what IFooBar said about the calling conventions

The first thing that I see is your function pointer definitions say:

typedef UINT (CALLBACK* LPFNDLLFUNC1)(VOID);
typedef UINT (CALLBACK* LPFNDLLFUNC2)(LPCSTR);
typedef UINT (CALLBACK* LPFNDLLFUNC3)(int);

But your actual functions are:

void MyDLLFunc1();
int MyDLLFunc2(char *TEXT);
void MyDLLFunc3(int a);

I think you need to fix that return type [wink]:

typedef void (CALLBACK* LPFNDLLFUNC1)(VOID);
typedef int (CALLBACK* LPFNDLLFUNC2)(char*);
typedef void (CALLBACK* LPFNDLLFUNC3)(int);

Also, you may need to 'export' your functions from the DLL:

__declspec(dllimport) void MyDLLFunc1()
{
...
}

__declspec(dllimport) int MyDLLFunc2(char *TEXT)
{
...
}

__declspec(dllimport) void MyDLLFunc3(int a)
{
...
}

But I'm not sure if using the .DEF the way you are solves that.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement