Yoshimitsu
Yoshimitsu

Reputation: 65

LNK2019: Unresolved external when calling to a function in a C dll from a C++ console Application (no CLR)

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 #included 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

Answers (1)

Windows programmer
Windows programmer

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

Related Questions