Reputation: 65
Im trying to call a function long *Test(int) in an empty C dll from a C++ Win32 Console app. The dll is called QSIWrapperUMeLt.dll. When I try building the console application I get the following output:
adding resource. type:MANIFEST, name:1, language:0x0409, flags:0x30, size:406
1>TestPlatform.obj : error LNK2019: unresolved external symbol _Test referenced in function _wmain
1>C:\Users\Deven Bryant\Desktop\temp version\TestPlatform\Debug\TestPlatform.exe : fatal error LNK1120: 1 unresolved externals
1>
1>Build FAILED.
Here's what I've done in order to call my QSIWrapperUMeLt dll from my console app;
in the dll i've included the extern "C"
and __declspec(dllexport)
attribute in the function definitions. both the dll and the console app are set to build for Win32. I've made sure the dll was set to compile as c code in the project settings. In the console app I've #include
d the QSIWrapperUMeLt.h
file and changed __declspec(dllexport)
to __declspec(dllimport)
using pre processor directives. I've also linked to the dll with #pragma comment(lib, "DLLTutorial.lib")
. The QSIWrapperUMeLt library file, header file, and dll are in my console app's project folder.
Bellow I've provided the dll's header file, the console apps cpp file, and symbol tables and export functions detected by dumpbin when run on QSIWrapperUMeLt.dll.
Also, I've tried the explicit linking route, however when I call load library it returns a null pointer.
Any ideas as to what I'm doing wrong would be much appreciated.
QSIWrapperUMELt.h
#include <Windows.h>
//#pragma comment(lib, "DLLTutorial.lib")
#ifdef EXPORT
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport);
#endif
#define BOOL int
#define TRUE 1
#define FLSE 0
typedef enum
{
initialize = 0,
setup,
capture,
temperature,
close,
getimagedata
} CallStates;
typedef struct ReturnedValues
{
BOOL initialized, imagereadyflag, exposuredone;
long** imagedata;
double Temperature;
}ReturnedValues;
typedef struct CameraData
{
short Mode;
short Binning;
int Exposure;
int Top;
int Left;
int Height; //ROIH
int Width; //ROIW
int CoolerSetpoint;
int Temperature;
}CameraData;
typedef void (*callFunction)(CameraData camdata, ReturnedValues *retvals);
DECLSPEC ReturnedValues *retvals;
callFunction pcallFunction;
HINSTANCE hlib;
CameraData camdata;
#ifdef __cplusplus
extern "C"
{
#endif
DECLSPEC ReturnedValues entryPoint();
DECLSPEC long *Test(int length);
#ifdef __cplusplus
}
#endif
TestPlatform.cpp (console app) Im only trying to call Test() from this
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <conio.h>
#include <strsafe.h>
#define IMPORT
//#define EXPLICIT
using namespace std;
#ifndef EXPLICIT
#include "QSIWrapperUMeLt.h"
//#include "QSIAccessor.h"
#pragma comment(lib, "QSIWrapperUMeLt.lib")
//#pragma comment(lib, "QSIAccessorUMEmpty.lib")
#endif
#ifdef EXPLICIT
typedef long *(*Test)(int length);
HINSTANCE hinstlib;
Test pTest;
#endif
void ErrorExit(LPTSTR lpszFunction);
int _tmain(int argc, _TCHAR* argv[])
{
int temp = 1;
long *data;
#ifdef EXPLICIT
hinstlib = LoadLibrary((LPCWSTR)"QSIWrapperUMeLt.dll");
if(hinstlib)
{
#endif
int i;
cout << "hinstlib was successfully initialized" << endl;
#ifdef EXPLICIT
pTest = (Test)GetProcAddress(hinstlib, (LPCSTR)"Test");
data = pTest(10000);
#else
data = Test(1000);
//callFunction(CameraData *camdata, ReturnedValues *retvals);
#endif
for(i = 0; i < 20; i++)
{
cout << data[i] << endl;
}
#ifdef EXPLICIT
}
else
{
ErrorExit(TEXT("LoadLibrary"));
}
FreeLibrary(hinstlib);
#endif
getch();
return 0;
}
void ErrorExit(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
QSIWrapperUMeLt SYMBOL TABLES
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin>dumpbin /SYMBOLS "C:\Users\...\Desktop\temp version\C_C++libs\QSIWrapperUMeLt\Debug\QSIWrapperUMeLt.li
b"
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file C:\Users\Deven Bryant\Desktop\temp version\C_C++libs\QSIWrapperUMeLt\Debug\QSIWrapperUMeLt.lib
File Type: LIBRARY
COFF SYMBOL TABLE
000 009C766F ABS notype Static | @comp.id
001 00000000 SECT2 notype External | __IMPORT_DESCRIPTOR_QSIWrapperUMeLt
002 C0000040 SECT2 notype Section | .idata$2
003 00000000 SECT3 notype Static | .idata$6
004 C0000040 UNDEF notype Section | .idata$4
005 C0000040 UNDEF notype Section | .idata$5
006 00000000 UNDEF notype External | __NULL_IMPORT_DESCRIPTOR
007 00000000 UNDEF notype External | ¦QSIWrapperUMeLt_NULL_THUNK_DATA
String Table Size = 0x62 bytes
COFF SYMBOL TABLE
000 009C766F ABS notype Static | @comp.id
001 00000000 SECT2 notype External | __NULL_IMPORT_DESCRIPTOR
String Table Size = 0x1D bytes
COFF SYMBOL TABLE
000 009C766F ABS notype Static | @comp.id
001 00000000 SECT2 notype External | ¦QSIWrapperUMeLt_NULL_THUNK_DATA
String Table Size = 0x25 bytes
Summary
DB .debug$S
14 .idata$2
14 .idata$3
4 .idata$4
4 .idata$5
14 .idata$6
QSIWrapperUMeLt EXPORTS
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin>dumpbin /EXPORTS "C:\Users\...\Desktop\temp version\C_C++libs\QSIWrapperUMeLt\Debug\QSIWrapperUMeLt.dl
l"
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file C:\Users\Deven Bryant\Desktop\temp version\C_C++libs\QSIWrapperUMeLt\Debug\QSIWrapperUMeLt.dll
File Type: DLL
Section contains the following exports for QSIWrapperUMeLt.dll
00000000 characteristics
500E089F time date stamp Mon Jul 23 19:29:51 2012
0.00 version
1 ordinal base
3 number of functions
3 number of names
ordinal hint RVA name
1 0 00011127 Test = @ILT+290(_Test)
2 1 0001102D entryPoint = @ILT+40(_entryPoint)
3 2 00017580 retvals = _retvals
Summary
1000 .data
1000 .idata
2000 .rdata
1000 .reloc
1000 .rsrc
4000 .text
10000 .textbss
Upvotes: 0
Views: 1628
Reputation: 8075
I don't see the reason for your problem when EXPLICIT is not defined. However, here's your problem in the argument to LoadLibrary:
(LPCWSTR)"QSIWrapperUMeLt.dll"
ANSI string "QSIWrapperUMeLt.dll" is an array of bytes, containing a bunch of single byte characters, terminated with a single byte NUL. When used in an expression such as a function argument, the expression is converted to a pointer to the first character, a pointer of type char* or LPSTR.
You cast the pointer to type LPCWSTR. However, the pointer still points to a bunch of single byte characters, terminated with a single byte NUL.
Since you want a Unicode string, you can do this:
L"QSIWrapperUMeLt.dll"
or for compatibility with either ANSI or Unicode when your code might be needed in the future:
_T("QSIWrapperUMeLt.dll")
Upvotes: 1