我使用dll做了个子界面,就是个简单的测试功能,在上面显示了个静态框,其中导出了三个函数
//主要用来在主界面的一个静态框中显示这个子界面
extern "C" __declspec(dllexport) void Show(CRect rc)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
/*CTest test;
test.Create (IDD_DIALOG1);
test.ShowWindow(SW_SHOW);*/
//test.DoModal();
m_test.Create(IDD_DIALOG1);
m_test.ShowWindow(SW_SHOW);
m_test.MoveWindow(rc);
}
//销毁这个子界面
extern "C" __declspec(dllexport) void Rel()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
m_test.DestroyWindow();
}//对这个子界面进行一个判断
extern "C" __declspec(dllexport) HWND Dec()
{
HWND hwnd;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
hwnd = m_test.GetSafeHwnd();
return hwnd;
}我的主界面做的是一个CTreeCtrl 类,但点击一个叶子节点的时候显示这个子界面,开始的时候我是直接在主程序中创建了一个子界面,一切正常
然后我将子见面的函数换成dll中的创建函数,具体代码如下:
在CTreeCtrl的消息处理函数OnTvnSelchangedTree1(主要是响应其中TVN_SELCHANGED消息)中
typedef void (WINAPI * CCDDLL)(CRect rc);
HINSTANCE hmod;
hmod = ::LoadLibrary ("ChildDlg.dll");
if(hmod==NULL)
{
AfxMessageBox("Fail");
}
CCDDLL lpproc;
lpproc = (CCDDLL)GetProcAddress (hmod,"Show");
if(lpproc==(CCDDLL)NULL)
{
MessageBox("lpproc is error");
}
typedef HWND (WINAPI * CCDDLL2)();
HINSTANCE hmod2;
hmod2 = ::LoadLibrary ("ChildDlg.dll");
if(hmod2==NULL)
{
AfxMessageBox("Fail");
}
CCDDLL2 reoroc;
reoroc = (CCDDLL2)GetProcAddress(hmod,"Rel");
if(reoroc==(CCDDLL2)NULL)
{
MessageBox("reoroc is error");
}


typedef HWND (WINAPI * CCDDLL1)();
HINSTANCE hmod1;
hmod1 = ::LoadLibrary ("ChildDlg.dll");
if(hmod1==NULL)
{
AfxMessageBox("Fail");
}
CCDDLL1 decroc;
decroc = (CCDDLL1)GetProcAddress(hmod,"Dec");
if(decroc==(CCDDLL1)NULL)
{
MessageBox("decroc is error");
}
HWND Cchd = decroc();
然后在switch/case的部分
if (!IsWindow(Cchd))//判断现在子界面的窗口是否为子窗口
{
(*lpproc) (rc);
}
             ......//深绿部分为如果但前窗口不是子窗口,则关闭现有窗口,
运行的时候弹出储物Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.问中断、继续,我中断了一下,发现错误出现在(*lpproc) (rc);语句后一次,OnTvnSelchangedTree1函数后一次,然后才能显示界面,这是怎么回事呀,我查了一下说是调用错误,可是我有点看不懂那个调用的情况,想请高手指点一下

解决方案 »

  1.   

    dll 中动态创建吧,比如这样:CTestDlg *g_pDlg;void ShowDlg(LPTSTR strTitle)
    {
      g_pDlg = new CTestDlg();
      g_pDlg->Create...
      g_pDlg->ShowWindow..
      g_pDlg->UpdateWindow..
    }void HideDlg()
    {
      if(g_pDlg != NULL)
      {
        delete pDlg;
      }
    }
      

  2.   

    恩,我调整了一下,发现错误的确是调用约定的错误。我开始看了很多教程,extern "C"调用的是__stdcall是C调用吗,在加载的时候必须声明一下WINAPI就是VC中宏定义的__stdcall,可是我将WINAPI去掉,发现错误没了,这样和教程所讲的正好相反呀。我还有一个问题,我在使用费dll对话框子框的时候,还是用CTreeCtrl调用子界面,我的程序如下
    //判断IDs是哪个界面
    switch(IDs)
    {
    case 01:
    如果当前不是dlg1,则创建并显示
    if (!IsWindow(dlg1.GetSafeHwnd()))
    {
        dlg1.Create(IDD_MAIN_DIALOG2,this);
        dlg1.ShowWindow(SW_SHOW);
        dlg1.MoveWindow(rc);
    }
    //如果当前界面是dlg2,关闭dlg2
    if (IsWindow(dlg2.GetSafeHwnd()))
    {
        dlg2.DestroyWindow();
    }
    ...
    如上,我想问下,在dll调用子对话框的时候使用前帖中的代码可以吗?
    还有hmod1,hmod2,hmod什么时候FreeLibrary才对呀
      

  3.   

    我还有个问题,即使在MFC dll常规模式下建的dll文件,我想问下在这种工程下建几个类,我已经建了一个dialog对话框并在这个对话框新建一个类,现在想再建一个类,在这个类中调用Dialog,只在类中调用了一个dialog对话框的头文件,竟然就报错,这个错误时IDD_DIALOG未定义,就是我这个Dialog类中enum { IDD = IDD_CHILD_DLGREL };这句与Dialog资源相关的语句竟然出错,有高手给我看看吗
      

  4.   

    extern "C"和调用约定没有关系的。
    可以 extern "C" __stdcall也可以extern "C" __declsc
    VC默认的是__declsc,所以只写extern "C"的话就不是WINAPI
      

  5.   

    用DEF文件导出吧,我从来不用什么declsc
      

  6.   

    我也是遇到类似楼主的问题,努力学习dll中。。