0

IDE:Eclipse Juno;编译器:MinGW 4.6.2;项目:Win32

我有一个带有两个有点不同的 MDI 子窗口的MainWindow : MdiChildWindowAMdiChildWindowB。第三个子窗口SharedWindow不是 MDI,但可以由任一 MDI 子窗口使用。所有这些都封装在它们自己的 C++ 类中。

为了避免SharedWindow的扩散,我借用了单例设计的一部分:MainWindowClass::GetSharedWindowInstance()将返回一个指向SharedWindow实例的指针,如果不存在则创建一个。 MainWindow.h包括SharedWindow* pSharedWindow备份功能。(这与SharedWindow成为单身人士一样接近。)

MainWindow实例化MdiChildWindowAMdiChildWindowB时,它传递this给它们的构造函数,它们保存在类变量中pMainWindow(定义为MainWindow*MdiChildWindowA.hMdiChildWindowB.h

coutMainWindowthis中的 of匹配MDI子窗口构造函数中的 ,但是当另一个函数调用时,已经改变了!制作静态似乎已经解决了问题,但如何改变?coutpMainWindowpMainWindow->GetSharedWindowInstance()pMainWindowpMainWindowpMainWindow

同样,我发现HMODULEandLPPICTURE变量在 in 中是静态的,SharedWindow.h否则它们会忘记它们在SharedWindow.cpp. 指针类型是否以某种方式免于作为类变量的持久性? 我认为static这是为了确保其类的所有实例都具有一个值。

编辑 2013-Sep-04:
下面是我的Application.cpp(大部分是从教程中复制的)。我以为我的MainWindow实例是在堆上创建的,并且会一直持续到退出。

#include "MainWindow.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow )
{   MSG  msg;
    HWND hMdiClientWindow;

    MainWindow *winMain = new MainWindow( hInstance );
    if( !winMain->Run( nCmdShow ) )
    {   delete winMain;
        return 1;
    }

    hMdiClientWindow = winMain->GetMdiClientWindow();

    while( GetMessage( &msg, NULL, 0, 0 ) )
    {   if( ! TranslateMDISysAccel( hMdiClientWindow, &msg ) )
        {   TranslateMessage( &msg );
            DispatchMessage ( &msg );
        }
    }

    delete winMain;

    return msg.wParam;
}

new MainWindow(...)调用MainWindow::MainWindow(),其中cout显示this0xdd13a0

MainWindow是在对 的调用中创建的Run(...),它将指针传递给MainWindowin的实例lpParam

bool MainWindow::Run( int nCmdShow )
{   ...
    hMainWindow = CreateWindowEx( ..., this );
    ...
}

在窗口过程中,指针保存在MainWindow的实例数据中:

LRESULT CALLBACK MainWindow::MainWindowProcedure( HWND hMainWindow, UINT Msg, WPARAM wParam, LPARAM lParam )
{   MainWindow* pThis;

    if( Msg == WM_NCCREATE )
    {   CREATESTRUCT* pCreateStruct = (CREATESTRUCT*) lParam;
        pThis = (MainWindow*) pCreateStruct->lpCreateParams;
        SetWindowLongPtr( hMainWindow, GWL_USERDATA, (LONG) pThis );
    } else
    {   pThis = (MainWindow*) GetWindowLongPtr( hMainWindow, GWL_USERDATA );
    }

在中,当它被传递给MdiChildWindowAMdiChildWindowBWM_CREATE的构造函数时,cout显示pThis0xdd13a0

switch( Msg )
{   ...
    case WM_CREATE:
    {   unique_ptr<MdiChildWindowA> upMdiChildWindowA;
        unique_ptr<MdiChildWindowB> upMdiChildWindowB;
        ...
        up_MdiChildWindowA = unique_ptr<MdiChildWindowA>( new MdiChildWindowA( m_hInstance, pThis, [window dimensions] ) );
        up_MdiChildWindowB = unique_ptr<MdiChildWindowB>( new MdiChildWindowB( m_hInstance, pThis, [window dimensions] ) );

MDI 子窗口的构造函数MainWindow将参数中的指针复制pMainWindow到类变量m_pMainWindow中,并cout显示两者都包含0xdd13a0

MdiChildWindowA::MdiChildWindowA( HINSTANCE hInstance, MainWindow* pMainWindow, ... )
{   m_pMainWindow = pMainWindow;
    ....
}

WM_CREATEMDI 子窗口程序中,cout显示m_pMainWindow仍包含0xdd13a0。唯一的其他引用m_pMainWindow发生在WM_LBUTTONDBLCLICK哪里,除非我将其设为静态,否则它会以某种方式变为0xdd1380(可能在传递过程中DefMDIChildProc(...)?):

MdiChildWindowA::MdiChildWindowProcedure( ... )
{   ...
    switch( ... )
    {   ...
        case WM_LBUTTONDBLCLICK:
        {   SharedWindow* pSharedWindow;
            ...
            pSharedWindow = pThis->m_pMainWindow->GetInstanceOfSharedWindow();  // pThis points to this instance of MdiChildWindowA. cout confirms its value hasn't changed.

由于m_pMainWindow指向错误的地方,当SharedWindow通过 调用函数时程序崩溃pSharedWindow。然而,它似乎GetInstanceOfSharedWindow()存在于这个虚假实例中,MainWindow因为返回了一个地址 - 但是,在上面的代码中,它是MdiChildWindowA!

(注意:我的命名约定让人抓狂,所以我用不太危险的名字重新输入了代码。希望没有错别字。)

@brunocodutra,@Chris Hayes:我还没有足够的评论意见,但我很欣赏你的想法。

4

1 回答 1

0

没有完整的相关代码很难说,但我猜MainWindow正在被释放。我会进一步猜测MainWindow最初存储在堆栈中,而不是堆中,因为导致地址更改的是函数调用(它会更改堆栈)。

我的建议:验证MainWindowMdiChildWindowAMdiChildWindowB(不确定哪个pMainWindow更改)是否是局部变量,如果是,请更改您的代码,以便它们在堆中分配,即通过使用关键字动态分配new

回答第二个问题,指针的处理方式与任何其他类型没有区别,本质上它们非常像整数,但它们的内容被迅速允许被解释为内存地址。

于 2013-09-04T02:34:47.570 回答