I have an MFC app which is a semestral final project at the university. The project’s solution includes two DLL modules: Except1 (handling errors and displaying messages), MyData (managing application data) and ProjectMFC that compiles to .exe file (the proper application project).
The project’s dependencies look like below:
Except1
|
|-->MyData
| |
| v
|-->ProjectMFC
According to the project guidelines in MyData and ProjectMFC files I have to create a declaration of pointer to Except1 module’s class in order to use methods from this module.
CExcept1App* pExcept;
In ProjectMFC it works.
But in MyData I get a linker error
Error LNK2019 unresolved external symbol GetExceptPtr referenced in function "public: __cdecl MY_DATA::MY_DATA(int)" (??0MY_DATA@@QEAA@H@Z)
although I’ve added additional dependencies in MyData project’s properties.
MyData.h:
// MyData.h : main header file for the MyData DLL
//
#pragma once
#ifndef __AFXWIN_H__
#error "include 'pch.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
#include "Except1.h"
#ifdef MY_DATA_EXPORTS
#define MYDATA_API __declspec(dllexport)
#else
#define MYDATA_API __declspec(dllimport)
#endif // MY_DATA_EXPORTS
// CMyDataApp
// See MyData.cpp for the implementation of this class
//
//template <class T, class Key>
//T* find(const T* p_begin, const T* p_end, const Key& k)
//{
// if (p_begin >= p_end)
// return NULL;
//
// T* p_tmp = const_cast<T*>(p_begin);
// for (; p_tmp != p_end; p_tmp++)
// {
// if (*p_tmp == key)
// return p_tmp;
// }
// return NULL;
//}
class CMyDataApp : public CWinApp
{
public:
CMyDataApp();
// Overrides
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
class CExcept1App;
class MYDATA_API MY_POINT
{
public:
double x;
double y;
char* name = NULL;
COLORREF color;
MY_POINT() : x(0), y(0), name(NULL), color(RGB(0, 0, 0)){}
MY_POINT(double xx, double yy, COLORREF c_color, const char* nname);
MY_POINT(const MY_POINT& ob);
~MY_POINT()
{
if (name)
delete[] name;
name = NULL;
}
MY_POINT& operator=(const MY_POINT& ob);
void set(double xx, double yy, COLORREF c_color, const char* nname);
MY_POINT get() { return *this; }
};
class MYDATA_API MY_DATA : public MY_POINT
{
protected:
MY_POINT* pTab;
int capacity;
int last;
public:
CExcept1App* pExcept;
MY_DATA(int no_it);
MY_DATA(const MY_DATA& ob);
~MY_DATA() { Free(); }
int size() { return last; }
void Free() { if (pTab) delete[] pTab; pTab = NULL; }
void Init(int no_it);
void Push(const MY_POINT& tmp);
int Size() { return last; }
void clear() { last = 0; }
MY_POINT& operator [] (const int i) {
return pTab[i];
}
void GetMaxMinCoords(double& max_x, double& min_x, double& max_y, double& min_y);
private:
MY_POINT* allocTab(MY_POINT* pTab, int n);
};
MyData.cpp:
// MyData.cpp : Defines the initialization routines for the DLL.
//
#include "pch.h"
#include "framework.h"
#include "MyData.h"
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMyDataApp
BEGIN_MESSAGE_MAP(CMyDataApp, CWinApp)
END_MESSAGE_MAP()
// CMyDataApp construction
CMyDataApp::CMyDataApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CMyDataApp object
CMyDataApp theApp;
// CMyDataApp initialization
BOOL CMyDataApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
MY_POINT::MY_POINT(double xx, double yy, COLORREF c_color, const char* nname = nullptr) : x(xx), y(yy), color(c_color)
{
try
{
if (name)
{
name = new char[strlen(nname) + 1];
strcpy_s(name, strlen(nname) + 1, nname);
}
}
catch (std::bad_alloc)
{
//pExcept->PutMessage(1001);
name = NULL;
}
}
MY_POINT::MY_POINT(const MY_POINT& ob)
{
x = ob.x;
y = ob.y;
color = ob.color;
try
{
if (ob.name)
{
name = new char[strlen(ob.name) + 1];
strcpy_s(name, strlen(ob.name) + 1, ob.name);
}
}
catch (std::bad_alloc)
{
//pExcept->PutMessage(1001);
name = NULL;
}
}
MY_POINT& MY_POINT::operator=(const MY_POINT& ob)
{
if (this == &ob) return *this;
delete[] name;
name = NULL;
x = ob.x;
y = ob.y;
color = ob.color;
try
{
if (ob.name)
{
name = new char[strlen(ob.name) + 1];
strcpy_s(name, strlen(ob.name) + 1, ob.name);
}
}
catch (std::bad_alloc)
{
//pExcept->PutMessage(1001);
name = NULL;
}
return *this;
}
void MY_POINT::set(double xx, double yy, COLORREF c_color, const char* nname)
{
x = xx;
y = yy;
color = c_color;
delete[] name;
name = NULL;
try
{
if (name)
{
name = new char[strlen(nname) + 1];
strcpy_s(name, strlen(name) + 1, nname);
}
}
catch (std::bad_alloc)
{
//pExcept->PutMessage(1001);
name = NULL;
}
}
MY_DATA::MY_DATA(int no_it)
{
pExcept = GetExceptPtr();
pTab = NULL;
Init(no_it);
}
MY_POINT* MY_DATA::allocTab(MY_POINT* pTab, int n)
{
try
{
if (!pTab)
{
pTab = new MY_POINT[n];
capacity = n;
}
}
catch (std::bad_alloc aa)
{
//pExcept->PutMessage(1001);
}
return pTab;
}
//it's the part of code using pExcept pointer
Except1.h:
// Except1.h : main header file for the Except1 DLL
//
#pragma once
#ifndef __AFXWIN_H__
#error "include 'pch.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
#ifdef EXCEPT1_EXPORT
#define EXCEPT1_API __declspec(dllexport)
#else
#define EXCEPT1_API __declspec(dllimport)
#endif
// CExcept1App
// See Except1.cpp for the implementation of this class
//
#define APP_START_MESSAGE WM_USER+100
enum ITS_APP_MESSAGE
{
WM_START = APP_START_MESSAGE,
WM_DIS_MSG,
WM_CLEAR_OUTPUT,
WM_DIS_TOTALMES
};
class MY_DATA;
class EXCEPT1_API CExcept1App : public CWinApp
{
public:
CWnd* ptrWnd;
MY_DATA* ptrDat;
public:
CExcept1App();
void SetWnd(CWnd* ptrwnd, MY_DATA* pdat) { ptrWnd = ptrwnd; ptrDat = pdat; }
void ResetDat(MY_DATA* pdat) { ptrDat = pdat; }
void PutMessage(UINT ID_MESSAGE);
void ClearOutWnd();
// Overrides
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
extern "C" CExcept1App * PASCAL EXPORT GetExceptPtr();```
GetExceptPtr() is also in Except1.def file:
; Except1.def : Declares the module parameters for the DLL.
LIBRARY
EXPORTS
; Explicit exports can go here
GetExceptPtr
Except1.cpp:
// Except1.cpp : Defines the initialization routines for the DLL.
//
#include "pch.h"
#include "framework.h"
#include "Except1.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CExcept1App
BEGIN_MESSAGE_MAP(CExcept1App, CWinApp)
END_MESSAGE_MAP()
// CExcept1App construction
CExcept1App::CExcept1App()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
ptrWnd = NULL;
ptrDat = NULL;
}
// The one and only CExcept1App object
CExcept1App theApp;
// CExcept1App initialization
BOOL CExcept1App::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
void CExcept1App::PutMessage(UINT ID_Message)
{
HINSTANCE hInstance = GetModuleHandleA(NULL);
char str[1024];
int ret = LoadStringA(hInstance, ID_Message, str, sizeof(str));
if (ptrWnd)
ptrWnd->SendMessage(WM_DIS_MSG, (WPARAM)str, (LPARAM)ptrDat);
else if (!ptrWnd && str[0] == 'E')
{
CString sstr(str);
AfxMessageBox(sstr);
UINT uExitCode = 0;
HANDLE hHandle = GetCurrentProcess();
TerminateProcess(GetCurrentProcess(), uExitCode);
}
}
void CExcept1App::ClearOutWnd()
{
if (ptrWnd)
ptrWnd->SendMessage(WM_CLEAR_OUTPUT, 0, 0);
}
extern "C" CExcept1App * PASCAL EXPORT GetExceptPtr()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return &theApp;
}
I've tried to use forward declaration because both Except1 and MyData use their pointers but it didn't solve the problem.
Damian is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.