Link to home
Start Free TrialLog in
Avatar of xebra19
xebra19

asked on

PropertySheet DLLs Followup (DanRollins)

I accepted your answer earlier because it seemed like it would work. However I've been having some problems implementing it. I've been using code like this:

*********************************************************
[DLL]
CPage* m_Page; // CPage is derived from CPropertyPage
__declspec(dllexport) void* CreatePage()
{
     m_Page = new CPage();
     return (void*)m_Page;
}

[APPLICATION]
CPropertyPage *aPage;
CPropertySheet Mysheet;
FARPROC CreateFunc;

CreateFunc = GetProcAddress(handletoDLL, "ExportedName");
aPage = (CPropertyPage*)CreateFunc();
Mysheet.AddPage(aPage);
*********************************************************

That code generates this error (copy and pasted):

Application: This program has performed an illegal operation and will be shut down. If the problem persists, contact the program vendor.

APPLICATION caused an invalid page fault in
module THEDLL.DLL at 0167:100056a1.
Registers:
EAX=007b1640 CS=0167 EIP=100056a1 EFLGS=00010246
EBX=00580000 SS=016f ESP=0068fb14 EBP=0068fb7c
ECX=007b1640 DS=016f ESI=0068fb84 FS=60bf
EDX=00000000 ES=016f EDI=0068fb70 GS=0000
Bytes at CS:EIP:
89 82 c8 00 00 00 8b 4d f0 8b 81 c8 00 00 00 8b
Stack dump:
0068fd54 0068fb84 00580000 cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc

Do you have any ideas on about what's going wrong here?
Avatar of jkr
jkr
Flag of Germany image

Have you checked whether CreateFunc contains a valid address before calling it? E.g.

FARPROC CreateFunc;

CreateFunc = GetProcAddress(handletoDLL, "ExportedName");

if ( NULL != CreateFunc) {

  aPage = (CPropertyPage*)CreateFunc();

} else {

  // error
}

BTW, you should use

extern "C" __declspec(dllexport) void* CreatePage()

to avoid exporting the function with a C++ mangled name...
You need to call
   AFX_MANAGE_STATE(AfxGetStaticModuleState());
in every case where control is passed from the EXE to the DLL.  That big block of comments provided at the top of the AppWizard-generated file goes into excruciating detail in this regard.

-- Dan

Also, when that error occurs, bring up the Call Stack to learn where the code went awry.  You can also diagnose many problems by single-stepping with the debugger.  You can trace right into the DLL.  The trick is putting a breakpoint on the

    aPage = (CPropertyPage*)CreateFunc();

line.

-- Dan
Avatar of xebra19
xebra19

ASKER

I did a debug, and it points out this line: m_Page = new CPage(); and says the expression doesn't evaluate.
Avatar of xebra19

ASKER

note: i added the AFX_MANAGE_STATE line at the top of that function
Avatar of xebra19

ASKER

jkr: I have checked and it does have the correct name. The function is being called.
>> the expression doesn't evaluate
Are you saying that the DLL cannot be compiled?  If so, then there is some chance that that is related to your problem.
-- Dan
Avatar of xebra19

ASKER

heh, no the DLL compiles. It compiles just fine. When the error occurs, and i click the debug button, it points to that line. I check the output window and under the line the references "m_Page = new CPage();" It says that the expression doesn't evaluate.
Avatar of xebra19

ASKER

also, if I set a breakpoint on this line: "aPage = (CPropertyPage*)CreateFunc();". I get this for the value aPage in the Debug output window:
Name: aPage
Value: 0x00000000 {CPropertyPage hWnd=???}

That line has a + sign in front of it. When I click it this drops down underneath:

Name: CDialog
Value: CXX0030: Error: expression cannot be evaluated

There are also a few more dropdowns that list different names but they pretty much all say "expression cannot be evaluated".
the variable aPage will have no value until the line:

   aPage = (CPropertyPage*)CreateFunc();

has been executed.  You need to breakpoint that line, and then single-step.  That could put you right into the DLL code where you can single-step the CreateFunc() function.

-- Dan


Avatar of xebra19

ASKER

well what i said earlier was that this line (which is in the CreateFunc function) is causing the problem:
m_Page = new CPage();
It tells me that this expression can not be evaluated (this is the line in the CreateFunc function).
If I mouse over the part that says "CPage()" it displays this tooltip: CPage = {CPage hWnd=???}

Could this be the problem? If not, i must not be understanding what you are saying. I debug my application letting it execute the code line by line until it hits an error, it then stops and points out that line to me. What else am i supposed to do?
right click on that line.  
choose Insert/Remove breakpoint
run the program
when it stops, it will display that line
now choose menu item Debug/Step Into

Now you can execute each program line, one line at a time.  In this case, that will involve stepping into the code that is in the DLL (the exported function, CreateFunc() code ).

-- Dan

Avatar of xebra19

ASKER

yes i tried that however, after going through about 10,000 lines of code related to AFX_MANAGE_STATE, i just stepped out until I got down to the mPage = net CPage() line. Then it shows this error:
First-chance exception in MainApplication.exe (THEDLL.DLL): 0xC0000005: Access Violation.

I don't see how assaigning a new CPropertyPage derived object to a pointer would cause an Access Violation.
Show your code leading up to the

    mPage= new CPage();

line in the DLL.  How have you defined mPage?

