DXUT库,CDXUTDialogResourceManager的一个不太好发现的问题

来源:互联网 发布:融资出让股份算法 编辑:程序博客网 时间:2024/04/30 02:01

 

如果按照DXUT例子的编码方式,很难出现这个问题的,但是这两日闲来无事,将DXUT分到了一个DLL内,结果……
退出时报错!

不断注释代码,最后发现是CDXUTDialogResourceManager惹的祸。再一检查,有些心得,遂拿来共享。


原因是这样的:
CDXUTDialogResourceManager在析构函数里干掉Cache(Delete):
//--------------------------------------------------------------------------------------
CDXUTDialogResourceManager::~CDXUTDialogResourceManager()
{
    int i;
    for( i=0; i < m_FontCache.GetSize(); i++ )
    {
        DXUTFontNode* pFontNode = m_FontCache.GetAt( i );
        SAFE_DELETE( pFontNode );
    }
    m_FontCache.RemoveAll();   

    for( i=0; i < m_TextureCache.GetSize(); i++ )
    {
        DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i );
        SAFE_DELETE( pTextureNode );
    }
    m_TextureCache.RemoveAll();   

    CUniBuffer::Uninitialize();
    CDXUTIMEEditBox::Uninitialize();
}
//--------------------------------------------------------------------------------------



而在OnDestroyDevice里真正Release这些资源:
//--------------------------------------------------------------------------------------
void CDXUTDialogResourceManager::OnDestroyDevice()
{
    int i=0; 

    m_pd3dDevice = NULL;

    // Release the resources but don't clear the cache, as these will need to be
    // recreated if the device is recreated
    for( i=0; i < m_FontCache.GetSize(); i++ )
    {
        DXUTFontNode* pFontNode = m_FontCache.GetAt( i );
        SAFE_RELEASE( pFontNode->pFont );
    }
    
    for( i=0; i < m_TextureCache.GetSize(); i++ )
    {
        DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i );
        SAFE_RELEASE( pTextureNode->pTexture );
    }

    SAFE_RELEASE( m_pSprite );
}
//--------------------------------------------------------------------------------------
一般说来,在例子中,这个RM都是以全局变量形式存在的:
extern CDXUTDialogResourceManager g_DialogResourceManager; // manager for shared resources of dialogs

这就有一个问题,OnDestroyDevice和析构函数究竟哪个在先?这就要看OnDestroyDevice的最终调用者DXUTState这个全局变量和g_DialogResourceManager这个全局变量的析构先后顺序了。
一般,如果这些代码和您的代码都编译到一个EXE,则顺序大凡是先State析构,调用DestroyDevice再RM析构,这就对了,既Release又Delete。
而在将DXUT封到Dll后,便发生了位于Dll的State后于位于EXE 的 RM析构的情况,这导致了先调用了RM的析构函数,然后才调用了State析构和OnDestroyDevice!!!
这意味着先调用了Delete,然后在Release的时候就找不着北了,资源没有Release,DXUT自然会报错!


由此得出一个结论:VC的CRT在退出时,先干掉了EXE本身的全局变量,然后才去释放各个DLL……
写到这里后,又发现DXUTState是一个非导出类,遂导出之,结果依旧……
不知对否,遂又作测试,发现凡是EXE中的全局变量,全都在Dll的State前析构。
extern CDXUTDialog             g_HUD;                  // dialog for standard controls
extern CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
皆如此。

解决的方案就近乎简单了,DialogRM 既然都析构了,何不调用自己的Release?为何一定要在State析构时才调用呢?
因此为增加一句:
CDXUTDialogResourceManager::~CDXUTDialogResourceManager()
{
[color=blue] /////////////////////////////////////////////////
OnDestroyDevice();
/////////////////////////////////////////////////
[/color]
    int i;
    for( i=0; i < m_FontCache.GetSize(); i++ )
    {
        DXUTFontNode* pFontNode = m_FontCache.GetAt( i );
        SAFE_DELETE( pFontNode );
    }
    m_FontCache.RemoveAll();   

    for( i=0; i < m_TextureCache.GetSize(); i++ )
    {
        DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i );
        SAFE_DELETE( pTextureNode );
    }
    m_TextureCache.RemoveAll();   

    CUniBuffer::Uninitialize();
    CDXUTIMEEditBox::Uninitialize();
}

去掉其他地方对RM 的OnDestroyDevice 的调用。
再编译连接,成功,不会再在退出时报错了。

结论:
该谁的事情谁自己处理,别让别人擦屁股,否则总会受人牵制。

欢迎大家指正 ^_^


原创粉丝点击