I'll post the particulars of both scenarios. Keep in mind that my "cegui usage environment" is fairly complex. I use cegui for a LOT of our application. It has been at the root of many of the features we have developed. There is a lot of dynamic creation/destruction of windows, registration of subscribers to be invoked on callback, dynamic creation of imagesets, etc. I mention this since the operating environment is not easily replicated, just based on a small snapshot of code. Nonetheless I'll highlight the specifics of the two scenarios.
Scenario 1:
I create a stack of "dispalyedimages". Each displayed image is initialized as follows:
The declaration:
Code: Select all
CEGUI::DefaultWindow *mImgGroupWindow;
CEGUI::DefaultWindow *mImgBoundingWindow;
CEGUI::DefaultWindow *mImgWindow;
CEGUI::Window *mImgLabelWindow;
The initialization/subscription:
Code: Select all
bool DisplayedImage::init(const std::string& imgName)
{
try {
mImgGroupWindow = static_cast<CEGUI::DefaultWindow *>(WidgetMaker::getSingleton().createWindow(WidgetMaker::DEFAULTWINDOW, imgName+".grp", false));
mImgBoundingWindow = static_cast<CEGUI::DefaultWindow *>(WidgetMaker::getSingleton().createWindow(WidgetMaker::STATICIMAGE, imgName+".bnd"));
mImgLabelWindow = WidgetMaker::getSingleton().createWindow(WidgetMaker::DIALOGITEMLABEL, imgName+".lbl", true);
mImgWindow = static_cast<CEGUI::DefaultWindow *>(WidgetMaker::getSingleton().createWindow(WidgetMaker::STATICIMAGE, imgName, false));
mImgBoundingWindow->addChildWindow(mImgWindow);
mImgGroupWindow->addChildWindow(mImgLabelWindow);
mImgGroupWindow->addChildWindow(mImgBoundingWindow);
mImgWindow->show();
mImgBoundingWindow->setProperty("FrameEnabled", "true");
mImgBoundingWindow->setProperty("BackgroundEnabled", "false");
mImgWindow->setProperty("FrameEnabled", "false");
mImgWindow->setProperty("BackgroundEnabled", "false");
mImgWindow->setInheritsAlpha(false);
mImgGroupWindow->hide();
// Setup callbacks
mImgMouseClickEventConnection = mImgWindow->subscribeEvent(CEGUI::DefaultWindow::EventMouseClick, CEGUI::Event::Subscriber(&DisplayedImage::handleMouseClick, this));
}
catch (CEGUI::Exception ce)
{
SVTConsole::getSingleton().printError(ce);
uninit();
return false;
}
return true;
}
Notice the single call to subscribeEvent. I used to ignore the eventconnection returned by this call.
My uninitialize method:
Code: Select all
void DisplayedImage::uninit()
{
if(mImgMouseClickEventConnection->connected())
{
mImgMouseClickEventConnection->disconnect();
}
if(mImgWindow)
{
WidgetMaker::getSingleton().destroyWindow(mImgWindow);
mImgWindow = 0;
}
if(mImgLabelWindow)
{
WidgetMaker::getSingleton().destroyWindow(mImgLabelWindow, true);
mImgLabelWindow = 0;
}
if(mImgBoundingWindow)
{
WidgetMaker::getSingleton().destroyWindow(mImgBoundingWindow);
mImgBoundingWindow = 0;
}
if(mImgGroupWindow)
{
WidgetMaker::getSingleton().destroyWindow(mImgGroupWindow);
mImgGroupWindow = 0;
}
}
As you see now, I no longer ignore it. When I did ignore it then the access violation that you saw in the initial post occurred. This displayed image is part of an image browser plugin that is part of our application. Our application architecture is a "pluggable" architecture. Many features of the application are loaded (plugged in), as needed. The init method is called when the plugin library is loaded as part of application startup. The uninit method is called when the plugin objects are destroyed on application shutdown.
Scenario 2:The second scenario is in a "Control Panel Management" class that is part of our base application. Plugins can register themselves with the manager so that they can be launched through pusbutton press (the pushbuttons are controls in the control panel).
These callbacks are registered as follows:
Code: Select all
void ControlPanelManager::registerCallback(const std::string& funcKey, CEGUI::Event::Subscriber *subscriber)
{
SubscriberConnectionPair scp;
scp.first = subscriber;
mControlCallbackMap[funcKey] = scp;
}
Notice the structure of a "SubscriberConnectionPair"
Code: Select all
typedef std::pair<CEGUI::Event::Subscriber*, CEGUI::Event::Connection> SubscriberConnectionPair;
This structure has been introduced as part of my "work-around". I was ignoring the connection until I worked to solve this long-standing shutdown issue.
Clients of the manager register as follows:
Code: Select all
CEGUI::Event::Subscriber *subscriber = (CEGUI::Event::Subscriber *)new CEGUI::Event::Subscriber(&IntellidarPluginManager::handleToggleInterfaceStatisticsMenu, this);
appView.registerCallback(sControlPanelName, subscriber);
In this example the "appView" is a ControlPanelManager.
The actual subscription occurs subsequent to this registry action:
Code: Select all
ControlCallbackMap::iterator refitr = mControlCallbackMap.find(ctlItr->second.referenceName);
if(refitr != mControlCallbackMap.end())
{
refitr->second.second = window->subscribeEvent(evtType, *(refitr->second.first));
return 0;
}
Code: Select all
typedef std::map<std::string, SubscriberConnectionPair> ControlCallbackMap;
Here, again, you see that I am no longer ignoring the return from the subscription. My subsequent shutdown will release the connection:
Code: Select all
void ControlPanelManager::unregisterCallback(const std::string& funcKey)
{
ControlCallbackMap::iterator it = mControlCallbackMap.find(funcKey);
if(it != mControlCallbackMap.end())
{
if(it->second.second->connected())
{
it->second.second->disconnect();
}
mControlCallbackMap.erase(it);
}
}