As soon as you are in the DLL, you can put a breakpoint in the constructor for your CPage.  I'd have to guess that something in there is going wrong.



Avatar of xebra19

ASKER

hmm, doesn't it seem easier to just export the m_Page pointer? And then just load it and call AddPage from the main program instead of messing with this function? It would probably eliminate a lot of possible errors. If this would be a better choice, how would I do what I did with the function to the pointer? (the GetProcAddress Part, in other words, how can i load the pointer into the main program so that I can call AddPage with it as a parameter?)
When you use a .LIB to interface the EXE to the DLL, it is very easy to export class objects and data variable.  As I understand your question, you will be using LoadLibrary, so the only way to access the DLL is via GetProcAddress, which does not return object or data -- only addresses of functions -- so at is not an option.

What's left is to simulate the ActiveX concept of a 'class factory' ... the DLL provides a function that creates and initializes the object and passes back a pointer to that object.

If you want to use 'normal DLL Linking' (using a LIB file and requiring the presence of all potentially needed DLLs at runtime) then that will simplify your task considerably.

-- Dan
Avatar of xebra19

ASKER

BEGIN[DLL CODE, DLL CODE, DLL CODE, DLL CODE]

Note the CPage I have been referring to has been renamed to CStatPage. Here's all the relavent code:
***********************************************************
// StatPage.cpp : implementation file
//

#include "stdafx.h"
#include "dllapp.h"
#include "StatPage.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CStatPage property page

IMPLEMENT_DYNCREATE(CStatPage, CPropertyPage)

CStatPage::CStatPage() : CPropertyPage(CStatPage::IDD)
{
     //{{AFX_DATA_INIT(CStatPage)
          // NOTE: the ClassWizard will add member initialization here
     //}}AFX_DATA_INIT
}

CStatPage::~CStatPage()
{
}

void CStatPage::DoDataExchange(CDataExchange* pDX)
{
     CPropertyPage::DoDataExchange(pDX);
     //{{AFX_DATA_MAP(CStatPage)
          // NOTE: the ClassWizard will add DDX and DDV calls here
     //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CStatPage, CPropertyPage)
     //{{AFX_MSG_MAP(CStatPage)
          // NOTE: the ClassWizard will add message map macros here
     //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CStatPage message handlers

***********************************************************

// StatPage.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CStatPage dialog

class CStatPage : public CPropertyPage
{
     DECLARE_DYNCREATE(CStatPage)

// Construction
public:
     CStatPage();
     ~CStatPage();

// Dialog Data
     //{{AFX_DATA(CStatPage)
     enum { IDD = IDD_STATDLG };
          // NOTE - ClassWizard will add data members here.
          //    DO NOT EDIT what you see in these blocks of generated code !
     //}}AFX_DATA


// Overrides
     // ClassWizard generate virtual function overrides
     //{{AFX_VIRTUAL(CStatPage)
     protected:
     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
     //}}AFX_VIRTUAL

// Implementation
protected:
     // Generated message map functions
     //{{AFX_MSG(CStatPage)
          // NOTE: the ClassWizard will add member functions here
     //}}AFX_MSG
     DECLARE_MESSAGE_MAP()

};

***********************************************************

// MAIN DLL HEADER FILE (IMPORTANT SECTIONS)
CStatPage* m_Page;
__declspec(dllexport) void* CreatePage();

***********************************************************

// MAIN DLL SOURCE FILE (IMPORTANT SECTIONS)
__declspec(dllexport) void* CreatePage()
{
     AFX_MANAGE_STATE(AfxGetStaticModuleState());
     m_Page = new CStatPage;
     return (void*)m_Page;
}

***********************************************************
END[DLL CODE, DLL CODE, DLL CODE, DLL CODE]
Avatar of xebra19

ASKER

HERE COMES THE MAIN PROGRAM SOURCE CODE
Avatar of xebra19

ASKER

***********************************************************

// MAIN PROGRAM (EXE) HEADER FILE (IMPORTANT SECTIONS)
CPropertyPage *m_Page;
CMainProgramDlg dlgacc;

***********************************************************

// MAIN PROGRAM (EXE) SOURCE FILE (IMPORTANT SECTIONS)
HMODULE hMod = LoadLibrary( dllPath );
FARPROC CreateFunc;
CreateFunc = GetProcAddress(hMod, "CreatePage");
if(CreateFunc == NULL)
{
     MessageBox("DLL NOT LOADED");
}
else
{
     m_Page = (CPropertyPage*)CreateFunc();
     dlgacc.m_sheet.AddPage(m_Page);
}

***********************************************************

The rest of the important code in the main app is just the code to setup the property sheet but i know that code is correct.
Avatar of xebra19

ASKER

BTW - m_sheet was Mysheet but i changed it to a more normal variable name. m_sheet is the name of the property sheet
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of xebra19

ASKER

well that worked. It didn't seem any different than what I was doing. I must have made some stupid type errors. Oh well. Thanks! You've been a big help!

If I did this right you should get 500 expert points (if the system hasn't changed)
Avatar of xebra19

ASKER

hmm, the increase points didn't work. oh well, i'll find a way to give you some more points later.
I'm glad I could help!

To award additional points, just make a new Question in the C++ TA.  Set it's title to
          Points for DanRollins
and place this in the question text:

For your help with: https://www.experts-exchange.com/cplusprog/Q.20299685.html

-- Dan