[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 454
  • Last Modified:

Where did I go wrong with this DLL program in msvc 7.1???

I am trying to create a dll file.  I have about 40 functions that I want to store in a DLL file and make calls sto them from other msv 7.1C++  programs.  So looked at some examples and decided to try one first before going to a large one. I tried 3 exsamples and always got a linking error when I tried to call one of the functions in the dll file i created.  Pls hlelp me find out where I am going wrong.  Here is a sample of the last code that I wrote.  The dll file complies fine but to program to make a call to it does not.  I used the mfc wizard to create the wizard and added the functions. I commented  where I added my code lines.  Could you please Debus this one or send me a sample of one that works so I can use it as a template???  I want to pass strings and numerical values to the calling applications.   Thanks in advance for your assistance.  I will be passing string and numbers in my functions.

DLL Program

the H File
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif

// This class is exported from the TESTDLL.dll
class TESTDLL_API CTESTDLL {
public:
     CTESTDLL(void);
     // TODO: add your methods here.
};

extern TESTDLL_API int nTESTDLL;

TESTDLL_API int fnTESTDLL(void);


 the CPP file

// TESTDLL.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#define TESTDLL_EXPORTS  // I added this line  *******************
#include "TESTDLL.h"
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                          )
{
     switch (ul_reason_for_call)
     {
     case DLL_PROCESS_ATTACH:
     case DLL_THREAD_ATTACH:
     case DLL_THREAD_DETACH:
     case DLL_PROCESS_DETACH:
          break;
     }
    return TRUE;
}

// This is an example of an exported variable
TESTDLL_API int nTESTDLL=0;

// This is an example of an exported function.
TESTDLL_API int fnTESTDLL(void)
{
     return 42;
}

// This is the constructor of a class that has been exported.
// see TESTDLL.h for the class definition
CString CTESTDLL::CTESTDLL()
{
     return "Test message.";
}

///////////////////////////////////    The program that calls the Dll

the H Files
// TestCall.h : main header file for the PROJECT_NAME application
//

#pragma once

#ifndef __AFXWIN_H__
     #error include 'stdafx.h' before including this file for PCH
#endif

#include "resource.h"          // main symbols


// CTestCallApp:
// See TestCall.cpp for the implementation of this class
//

class CTestCallApp : public CWinApp
{
public:
     CTestCallApp();

// Overrides
     public:
     virtual BOOL InitInstance();

// Implementation

     DECLARE_MESSAGE_MAP()
};

extern CTestCallApp theApp;

// TestCallDlg.h : header file
//

#pragma once


// CTestCallDlg dialog
class CTestCallDlg : public CDialog
{
// Construction
public:
     CTestCallDlg(CWnd* pParent = NULL);     // standard constructor

// Dialog Data
     enum { IDD = IDD_TESTCALL_DIALOG };

     protected:
     virtual void DoDataExchange(CDataExchange* pDX);     // DDX/DDV support


// Implementation
protected:
     HICON m_hIcon;

     // Generated message map functions
     virtual BOOL OnInitDialog();
     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
     afx_msg void OnPaint();
     afx_msg HCURSOR OnQueryDragIcon();
     DECLARE_MESSAGE_MAP()
};
 The CPP Files

// TestCall.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "TestCall.h"
#include "TestCallDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CTestCallApp

BEGIN_MESSAGE_MAP(CTestCallApp, CWinApp)
     ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()


// CTestCallApp construction

CTestCallApp::CTestCallApp()
{
     // TODO: add construction code here,
     // Place all significant initialization in InitInstance
}


// The one and only CTestCallApp object

CTestCallApp theApp;


// CTestCallApp initialization

BOOL CTestCallApp::InitInstance()
{
     // InitCommonControls() is required on Windows XP if an application
     // manifest specifies use of ComCtl32.dll version 6 or later to enable
     // visual styles.  Otherwise, any window creation will fail.
     InitCommonControls();

     CWinApp::InitInstance();

     AfxEnableControlContainer();

     // Standard initialization
     // If you are not using these features and wish to reduce the size
     // of your final executable, you should remove from the following
     // the specific initialization routines you do not need
     // Change the registry key under which our settings are stored
     // TODO: You should modify this string to be something appropriate
     // such as the name of your company or organization
     SetRegistryKey(_T("Local AppWizard-Generated Applications"));

     CTestCallDlg dlg;
     m_pMainWnd = &dlg;
     INT_PTR nResponse = dlg.DoModal();
     if (nResponse == IDOK)
     {
          // TODO: Place code here to handle when the dialog is
          //  dismissed with OK
     }
     else if (nResponse == IDCANCEL)
     {
          // TODO: Place code here to handle when the dialog is
          //  dismissed with Cancel
     }

     // Since the dialog has been closed, return FALSE so that we exit the
     //  application, rather than start the application's message pump.
     return FALSE;
}

// TestCallDlg.cpp : implementation file
//
#include "stdafx.h"
#include "TestCall.h"
#include "TestCallDlg.h"
#include "TESTDLL.h"  // I added this line
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
     CAboutDlg();

// Dialog Data
     enum { IDD = IDD_ABOUTBOX };

     protected:
     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
     DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CTestCallDlg dialog



