mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-11-17 13:01:42 +00:00
Merge with develop
This commit is contained in:
parent
2b4058ed95
commit
ad26721df6
11 changed files with 89 additions and 92 deletions
|
@ -45,7 +45,7 @@ SOURCE_GROUP("Translation Files" FILES ${CLIENT_INSTALL_TRANS} ${CLIENT_INSTALL_
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
SET(MACOSX_BUNDLE_INFO_STRING "Ryzom Installer")
|
SET(MACOSX_BUNDLE_INFO_STRING "Ryzom Installer")
|
||||||
SET(MACOSX_BUNDLE_ICON_FILE "ryzom.icns")
|
SET(MACOSX_BUNDLE_ICON_FILE "ryzom.icns")
|
||||||
SET(MACOSX_BUNDLE_GUI_IDENTIFIER "")
|
SET(MACOSX_BUNDLE_GUI_IDENTIFIER "com.winchgate.RyzomInstaller")
|
||||||
SET(MACOSX_BUNDLE_LONG_VERSION_STRING ${RYZOM_VERSION})
|
SET(MACOSX_BUNDLE_LONG_VERSION_STRING ${RYZOM_VERSION})
|
||||||
SET(MACOSX_BUNDLE_BUNDLE_NAME "Ryzom Installer")
|
SET(MACOSX_BUNDLE_BUNDLE_NAME "Ryzom Installer")
|
||||||
SET(MACOSX_BUNDLE_SHORT_VERSION_STRING ${RYZOM_VERSION})
|
SET(MACOSX_BUNDLE_SHORT_VERSION_STRING ${RYZOM_VERSION})
|
||||||
|
|
|
@ -10,18 +10,8 @@
|
||||||
<string>$NAME</string>
|
<string>$NAME</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>ryzom.icns</string>
|
<string>ryzom.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>$IDENTIFIER</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleLocalizations</key>
|
|
||||||
<array>
|
|
||||||
<string>en</string>
|
|
||||||
<string>fr</string>
|
|
||||||
<string>de</string>
|
|
||||||
<string>ru</string>
|
|
||||||
<string>es</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleLongVersionString</key>
|
<key>CFBundleLongVersionString</key>
|
||||||
<string>$VERSION</string>
|
<string>$VERSION</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
@ -38,16 +28,8 @@
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CSResourcesFileMapped</key>
|
|
||||||
<true/>
|
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.role-playing-games</string>
|
<string>public.app-category.role-playing-games</string>
|
||||||
<key>LSFileQuarantineEnabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>10.6</string>
|
|
||||||
<key>LSRequiresCarbon</key>
|
|
||||||
<true/>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>$COPYRIGHT</string>
|
<string>$COPYRIGHT</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|
|
@ -502,7 +502,7 @@ bool CFilesExtractor::extract7z()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SZ_ERROR_INPUT_EOF:
|
case SZ_ERROR_INPUT_EOF:
|
||||||
error = QApplication::tr("Errors in 7z file");
|
error = QApplication::tr("File %1 is corrupted, unable to uncompress it").arg(m_sourceFile);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SZ_ERROR_FAIL:
|
case SZ_ERROR_FAIL:
|
||||||
|
|
|
@ -216,6 +216,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
COperationDialog dialog;
|
COperationDialog dialog;
|
||||||
|
|
||||||
|
dialog.setCurrentServerId(config.getProfile().server);
|
||||||
dialog.setOperation(OperationUninstall);
|
dialog.setOperation(OperationUninstall);
|
||||||
dialog.setUninstallComponents(components);
|
dialog.setUninstallComponents(components);
|
||||||
|
|
||||||
|
@ -244,6 +245,7 @@ int main(int argc, char *argv[])
|
||||||
if (step != Done)
|
if (step != Done)
|
||||||
{
|
{
|
||||||
COperationDialog dialog;
|
COperationDialog dialog;
|
||||||
|
dialog.setCurrentServerId(config.getProfile().server);
|
||||||
dialog.setOperation(config.getSrcServerDirectory().isEmpty() ? OperationInstall:OperationMigrate);
|
dialog.setOperation(config.getSrcServerDirectory().isEmpty() ? OperationInstall:OperationMigrate);
|
||||||
|
|
||||||
if (!dialog.exec()) return 1;
|
if (!dialog.exec()) return 1;
|
||||||
|
|
|
@ -126,12 +126,6 @@ void COperationDialog::processInstallNextStep()
|
||||||
{
|
{
|
||||||
CConfigFile *config = CConfigFile::getInstance();
|
CConfigFile *config = CConfigFile::getInstance();
|
||||||
|
|
||||||
// default server
|
|
||||||
const CServer &server = config->getServer();
|
|
||||||
|
|
||||||
// default profile
|
|
||||||
const CProfile &configuration = config->getProfile();
|
|
||||||
|
|
||||||
// long operations are done in a thread
|
// long operations are done in a thread
|
||||||
OperationStep step = config->getInstallNextStep();
|
OperationStep step = config->getInstallNextStep();
|
||||||
|
|
||||||
|
@ -352,8 +346,10 @@ void COperationDialog::processUpdateProfilesNextStep()
|
||||||
if (server.clientDownloadUrl == defaultServer.clientDownloadUrl)
|
if (server.clientDownloadUrl == defaultServer.clientDownloadUrl)
|
||||||
{
|
{
|
||||||
if (QFile::exists(""))
|
if (QFile::exists(""))
|
||||||
|
{
|
||||||
downloadData();
|
downloadData();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -558,12 +554,7 @@ void COperationDialog::extractDownloadedData()
|
||||||
extractor.setSourceFile(config->getInstallationDirectory() + "/" + server.dataDownloadFilename);
|
extractor.setSourceFile(config->getInstallationDirectory() + "/" + server.dataDownloadFilename);
|
||||||
extractor.setDestinationDirectory(dest);
|
extractor.setDestinationDirectory(dest);
|
||||||
|
|
||||||
if (extractor.exec())
|
if (!extractor.exec()) return;
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
emit done();
|
emit done();
|
||||||
}
|
}
|
||||||
|
@ -593,12 +584,7 @@ void COperationDialog::extractDownloadedClient()
|
||||||
extractor.setSourceFile(config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename));
|
extractor.setSourceFile(config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename));
|
||||||
extractor.setDestinationDirectory(destinationDirectory);
|
extractor.setDestinationDirectory(destinationDirectory);
|
||||||
|
|
||||||
if (extractor.exec())
|
if (!extractor.exec()) return;
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
launchUpgradeScript(destinationDirectory, server.clientFilename);
|
launchUpgradeScript(destinationDirectory, server.clientFilename);
|
||||||
|
|
||||||
|
@ -626,12 +612,7 @@ void COperationDialog::copyDataFiles()
|
||||||
copier.setDestinationDirectory(server.getDirectory());
|
copier.setDestinationDirectory(server.getDirectory());
|
||||||
copier.setIncludeFilter(serverFiles);
|
copier.setIncludeFilter(serverFiles);
|
||||||
|
|
||||||
if (copier.exec())
|
if (!copier.exec()) return;
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
emit done();
|
emit done();
|
||||||
}
|
}
|
||||||
|
@ -661,12 +642,7 @@ void COperationDialog::copyProfileFiles()
|
||||||
copier.setDestinationDirectory(profile.getDirectory());
|
copier.setDestinationDirectory(profile.getDirectory());
|
||||||
copier.setIncludeFilter(profileFiles);
|
copier.setIncludeFilter(profileFiles);
|
||||||
|
|
||||||
if (copier.exec())
|
if (!copier.exec()) return;
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// correct path to client_default.cfg
|
// correct path to client_default.cfg
|
||||||
profile.createClientConfig();
|
profile.createClientConfig();
|
||||||
|
@ -688,7 +664,8 @@ void COperationDialog::extractBnpClient()
|
||||||
CFilesExtractor extractor(this);
|
CFilesExtractor extractor(this);
|
||||||
extractor.setSourceFile(config->getSrcServerClientBNPFullPath());
|
extractor.setSourceFile(config->getSrcServerClientBNPFullPath());
|
||||||
extractor.setDestinationDirectory(destinationDirectory);
|
extractor.setDestinationDirectory(destinationDirectory);
|
||||||
extractor.exec();
|
|
||||||
|
if (!extractor.exec()) return;
|
||||||
|
|
||||||
launchUpgradeScript(destinationDirectory, server.clientFilename);
|
launchUpgradeScript(destinationDirectory, server.clientFilename);
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
|
|
||||||
void setOperation(OperationType operation);
|
void setOperation(OperationType operation);
|
||||||
void setUninstallComponents(const SComponents &components);
|
void setUninstallComponents(const SComponents &components);
|
||||||
|
void setCurrentServerId(const QString &serverId) { m_currentServerId = serverId; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onAbortClicked();
|
void onAbortClicked();
|
||||||
|
|
|
@ -49,6 +49,29 @@ void CProfile::saveToSettings(QSettings &settings) const
|
||||||
settings.setValue("menu_shortcut", menuShortcut);
|
settings.setValue("menu_shortcut", menuShortcut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CProfile::isValid(QString &error) const
|
||||||
|
{
|
||||||
|
QRegExp idReg("^[0-9a-z_]+$");
|
||||||
|
|
||||||
|
if (!idReg.exactMatch(id))
|
||||||
|
{
|
||||||
|
error = QApplication::tr("Profile ID %1 is using invalid characters (only lowercase letters, numbers and underscore are allowed)").arg(id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegExp nameReg("[/\\\\<>?*:.%|\"]");
|
||||||
|
|
||||||
|
int pos = nameReg.indexIn(name);
|
||||||
|
|
||||||
|
if (pos > -1)
|
||||||
|
{
|
||||||
|
error = QApplication::tr("Profile name %1 is using invalid character %2 at position %3").arg(name).arg(name[pos]).arg(pos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QString CProfile::getDirectory() const
|
QString CProfile::getDirectory() const
|
||||||
{
|
{
|
||||||
return CConfigFile::getInstance()->getProfileDirectory() + "/" + id;
|
return CConfigFile::getInstance()->getProfileDirectory() + "/" + id;
|
||||||
|
@ -105,7 +128,7 @@ void CProfile::createShortcuts() const
|
||||||
// create desktop shortcut
|
// create desktop shortcut
|
||||||
if (!createShortcut(shortcut, name, exe, profileArguments, icon, workingDir))
|
if (!createShortcut(shortcut, name, exe, profileArguments, icon, workingDir))
|
||||||
{
|
{
|
||||||
qDebug() << "Unable to create desktop directory";
|
qDebug() << "Unable to create desktop shortcut";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ public:
|
||||||
void loadFromSettings(const QSettings &settings);
|
void loadFromSettings(const QSettings &settings);
|
||||||
void saveToSettings(QSettings &settings) const;
|
void saveToSettings(QSettings &settings) const;
|
||||||
|
|
||||||
|
bool isValid(QString &error) const;
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
QString getDirectory() const;
|
QString getDirectory() const;
|
||||||
QString getClientFullPath() const;
|
QString getClientFullPath() const;
|
||||||
|
|
|
@ -56,6 +56,21 @@ void CProfilesDialog::accept()
|
||||||
{
|
{
|
||||||
saveProfile(m_currentProfileIndex);
|
saveProfile(m_currentProfileIndex);
|
||||||
|
|
||||||
|
const CProfiles &profiles = m_model->getProfiles();
|
||||||
|
|
||||||
|
// check if profiles are valid
|
||||||
|
foreach(const CProfile &profile, profiles)
|
||||||
|
{
|
||||||
|
QString error;
|
||||||
|
|
||||||
|
if (!profile.isValid(error))
|
||||||
|
{
|
||||||
|
// display an error message
|
||||||
|
QMessageBox::critical(this, tr("Error"), error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_model->save();
|
m_model->save();
|
||||||
|
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
|
|
|
@ -41,36 +41,6 @@ QString qBytesToHumanReadable(qint64 bytes)
|
||||||
return QString::fromUtf8(NLMISC::bytesToHumanReadableUnits(bytes, units).c_str());
|
return QString::fromUtf8(NLMISC::bytesToHumanReadableUnits(bytes, units).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString nameToId(const QString &name)
|
|
||||||
{
|
|
||||||
QString res;
|
|
||||||
|
|
||||||
// only allows simple characters
|
|
||||||
QRegExp allowedCharacters("^[0-9a-zA-Z-]$");
|
|
||||||
|
|
||||||
for (int i = 0, len = name.length(); i < len; ++i)
|
|
||||||
{
|
|
||||||
if (allowedCharacters.indexIn(name.at(i)) > -1)
|
|
||||||
{
|
|
||||||
// allowed character
|
|
||||||
res += name[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// not allowed, replace by a space
|
|
||||||
res += " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// simplify all spaces
|
|
||||||
res = res.simplified();
|
|
||||||
|
|
||||||
// replace spaces by minus
|
|
||||||
res.replace(" ", "-");
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDirectoryEmpty(const QString &directory, bool recursize)
|
bool isDirectoryEmpty(const QString &directory, bool recursize)
|
||||||
{
|
{
|
||||||
bool res = true;
|
bool res = true;
|
||||||
|
@ -81,18 +51,21 @@ bool isDirectoryEmpty(const QString &directory, bool recursize)
|
||||||
|
|
||||||
if (dir.exists())
|
if (dir.exists())
|
||||||
{
|
{
|
||||||
|
// process all files and directories excepted parent and current ones
|
||||||
QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot);
|
QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); ++i)
|
for (int i = 0, len = list.size(); i < len; ++i)
|
||||||
{
|
{
|
||||||
QFileInfo fileInfo = list.at(i);
|
QFileInfo fileInfo = list.at(i);
|
||||||
|
|
||||||
if (fileInfo.isDir())
|
if (fileInfo.isDir())
|
||||||
{
|
{
|
||||||
|
// don't consider empty directories as files, but process it recursively if required
|
||||||
if (recursize) if (!isDirectoryEmpty(fileInfo.absoluteFilePath(), true)) return false;
|
if (recursize) if (!isDirectoryEmpty(fileInfo.absoluteFilePath(), true)) return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// we found a file, directory is not empty
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,6 +100,7 @@ qint64 getDirectorySize(const QString &directory, bool recursize)
|
||||||
|
|
||||||
if (dir.exists())
|
if (dir.exists())
|
||||||
{
|
{
|
||||||
|
// process all files and directories excepted parent and current ones
|
||||||
QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot);
|
QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); ++i)
|
for (int i = 0; i < list.size(); ++i)
|
||||||
|
@ -343,11 +317,11 @@ bool createShortcut(const QString &shortcut, const QString &name, const QString
|
||||||
|
|
||||||
CConfigFile *config = CConfigFile::getInstance();
|
CConfigFile *config = CConfigFile::getInstance();
|
||||||
|
|
||||||
|
// HTML escape values because they'll be in a XML file
|
||||||
strings.clear();
|
strings.clear();
|
||||||
strings["NAME"] = name;
|
strings["NAME"] = name.toHtmlEscaped();
|
||||||
strings["COPYRIGHT"] = config->getProductPublisher();
|
strings["COPYRIGHT"] = config->getProductPublisher().toHtmlEscaped();
|
||||||
strings["VERSION"] = QApplication::applicationVersion();
|
strings["VERSION"] = QApplication::applicationVersion();
|
||||||
strings["IDENTIFIER"] = "com.winchgate.Ryzom-" + nameToId(name);
|
|
||||||
|
|
||||||
// write Info.plist
|
// write Info.plist
|
||||||
if (!writeResourceWithTemplates(":/templates/Info.plist", plistFile, strings)) return false;
|
if (!writeResourceWithTemplates(":/templates/Info.plist", plistFile, strings)) return false;
|
||||||
|
|
|
@ -28,40 +28,61 @@
|
||||||
* \date 2016
|
* \date 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// convert a size in bytes to a QString with larger unit (KiB, MiB, etc...)
|
||||||
QString qBytesToHumanReadable(qint64 bytes);
|
QString qBytesToHumanReadable(qint64 bytes);
|
||||||
QString nameToId(const QString &name);
|
|
||||||
|
|
||||||
|
// return true is the specified directory is empty (has no file inside) (and all its subdirectories if recursize is true)
|
||||||
bool isDirectoryEmpty(const QString &directory, bool recursize);
|
bool isDirectoryEmpty(const QString &directory, bool recursize);
|
||||||
|
|
||||||
|
// check if specified directory is writable
|
||||||
bool isDirectoryWritable(const QString &directory);
|
bool isDirectoryWritable(const QString &directory);
|
||||||
|
|
||||||
|
// return the total size in bytes of specified directtory (and all its subdirectories if recursize is true)
|
||||||
qint64 getDirectorySize(const QString &directory, bool recursize);
|
qint64 getDirectorySize(const QString &directory, bool recursize);
|
||||||
|
|
||||||
// Convert a UTF-8 string to QString
|
// convert a UTF-8 string to QString
|
||||||
QString qFromUtf8(const std::string &str);
|
QString qFromUtf8(const std::string &str);
|
||||||
|
|
||||||
// Convert a QString to UTF-8 string
|
// convert a QString to UTF-8 string
|
||||||
std::string qToUtf8(const QString &str);
|
std::string qToUtf8(const QString &str);
|
||||||
|
|
||||||
// Convert a UTF-16 string to QString
|
// convert an UTF-16 string to QString
|
||||||
QString qFromUtf16(const ucstring &str);
|
QString qFromUtf16(const ucstring &str);
|
||||||
|
|
||||||
// Convert a QString to UTF-16 string
|
// convert a QString to UTF-16 string
|
||||||
ucstring qToUtf16(const QString &str);
|
ucstring qToUtf16(const QString &str);
|
||||||
|
|
||||||
|
// convert an wchar_t* to QString
|
||||||
QString qFromWide(const wchar_t *str);
|
QString qFromWide(const wchar_t *str);
|
||||||
|
|
||||||
|
// convert an QString to wchar_t*
|
||||||
wchar_t* qToWide(const QString &str);
|
wchar_t* qToWide(const QString &str);
|
||||||
|
|
||||||
|
// check if a shortcut already exists (the extension will be added)
|
||||||
bool shortcutExists(const QString &shortcut);
|
bool shortcutExists(const QString &shortcut);
|
||||||
|
|
||||||
|
// create a shortcut with the native format of the current platform
|
||||||
bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir);
|
bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir);
|
||||||
|
|
||||||
|
// remove a shortcut (the extension will be added)
|
||||||
bool removeShortcut(const QString &shortcut);
|
bool removeShortcut(const QString &shortcut);
|
||||||
|
|
||||||
|
// return the real path of shortcut
|
||||||
bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &pathObj);
|
bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &pathObj);
|
||||||
|
|
||||||
|
// append the shortcut of current platform to specified path
|
||||||
QString appendShortcutExtension(const QString &shortcut);
|
QString appendShortcutExtension(const QString &shortcut);
|
||||||
|
|
||||||
|
// launch an executable with --version parameter and parse version string
|
||||||
QString getVersionFromExecutable(const QString &path);
|
QString getVersionFromExecutable(const QString &path);
|
||||||
|
|
||||||
|
// write a resource in QRC to disk
|
||||||
bool writeResource(const QString &resource, const QString &path);
|
bool writeResource(const QString &resource, const QString &path);
|
||||||
|
|
||||||
|
// write a resource in QRC to disk and replace all variables by specified values
|
||||||
bool writeResourceWithTemplates(const QString &resource, const QString &path, const QMap<QString, QString> &strings);
|
bool writeResourceWithTemplates(const QString &resource, const QString &path, const QMap<QString, QString> &strings);
|
||||||
|
|
||||||
|
// a little helper class to unintialize COM after using it
|
||||||
class CCOMHelper
|
class CCOMHelper
|
||||||
{
|
{
|
||||||
bool m_mustUninit;
|
bool m_mustUninit;
|
||||||
|
|
Loading…
Reference in a new issue