CTestCallDlg::CTestCallDlg(CWnd* pParent /*=NULL*/)
     : CDialog(CTestCallDlg::IDD, pParent)
{
     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTestCallDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CTestCallDlg, CDialog)
     ON_WM_SYSCOMMAND()
     ON_WM_PAINT()
     ON_WM_QUERYDRAGICON()
     //}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CTestCallDlg message handlers

BOOL CTestCallDlg::OnInitDialog()
{
     CDialog::OnInitDialog();

     // Add "About..." menu item to system menu.

     // IDM_ABOUTBOX must be in the system command range.
     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
     ASSERT(IDM_ABOUTBOX < 0xF000);

     CMenu* pSysMenu = GetSystemMenu(FALSE);
     if (pSysMenu != NULL)
     {
          CString strAboutMenu;
          strAboutMenu.LoadString(IDS_ABOUTBOX);
          if (!strAboutMenu.IsEmpty())
          {
               pSysMenu->AppendMenu(MF_SEPARATOR);
               pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
          }
     }

     // Set the icon for this dialog.  The framework does this automatically
     //  when the application's main window is not a dialog
     SetIcon(m_hIcon, TRUE);               // Set big icon
     SetIcon(m_hIcon, FALSE);          // Set small icon

     // TODO: Add extra initialization here
     // Code to test TESTDLL.dll Program
     int n = fnTESTDLL();   /// I added this line and Here is where I am getting the linking errors.*****************

     // Code to test the CTestdll class
     CTESTDLL test;          /// I added this line and Here is where I am getting the linking errors. *****************

     return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTestCallDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
     {
          CAboutDlg dlgAbout;
          dlgAbout.DoModal();
     }
     else
     {
          CDialog::OnSysCommand(nID, lParam);
     }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTestCallDlg::OnPaint()
{
     if (IsIconic())
     {
          CPaintDC dc(this); // device context for painting

          SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

          // Center icon in client rectangle
          int cxIcon = GetSystemMetrics(SM_CXICON);
          int cyIcon = GetSystemMetrics(SM_CYICON);
          CRect rect;
          GetClientRect(&rect);
          int x = (rect.Width() - cxIcon + 1) / 2;
          int y = (rect.Height() - cyIcon + 1) / 2;

          // Draw the icon
          dc.DrawIcon(x, y, m_hIcon);
     }
     else
     {
          CDialog::OnPaint();
     }
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTestCallDlg::OnQueryDragIcon()
{
     return static_cast<HCURSOR>(m_hIcon);
}


0
lcrogers
Asked:
lcrogers
  • 3
  • 3
1 Solution
 
cookreCommented:
Once you read this you'll see what the problem is:
http://www.codetools.com/dll/XDllPt4.asp
0
 
i_maheshCommented:
the two things you might be missing are
1. Providing a prototype of the class and the function exported from the dll
2. Providing the lib file of the dll to the linker in the caller application.
0
 
lcrogersAuthor Commented:
I'm sorry, I was wondering why I did not recieve any responses to this question and come to find out that my email address was wrong.  here are the errors that I am recieving:

TestCall error LNK2019: unresolved external symbol "__declspec(dllimport) int __cdecl fnTESTDLL(void)" (__imp_?fnTESTDLL@@YAHXZ) referenced in function "protected: virtual int __thiscall CTestCallDlg::OnInitDialog(void)" (?OnInitDialog@CTestCallDlg@@MAEHXZ)
TestCall error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall CTESTDLL::CTESTDLL(void)" (__imp_??0CTESTDLL@@QAE@XZ) referenced in function "protected: virtual int __thiscall CTestCallDlg::OnInitDialog(void)" (?OnInitDialog@CTestCallDlg@@MAEHXZ)
TestCall fatal error LNK1120: 2 unresolved externals

As I said earlier, I would like to send and recieve CStrings to this library too.  I will be checking this question, now that I know that I am recieving help.   Thanks IKE,  Oh I tried what you suggested and I recieve the same errors.

Lou
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
cookreCommented:
If you're going to reference an entry point by name, the name has to be resolved by the linker via a corresponding LIB file.  Otherwise, you do the standard thing of calling GetProcAddress:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocaddress.asp
0
 
lcrogersAuthor Commented:
I can see the function when a add them to my calling application, but when I compile the program I get the above errors. In fact I can see all the functions in the dll.
0
 
cookreCommented:
The compile is fine.
The DLL is probably fine.
It's the link that's failing - for the reason mentioned above.

Linking is the final step of creating an executable.  
It's job is to combine all of the specified OBJ files, resolve all external references in those OBJs, and convert the OBJs' relative addresses into absolute (well, kinda) addresses.

Now, by referencing the entrypoints by name, you create an unknown reference in the OBJ that the linker has to resolve.  The linker looks in specified OBJs and LIBs.  It doesn't look in DLLs.

So, to call the functions that way, you have to make a LIB equivalent to the DLL.  Note, however, that that will include the code from the LIB into the generated EXE (static link).

If you want the dll to be external at runtime, you code needs to:

LoadLibrary() // load the target dll
GetProcAddress() // Get the address of the desired entry point.

0
 
lcrogersAuthor Commented:
Okay I loaded thelibrary using those two cammands now how do I get access to them???  for insstance if I want to send a number to them so that it would send me back a string?
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now