Merge branch 'feature_updater' into develop
This commit is contained in:
commit
7f52bed9e3
@ -97,6 +97,9 @@ include_directories(${LIBSETTINGS_INCLUDE_DIR})
|
||||
add_subdirectory(depends/groupview)
|
||||
include_directories(${LIBGROUPVIEW_INCLUDE_DIR})
|
||||
|
||||
# Add the updater
|
||||
add_subdirectory(mmc_updater)
|
||||
|
||||
################################ SET UP BUILD OPTIONS ################################
|
||||
|
||||
######## Check endianness ########
|
||||
@ -115,24 +118,54 @@ SET(MultiMC_VERSION_MINOR 0)
|
||||
SET(MultiMC_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
|
||||
|
||||
# Build type
|
||||
SET(MultiMC_VERSION_BUILD_TYPE "custombuild" CACHE STRING "Build type. Usually corresponds to the buildbot build name. Empty string for no build type.")
|
||||
SET(MultiMC_VERSION_BUILD_TYPE "custombuild" CACHE STRING "Build type. If this is set, it is appended to the end of the version string with a dash (<version string>-<build type>. It is not used for anything other than indicating in the version string what type of build this is (eg 'lin64').")
|
||||
|
||||
# Version channel
|
||||
SET(MultiMC_VERSION_CHANNEL "" CACHE STRING "The current build's channel. Included in the version string.")
|
||||
|
||||
# Channel list URL
|
||||
SET(MultiMC_CHANLIST_URL "" CACHE STRING "URL for the channel list.")
|
||||
|
||||
# Updater enabled?
|
||||
SET(MultiMC_UPDATER false CACHE BOOL "Whether or not the update system is enabled. If this is enabled, you must also set MultiMC_CHANLIST_URL and MultiMC_VERSION_CHANNEL in order for it to work properly.")
|
||||
|
||||
|
||||
# Build a version string to display in the configure logs.
|
||||
SET(MultiMC_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}")
|
||||
|
||||
IF (MultiMC_VERSION_BUILD GREATER -1)
|
||||
SET(MultiMC_VERSION_STRING "${MultiMC_VERSION_STRING}.${MultiMC_VERSION_BUILD}")
|
||||
ENDIF ()
|
||||
|
||||
IF (NOT MultiMC_VERSION_CHANNEL STREQUAL "")
|
||||
SET(MultiMC_VERSION_STRING "${MultiMC_VERSION_STRING}-${MultiMC_VERSION_CHANNEL}")
|
||||
ENDIF ()
|
||||
IF (NOT MultiMC_VERSION_BUILD_TYPE STREQUAL "")
|
||||
SET(MultiMC_VERSION_STRING "${MultiMC_VERSION_STRING}-${MultiMC_VERSION_BUILD_TYPE}")
|
||||
ENDIF ()
|
||||
|
||||
MESSAGE(STATUS "MultiMC 5 version ${MultiMC_VERSION_STRING}")
|
||||
|
||||
# Custom target to just print the version.
|
||||
# If the update system is enabled, make sure MultiMC_CHANLIST_URL and MultiMC_VERSION_CHANNEL are set.
|
||||
IF (MultiMC_UPDATER)
|
||||
IF (MultiMC_VERSION_CHANNEL STREQUAL "")
|
||||
MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_CHANNEL is not set.\n"
|
||||
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
|
||||
ENDIF ()
|
||||
IF (MultiMC_CHANLIST_URL STREQUAL "")
|
||||
MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_CHANLIST_URL is not set.\n"
|
||||
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
|
||||
ENDIF ()
|
||||
IF (MultiMC_VERSION_BUILD LESS 0)
|
||||
MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_BUILD is not set.\n"
|
||||
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
|
||||
ENDIF ()
|
||||
|
||||
MESSAGE(STATUS "Updater is enabled. Channel list URL: ${MultiMC_CHANLIST_URL}")
|
||||
ENDIF ()
|
||||
|
||||
#### Custom target to just print the version.
|
||||
ADD_CUSTOM_TARGET(version echo "Version: ${MultiMC_VERSION_STRING}")
|
||||
|
||||
# Check the current Git commit
|
||||
#### Check the current Git commit
|
||||
execute_process(COMMAND git rev-parse HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_COMMIT_CHECK_RESULTVAR
|
||||
@ -140,7 +173,6 @@ execute_process(COMMAND git rev-parse HEAD
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# If Git executed successfully
|
||||
IF(GIT_COMMIT_CHECK_RESULTVAR EQUAL 0)
|
||||
SET(MultiMC_GIT_COMMIT "${GIT_COMMIT_CHECK_OUTVAR}")
|
||||
MESSAGE(STATUS "Git commit: ${MultiMC_GIT_COMMIT}")
|
||||
@ -149,41 +181,8 @@ ELSE()
|
||||
MESSAGE(STATUS "Failed to check Git commit. ${GIT_COMMIT_CHECK_RESULTVAR}")
|
||||
ENDIF()
|
||||
|
||||
|
||||
######## Set Jenkins info ########
|
||||
# Jenkins build tag
|
||||
IF(DEFINED MultiMC_BUILD_TAG)
|
||||
MESSAGE(STATUS "Build tag: ${MultiMC_BUILD_TAG}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "No build tag specified.")
|
||||
SET(MultiMC_BUILD_TAG custom)
|
||||
ENDIF()
|
||||
|
||||
# Architecture detection
|
||||
IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
SET(MultiMC_ARCH "x64" CACHE STRING "Architecture we're building for.")
|
||||
ELSE()
|
||||
SET(MultiMC_ARCH "x86" CACHE STRING "Architecture we're building for.")
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "Architecture is ${MultiMC_ARCH}")
|
||||
|
||||
# Jenkins job name
|
||||
IF(WIN32)
|
||||
SET(MultiMC_JOB_NAME "MultiMC5Windows" CACHE STRING "Jenkins job name.")
|
||||
ELSEIF(UNIX AND APPLE)
|
||||
SET(MultiMC_JOB_NAME "MultiMC5OSX" CACHE STRING "Jenkins job name.")
|
||||
ELSE()
|
||||
SET(MultiMC_JOB_NAME "MultiMC5Linux" CACHE STRING "Jenkins job name.")
|
||||
ENDIF()
|
||||
|
||||
# Jenkins URL
|
||||
SET(MultiMC_JOB_URL "http://ci.forkk.net/job/${MultiMC_JOB_NAME}/arch=${MultiMC_ARCH}${MultiMC_Extra_Label}/"
|
||||
CACHE STRING "URL of the jenkins job to pull updates from.")
|
||||
MESSAGE(STATUS "Job URL: ${MultiMC_JOB_URL}")
|
||||
|
||||
######## Configure header ########
|
||||
configure_file("${PROJECT_SOURCE_DIR}/config.h.in"
|
||||
"${PROJECT_BINARY_DIR}/include/config.h")
|
||||
configure_file("${PROJECT_SOURCE_DIR}/config.h.in" "${PROJECT_BINARY_DIR}/include/config.h")
|
||||
|
||||
|
||||
######## Other Stuff ########
|
||||
@ -251,6 +250,8 @@ gui/dialogs/AccountListDialog.h
|
||||
gui/dialogs/AccountListDialog.cpp
|
||||
gui/dialogs/AccountSelectDialog.h
|
||||
gui/dialogs/AccountSelectDialog.cpp
|
||||
gui/dialogs/UpdateDialog.h
|
||||
gui/dialogs/UpdateDialog.cpp
|
||||
|
||||
# GUI - widgets
|
||||
gui/widgets/InstanceDelegate.h
|
||||
@ -315,6 +316,12 @@ logic/auth/flows/RefreshTask.cpp
|
||||
logic/auth/flows/ValidateTask.h
|
||||
logic/auth/flows/ValidateTask.cpp
|
||||
|
||||
# Update system
|
||||
logic/updater/UpdateChecker.h
|
||||
logic/updater/UpdateChecker.cpp
|
||||
logic/updater/DownloadUpdateTask.h
|
||||
logic/updater/DownloadUpdateTask.cpp
|
||||
|
||||
# legacy instances
|
||||
logic/LegacyInstance.h
|
||||
logic/LegacyInstance.cpp
|
||||
@ -383,7 +390,6 @@ logic/NagUtils.h
|
||||
logic/NagUtils.cpp
|
||||
logic/SkinUtils.h
|
||||
logic/SkinUtils.cpp
|
||||
|
||||
)
|
||||
|
||||
|
||||
@ -410,6 +416,7 @@ gui/dialogs/EditNotesDialog.ui
|
||||
gui/dialogs/AccountListDialog.ui
|
||||
gui/dialogs/AccountSelectDialog.ui
|
||||
gui/dialogs/EditAccountDialog.ui
|
||||
gui/dialogs/UpdateDialog.ui
|
||||
|
||||
# Widgets/other
|
||||
gui/widgets/MCModInfoFrame.ui
|
||||
|
76
MultiMC.cpp
76
MultiMC.cpp
@ -2,10 +2,12 @@
|
||||
#include "MultiMC.h"
|
||||
#include <iostream>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QTranslator>
|
||||
#include <QLibraryInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QStringList>
|
||||
|
||||
#include "gui/MainWindow.h"
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
@ -21,6 +23,8 @@
|
||||
|
||||
#include "logic/JavaUtils.h"
|
||||
|
||||
#include "logic/updater/UpdateChecker.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
#include "cmdutils.h"
|
||||
#include <inisettingsobject.h>
|
||||
@ -32,7 +36,7 @@
|
||||
using namespace Util::Commandline;
|
||||
|
||||
MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv),
|
||||
m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_BUILD_TYPE}
|
||||
m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_CHANNEL, VERSION_BUILD_TYPE}
|
||||
{
|
||||
setOrganizationName("MultiMC");
|
||||
setApplicationName("MultiMC5");
|
||||
@ -138,6 +142,9 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv),
|
||||
// load settings
|
||||
initGlobalSettings();
|
||||
|
||||
// initialize the updater
|
||||
m_updateChecker.reset(new UpdateChecker());
|
||||
|
||||
// and instances
|
||||
auto InstDirSetting = m_settings->getSetting("InstanceDir");
|
||||
m_instances.reset(new InstanceList(InstDirSetting->get().toString(), this));
|
||||
@ -404,6 +411,65 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist()
|
||||
return m_javalist;
|
||||
}
|
||||
|
||||
#ifdef WINDOWS
|
||||
#define UPDATER_BIN "updater.exe"
|
||||
#elif LINUX
|
||||
#define UPDATER_BIN "updater"
|
||||
#elif OSX
|
||||
#define UPDATER_BIN "updater"
|
||||
#else
|
||||
#error Unsupported operating system.
|
||||
#endif
|
||||
|
||||
void MultiMC::installUpdates(const QString& updateFilesDir, bool restartOnFinish)
|
||||
{
|
||||
QLOG_INFO() << "Installing updates.";
|
||||
#if LINUX
|
||||
// On Linux, the MultiMC executable file is actually in the bin folder inside the installation directory.
|
||||
// This means that MultiMC's *actual* install path is the parent folder.
|
||||
// We need to tell the updater to run with this directory as the install path, rather than the bin folder where the executable is.
|
||||
// On other operating systems, we'll just use the path to the executable.
|
||||
QString appDir = QFileInfo(MMC->applicationDirPath()).dir().path();
|
||||
|
||||
// On Linux, we also need to set the finish command to the launch script, rather than the binary.
|
||||
QString finishCmd = PathCombine(appDir, "MultiMC");
|
||||
#else
|
||||
QString appDir = MMC->applicationDirPath();
|
||||
QString finishCmd = MMC->applicationFilePath();
|
||||
#endif
|
||||
|
||||
// Build the command we'll use to run the updater.
|
||||
// Note, the above comment about the app dir path on Linux is irrelevant here because the updater binary is always in the
|
||||
// same folder as the main binary.
|
||||
QString updaterBinary = PathCombine(MMC->applicationDirPath(), UPDATER_BIN);
|
||||
QStringList args;
|
||||
// ./updater --install-dir $INSTALL_DIR --package-dir $UPDATEFILES_DIR --script $UPDATEFILES_DIR/file_list.xml --wait $PID --mode main
|
||||
args << "--install-dir" << appDir;
|
||||
args << "--package-dir" << updateFilesDir;
|
||||
args << "--script" << PathCombine(updateFilesDir, "file_list.xml");
|
||||
args << "--wait" << QString::number(MMC->applicationPid());
|
||||
|
||||
if (restartOnFinish)
|
||||
args << "--finish-cmd" << finishCmd;
|
||||
|
||||
QLOG_INFO() << "Running updater with command" << updaterBinary << args.join(" ");
|
||||
|
||||
QProcess::startDetached(updaterBinary, args);
|
||||
|
||||
// Now that we've started the updater, quit MultiMC.
|
||||
MMC->quit();
|
||||
}
|
||||
|
||||
void MultiMC::setUpdateOnExit(const QString& updateFilesDir)
|
||||
{
|
||||
m_updateOnExitPath = updateFilesDir;
|
||||
}
|
||||
|
||||
QString MultiMC::getExitUpdatePath() const
|
||||
{
|
||||
return m_updateOnExitPath;
|
||||
}
|
||||
|
||||
int main_gui(MultiMC &app)
|
||||
{
|
||||
// show main window
|
||||
@ -412,7 +478,13 @@ int main_gui(MultiMC &app)
|
||||
mainWin.restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("MainWindowGeometry").toByteArray()));
|
||||
mainWin.show();
|
||||
mainWin.checkSetDefaultJava();
|
||||
return app.exec();
|
||||
auto exitCode = app.exec();
|
||||
|
||||
// Update if necessary.
|
||||
if (!app.getExitUpdatePath().isEmpty())
|
||||
app.installUpdates(app.getExitUpdatePath(), false);
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
25
MultiMC.h
25
MultiMC.h
@ -17,6 +17,7 @@ class IconList;
|
||||
class QNetworkAccessManager;
|
||||
class ForgeVersionList;
|
||||
class JavaVersionList;
|
||||
class UpdateChecker;
|
||||
|
||||
#if defined(MMC)
|
||||
#undef MMC
|
||||
@ -84,6 +85,11 @@ public:
|
||||
return m_metacache;
|
||||
}
|
||||
|
||||
std::shared_ptr<UpdateChecker> updateChecker()
|
||||
{
|
||||
return m_updateChecker;
|
||||
}
|
||||
|
||||
std::shared_ptr<LWJGLVersionList> lwjgllist();
|
||||
|
||||
std::shared_ptr<ForgeVersionList> forgelist();
|
||||
@ -92,6 +98,22 @@ public:
|
||||
|
||||
std::shared_ptr<JavaVersionList> javalist();
|
||||
|
||||
/*!
|
||||
* Installs update from the given update files directory.
|
||||
*/
|
||||
void installUpdates(const QString& updateFilesDir, bool restartOnFinish=false);
|
||||
|
||||
/*!
|
||||
* Sets MultiMC to install updates from the given directory when it exits.
|
||||
*/
|
||||
void setUpdateOnExit(const QString& updateFilesDir);
|
||||
|
||||
/*!
|
||||
* Gets the path to install updates from on exit.
|
||||
* If this is an empty string, no updates should be installed on exit.
|
||||
*/
|
||||
QString getExitUpdatePath() const;
|
||||
|
||||
private:
|
||||
void initLogger();
|
||||
|
||||
@ -106,6 +128,7 @@ private:
|
||||
std::shared_ptr<QTranslator> m_mmc_translator;
|
||||
std::shared_ptr<SettingsObject> m_settings;
|
||||
std::shared_ptr<InstanceList> m_instances;
|
||||
std::shared_ptr<UpdateChecker> m_updateChecker;
|
||||
std::shared_ptr<MojangAccountList> m_accounts;
|
||||
std::shared_ptr<IconList> m_icons;
|
||||
std::shared_ptr<QNetworkAccessManager> m_qnam;
|
||||
@ -117,6 +140,8 @@ private:
|
||||
QsLogging::DestinationPtr m_fileDestination;
|
||||
QsLogging::DestinationPtr m_debugDestination;
|
||||
|
||||
QString m_updateOnExitPath;
|
||||
|
||||
Status m_status = MultiMC::Failed;
|
||||
MultiMCVersion m_version;
|
||||
};
|
||||
|
@ -32,8 +32,9 @@ struct MultiMCVersion
|
||||
QString::number(major),
|
||||
QString::number(minor));
|
||||
|
||||
if (build > 0) vstr += QString(".%1").arg(QString::number(build));
|
||||
if (!buildType.isEmpty()) vstr += QString("-%1").arg(buildType);
|
||||
if (build >= 0) vstr += "." + QString::number(build);
|
||||
if (!channel.isEmpty()) vstr += "-" + channel;
|
||||
if (!buildType.isEmpty()) vstr += "-" + buildType;
|
||||
|
||||
return vstr;
|
||||
}
|
||||
@ -60,10 +61,14 @@ struct MultiMCVersion
|
||||
*/
|
||||
int build;
|
||||
|
||||
/*!
|
||||
* \brief This build's channel.
|
||||
*/
|
||||
QString channel;
|
||||
|
||||
/*!
|
||||
* \brief The build type.
|
||||
* This indicates the type of build that this is. For example, lin64-stable.
|
||||
* Usually corresponds to this build's buildbot builder name.
|
||||
* This indicates the type of build that this is. For example, lin64 or custombuild.
|
||||
*/
|
||||
QString buildType;
|
||||
};
|
||||
|
18
config.h.in
18
config.h.in
@ -1,16 +1,18 @@
|
||||
// Minor and major version, used to communicate changes to users.
|
||||
#define VERSION_MAJOR @MultiMC_VERSION_MAJOR@
|
||||
#define VERSION_MINOR @MultiMC_VERSION_MINOR@
|
||||
|
||||
// Build number, channel, and type -- number and channel are used by the updater, type is purely visual
|
||||
#define VERSION_BUILD @MultiMC_VERSION_BUILD@
|
||||
#define VERSION_CHANNEL "@MultiMC_VERSION_CHANNEL@"
|
||||
#define VERSION_BUILD_TYPE "@MultiMC_VERSION_BUILD_TYPE@"
|
||||
|
||||
#define GIT_COMMIT "@MultiMC_GIT_COMMIT@"
|
||||
// URL for the updater's channel
|
||||
#define CHANLIST_URL "@MultiMC_CHANLIST_URL@"
|
||||
|
||||
#define VERSION_STR "@MultiMC_VERSION_STRING@"
|
||||
// The commit hash of this build
|
||||
#define GIT_COMMIT "@MultiMC_GIT_COMMIT@"
|
||||
|
||||
#define x86 1
|
||||
#define x64 2
|
||||
|
||||
#define ARCH @MultiMC_ARCH@
|
||||
|
||||
#define USE_HTTPS @MultiMC_USE_HTTPS@
|
||||
// This is printed on start to standard output
|
||||
#define VERSION_STR "@MultiMC_VERSION_STRING@"
|
||||
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "gui/dialogs/CopyInstanceDialog.h"
|
||||
#include "gui/dialogs/AccountListDialog.h"
|
||||
#include "gui/dialogs/AccountSelectDialog.h"
|
||||
#include "gui/dialogs/UpdateDialog.h"
|
||||
#include "gui/dialogs/EditAccountDialog.h"
|
||||
|
||||
#include "gui/ConsoleWindow.h"
|
||||
@ -69,6 +70,12 @@
|
||||
#include "logic/lists/IconList.h"
|
||||
#include "logic/lists/JavaVersionList.h"
|
||||
|
||||
#include "logic/auth/flows/AuthenticateTask.h"
|
||||
#include "logic/auth/flows/RefreshTask.h"
|
||||
#include "logic/auth/flows/ValidateTask.h"
|
||||
|
||||
#include "logic/updater/DownloadUpdateTask.h"
|
||||
|
||||
#include "logic/BaseInstance.h"
|
||||
#include "logic/InstanceFactory.h"
|
||||
#include "logic/MinecraftProcess.h"
|
||||
@ -80,6 +87,8 @@
|
||||
|
||||
#include "logic/LegacyInstance.h"
|
||||
|
||||
#include <logic/updater/UpdateChecker.h>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
@ -232,6 +241,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
MMC->lwjgllist()->loadList();
|
||||
}
|
||||
|
||||
// set up the updater object.
|
||||
auto updater = MMC->updateChecker();
|
||||
QObject::connect(updater.get(), &UpdateChecker::updateAvailable, this, &MainWindow::updateAvailable);
|
||||
// if automatic update checks are allowed, start one.
|
||||
if(MMC->settings()->get("AutoUpdate").toBool())
|
||||
on_actionCheckUpdate_triggered();
|
||||
|
||||
assets_downloader = new OneSixAssets();
|
||||
connect(assets_downloader, SIGNAL(indexStarted()), SLOT(assetsIndexStarted()));
|
||||
connect(assets_downloader, SIGNAL(filesStarted()), SLOT(assetsFilesStarted()));
|
||||
@ -413,6 +429,41 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
|
||||
return QMainWindow::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void MainWindow::updateAvailable(QString repo, QString versionName, int versionId)
|
||||
{
|
||||
UpdateDialog dlg;
|
||||
UpdateAction action = (UpdateAction) dlg.exec();
|
||||
switch(action)
|
||||
{
|
||||
case UPDATE_LATER:
|
||||
QLOG_INFO() << "Update will be installed later.";
|
||||
break;
|
||||
case UPDATE_NOW:
|
||||
downloadUpdates(repo, versionId);
|
||||
break;
|
||||
case UPDATE_ONEXIT:
|
||||
downloadUpdates(repo, versionId, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::downloadUpdates(QString repo, int versionId, bool installOnExit)
|
||||
{
|
||||
QLOG_INFO() << "Downloading updates.";
|
||||
// TODO: If the user chooses to update on exit, we should download updates in the background.
|
||||
// Doing so is a bit complicated, because we'd have to make sure it finished downloading before actually exiting MultiMC.
|
||||
ProgressDialog updateDlg(this);
|
||||
DownloadUpdateTask updateTask(repo, versionId, &updateDlg);
|
||||
// If the task succeeds, install the updates.
|
||||
if (updateDlg.exec(&updateTask))
|
||||
{
|
||||
if (installOnExit)
|
||||
MMC->setUpdateOnExit(updateTask.updateFilesDir());
|
||||
else
|
||||
MMC->installUpdates(updateTask.updateFilesDir());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onCatToggled(bool state)
|
||||
{
|
||||
setCatBackground(state);
|
||||
@ -600,6 +651,8 @@ void MainWindow::on_actionConfig_Folder_triggered()
|
||||
|
||||
void MainWindow::on_actionCheckUpdate_triggered()
|
||||
{
|
||||
auto updater = MMC->updateChecker();
|
||||
updater->checkForUpdate();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSettings_triggered()
|
||||
|
@ -156,11 +156,18 @@ slots:
|
||||
|
||||
void startTask(Task *task);
|
||||
|
||||
void updateAvailable(QString repo, QString versionName, int versionId);
|
||||
|
||||
void activeAccountChanged();
|
||||
|
||||
void changeActiveAccount();
|
||||
|
||||
void repopulateAccountsMenu();
|
||||
|
||||
/*!
|
||||
* Runs the DownloadUpdateTask and installs updates.
|
||||
*/
|
||||
void downloadUpdates(QString repo, int versionId, bool installOnExit=false);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev);
|
||||
|
28
gui/dialogs/UpdateDialog.cpp
Normal file
28
gui/dialogs/UpdateDialog.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "UpdateDialog.h"
|
||||
#include "ui_UpdateDialog.h"
|
||||
#include "gui/Platform.h"
|
||||
|
||||
UpdateDialog::UpdateDialog(QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
UpdateDialog::~UpdateDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateDialog::on_btnUpdateLater_clicked()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
|
||||
void UpdateDialog::on_btnUpdateNow_clicked()
|
||||
{
|
||||
done(UPDATE_NOW);
|
||||
}
|
||||
|
||||
void UpdateDialog::on_btnUpdateOnExit_clicked()
|
||||
{
|
||||
done(UPDATE_ONEXIT);
|
||||
}
|
46
gui/dialogs/UpdateDialog.h
Normal file
46
gui/dialogs/UpdateDialog.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class UpdateDialog;
|
||||
}
|
||||
|
||||
enum UpdateAction
|
||||
{
|
||||
UPDATE_LATER = QDialog::Rejected,
|
||||
UPDATE_NOW = QDialog::Accepted,
|
||||
UPDATE_ONEXIT = 2
|
||||
};
|
||||
|
||||
class UpdateDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdateDialog(QWidget *parent = 0);
|
||||
~UpdateDialog();
|
||||
|
||||
private:
|
||||
Ui::UpdateDialog *ui;
|
||||
public slots:
|
||||
void on_btnUpdateNow_clicked();
|
||||
void on_btnUpdateOnExit_clicked();
|
||||
void on_btnUpdateLater_clicked();
|
||||
};
|
70
gui/dialogs/UpdateDialog.ui
Normal file
70
gui/dialogs/UpdateDialog.ui
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UpdateDialog</class>
|
||||
<widget class="QDialog" name="UpdateDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>260</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MultiMC Update</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../graphics.qrc">
|
||||
<normaloff>:/icons/toolbar/checkupdate</normaloff>:/icons/toolbar/checkupdate</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>A new MultiMC update is available!</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateNow">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update now</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateOnExit">
|
||||
<property name="text">
|
||||
<string>Update after MultiMC closes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateLater">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Don't update yet</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../graphics.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@ -63,6 +63,15 @@ void FileDownload::start()
|
||||
request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1());
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Uncached)");
|
||||
|
||||
// Go ahead and try to open the file.
|
||||
// If we don't do this, empty files won't be created, which breaks the updater.
|
||||
// Plus, this way, we don't end up starting a download for a file we can't open.
|
||||
if (!m_output_file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
emit failed(index_within_job);
|
||||
return;
|
||||
}
|
||||
|
||||
auto worker = MMC->qnam();
|
||||
QNetworkReply *rep = worker->get(request);
|
||||
|
||||
|
398
logic/updater/DownloadUpdateTask.cpp
Normal file
398
logic/updater/DownloadUpdateTask.cpp
Normal file
@ -0,0 +1,398 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "DownloadUpdateTask.h"
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "logic/updater/UpdateChecker.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "pathutils.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QTemporaryDir>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
|
||||
DownloadUpdateTask::DownloadUpdateTask(QString repoUrl, int versionId, QObject* parent) :
|
||||
Task(parent)
|
||||
{
|
||||
m_cVersionId = MMC->version().build;
|
||||
|
||||
m_nRepoUrl = repoUrl;
|
||||
m_nVersionId = versionId;
|
||||
|
||||
m_updateFilesDir.setAutoRemove(false);
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::executeTask()
|
||||
{
|
||||
// GO!
|
||||
// This will call the next step when it's done.
|
||||
findCurrentVersionInfo();
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::findCurrentVersionInfo()
|
||||
{
|
||||
setStatus(tr("Finding information about the current version."));
|
||||
|
||||
auto checker = MMC->updateChecker();
|
||||
|
||||
// This runs after we've tried loading the channel list.
|
||||
// If the channel list doesn't need to be loaded, this will be called immediately.
|
||||
// If the channel list does need to be loaded, this will be called when it's done.
|
||||
auto processFunc = [this, &checker] () -> void
|
||||
{
|
||||
// Now, check the channel list again.
|
||||
if (checker->hasChannels())
|
||||
{
|
||||
// We still couldn't load the channel list. Give up. Call loadVersionInfo and return.
|
||||
QLOG_INFO() << "Reloading the channel list didn't work. Giving up.";
|
||||
loadVersionInfo();
|
||||
return;
|
||||
}
|
||||
|
||||
QList<UpdateChecker::ChannelListEntry> channels = checker->getChannelList();
|
||||
QString channelId = MMC->version().channel;
|
||||
|
||||
// Search through the channel list for a channel with the correct ID.
|
||||
for (auto channel : channels)
|
||||
{
|
||||
if (channel.id == channelId)
|
||||
{
|
||||
QLOG_INFO() << "Found matching channel.";
|
||||
m_cRepoUrl = channel.url;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we've done that, load version info.
|
||||
loadVersionInfo();
|
||||
};
|
||||
|
||||
if (checker->hasChannels())
|
||||
{
|
||||
// Load the channel list and wait for it to finish loading.
|
||||
QLOG_INFO() << "No channel list entries found. Will try reloading it.";
|
||||
|
||||
QObject::connect(checker.get(), &UpdateChecker::channelListLoaded, processFunc);
|
||||
checker->updateChanList();
|
||||
}
|
||||
else
|
||||
{
|
||||
processFunc();
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::loadVersionInfo()
|
||||
{
|
||||
setStatus(tr("Loading version information."));
|
||||
|
||||
// Create the net job for loading version info.
|
||||
NetJob* netJob = new NetJob("Version Info");
|
||||
|
||||
// Find the index URL.
|
||||
QUrl newIndexUrl = QUrl(m_nRepoUrl).resolved(QString::number(m_nVersionId) + ".json");
|
||||
|
||||
// Add a net action to download the version info for the version we're updating to.
|
||||
netJob->addNetAction(ByteArrayDownload::make(newIndexUrl));
|
||||
|
||||
// If we have a current version URL, get that one too.
|
||||
if (!m_cRepoUrl.isEmpty())
|
||||
{
|
||||
QUrl cIndexUrl = QUrl(m_cRepoUrl).resolved(QString::number(m_cVersionId) + ".json");
|
||||
netJob->addNetAction(ByteArrayDownload::make(cIndexUrl));
|
||||
}
|
||||
|
||||
// Connect slots so we know when it's done.
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, &DownloadUpdateTask::vinfoDownloadFinished);
|
||||
QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::vinfoDownloadFailed);
|
||||
|
||||
// Store the NetJob in a class member. We don't want to lose it!
|
||||
m_vinfoNetJob.reset(netJob);
|
||||
|
||||
// Finally, we start the network job and the thread's event loop to wait for it to finish.
|
||||
netJob->start();
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::vinfoDownloadFinished()
|
||||
{
|
||||
// Both downloads succeeded. OK. Parse stuff.
|
||||
parseDownloadedVersionInfo();
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::vinfoDownloadFailed()
|
||||
{
|
||||
// Something failed. We really need the second download (current version info), so parse downloads anyways as long as the first one succeeded.
|
||||
if (m_vinfoNetJob->first()->m_status != Job_Failed)
|
||||
{
|
||||
parseDownloadedVersionInfo();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Give a more detailed error message.
|
||||
QLOG_ERROR() << "Failed to download version info files.";
|
||||
emitFailed(tr("Failed to download version info files."));
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::parseDownloadedVersionInfo()
|
||||
{
|
||||
setStatus(tr("Reading file lists."));
|
||||
|
||||
parseVersionInfo(NEW_VERSION, &m_nVersionFileList);
|
||||
|
||||
// If there is a second entry in the network job's list, load it as the current version's info.
|
||||
if (m_vinfoNetJob->size() >= 2 && m_vinfoNetJob->operator[](1)->m_status != Job_Failed)
|
||||
{
|
||||
parseVersionInfo(CURRENT_VERSION, &m_cVersionFileList);
|
||||
}
|
||||
|
||||
// We don't need this any more.
|
||||
m_vinfoNetJob.reset();
|
||||
|
||||
// Now that we're done loading version info, we can move on to the next step. Process file lists and download files.
|
||||
processFileLists();
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::parseVersionInfo(VersionInfoFileEnum vfile, VersionFileList* list)
|
||||
{
|
||||
if (vfile == CURRENT_VERSION) setStatus(tr("Reading file list for current version."));
|
||||
else if (vfile == NEW_VERSION) setStatus(tr("Reading file list for new version."));
|
||||
|
||||
QLOG_DEBUG() << "Reading file list for" << (vfile == NEW_VERSION ? "new" : "current") << "version.";
|
||||
|
||||
QByteArray data;
|
||||
{
|
||||
ByteArrayDownloadPtr dl = std::dynamic_pointer_cast<ByteArrayDownload>(
|
||||
vfile == NEW_VERSION ? m_vinfoNetJob->first() : m_vinfoNetJob->operator[](1));
|
||||
data = dl->m_data;
|
||||
}
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
QLOG_ERROR() << "Failed to parse version info JSON:" << jsonError.errorString() << "at" << jsonError.offset;
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject json = jsonDoc.object();
|
||||
|
||||
QLOG_DEBUG() << "Loading version info from JSON.";
|
||||
QJsonArray filesArray = json.value("Files").toArray();
|
||||
for (QJsonValue fileValue : filesArray)
|
||||
{
|
||||
QJsonObject fileObj = fileValue.toObject();
|
||||
|
||||
VersionFileEntry file{
|
||||
fileObj.value("Path").toString(),
|
||||
fileObj.value("Perms").toVariant().toInt(),
|
||||
FileSourceList(),
|
||||
fileObj.value("MD5").toString(),
|
||||
};
|
||||
QLOG_DEBUG() << "File" << file.path << "with perms" << file.mode;
|
||||
|
||||
QJsonArray sourceArray = fileObj.value("Sources").toArray();
|
||||
for (QJsonValue val : sourceArray)
|
||||
{
|
||||
QJsonObject sourceObj = val.toObject();
|
||||
|
||||
QString type = sourceObj.value("SourceType").toString();
|
||||
if (type == "http")
|
||||
{
|
||||
file.sources.append(FileSource("http", sourceObj.value("Url").toString()));
|
||||
}
|
||||
else if (type == "httpc")
|
||||
{
|
||||
file.sources.append(FileSource("httpc", sourceObj.value("Url").toString(), sourceObj.value("CompressionType").toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
QLOG_WARN() << "Unknown source type" << type << "ignored.";
|
||||
}
|
||||
}
|
||||
|
||||
QLOG_DEBUG() << "Loaded info for" << file.path;
|
||||
|
||||
list->append(file);
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::processFileLists()
|
||||
{
|
||||
setStatus(tr("Processing file lists. Figuring out how to install the update."));
|
||||
|
||||
// First, if we've loaded the current version's file list, we need to iterate through it and
|
||||
// delete anything in the current one version's list that isn't in the new version's list.
|
||||
for (VersionFileEntry entry : m_cVersionFileList)
|
||||
{
|
||||
for (VersionFileEntry newEntry : m_nVersionFileList)
|
||||
{
|
||||
if (newEntry.path == entry.path)
|
||||
continue;
|
||||
}
|
||||
// If the loop reaches the end, we didn't find a match. Delete the file.
|
||||
m_operationList.append(UpdateOperation::DeleteOp(entry.path));
|
||||
}
|
||||
|
||||
// Create a network job for downloading files.
|
||||
NetJob* netJob = new NetJob("Update Files");
|
||||
|
||||
// Next, check each file in MultiMC's folder and see if we need to update them.
|
||||
for (VersionFileEntry entry : m_nVersionFileList)
|
||||
{
|
||||
// TODO: Let's not MD5sum a ton of files on the GUI thread. We should probably find a way to do this in the background.
|
||||
QString fileMD5;
|
||||
QFile entryFile(entry.path);
|
||||
if (entryFile.open(QFile::ReadOnly))
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
hash.addData(entryFile.readAll());
|
||||
fileMD5 = hash.result().toHex();
|
||||
}
|
||||
|
||||
if (!entryFile.exists() || fileMD5.isEmpty() || fileMD5 != entry.md5)
|
||||
{
|
||||
QLOG_DEBUG() << "Found file" << entry.path << "that needs updating.";
|
||||
|
||||
// Go through the sources list and find one to use.
|
||||
// TODO: Make a NetAction that takes a source list and tries each of them until one works. For now, we'll just use the first http one.
|
||||
for (FileSource source : entry.sources)
|
||||
{
|
||||
if (source.type == "http")
|
||||
{
|
||||
QLOG_DEBUG() << "Will download" << entry.path << "from" << source.url;
|
||||
|
||||
// Download it to updatedir/<filepath>-<md5> where filepath is the file's path with slashes replaced by underscores.
|
||||
QString dlPath = PathCombine(m_updateFilesDir.path(), QString(entry.path).replace("/", "_"));
|
||||
|
||||
// We need to download the file to the updatefiles folder and add a task to copy it to its install path.
|
||||
FileDownloadPtr download = FileDownload::make(source.url, dlPath);
|
||||
download->m_check_md5 = true;
|
||||
download->m_expected_md5 = entry.md5;
|
||||
netJob->addNetAction(download);
|
||||
|
||||
// Now add a copy operation to our operations list to install the file.
|
||||
m_operationList.append(UpdateOperation::CopyOp(dlPath, entry.path, entry.mode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add listeners to wait for the downloads to finish.
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, &DownloadUpdateTask::fileDownloadFinished);
|
||||
QObject::connect(netJob, &NetJob::progress, this, &DownloadUpdateTask::fileDownloadProgressChanged);
|
||||
QObject::connect(netJob, &NetJob::failed, this, &DownloadUpdateTask::fileDownloadFailed);
|
||||
|
||||
// Now start the download.
|
||||
setStatus(tr("Downloading %1 update files.").arg(QString::number(netJob->size())));
|
||||
QLOG_DEBUG() << "Begin downloading update files to" << m_updateFilesDir.path();
|
||||
m_filesNetJob.reset(netJob);
|
||||
netJob->start();
|
||||
|
||||
writeInstallScript(m_operationList, PathCombine(m_updateFilesDir.path(), "file_list.xml"));
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::writeInstallScript(UpdateOperationList& opsList, QString scriptFile)
|
||||
{
|
||||
// Build the base structure of the XML document.
|
||||
QDomDocument doc;
|
||||
|
||||
QDomElement root = doc.createElement("update");
|
||||
root.setAttribute("version", "3");
|
||||
doc.appendChild(root);
|
||||
|
||||
QDomElement installFiles = doc.createElement("install");
|
||||
root.appendChild(installFiles);
|
||||
|
||||
QDomElement removeFiles = doc.createElement("uninstall");
|
||||
root.appendChild(removeFiles);
|
||||
|
||||
// Write the operation list to the XML document.
|
||||
for (UpdateOperation op : opsList)
|
||||
{
|
||||
QDomElement file = doc.createElement("file");
|
||||
|
||||
switch (op.type)
|
||||
{
|
||||
case UpdateOperation::OP_COPY:
|
||||
{
|
||||
// Install the file.
|
||||
QDomElement name = doc.createElement("source");
|
||||
QDomElement path = doc.createElement("dest");
|
||||
QDomElement mode = doc.createElement("mode");
|
||||
name.appendChild(doc.createTextNode(op.file));
|
||||
path.appendChild(doc.createTextNode(op.dest));
|
||||
// We need to add a 0 at the beginning here, because Qt doesn't convert to octal correctly.
|
||||
mode.appendChild(doc.createTextNode("0" + QString::number(op.mode, 8)));
|
||||
file.appendChild(name);
|
||||
file.appendChild(path);
|
||||
file.appendChild(mode);
|
||||
installFiles.appendChild(file);
|
||||
QLOG_DEBUG() << "Will install file" << op.file;
|
||||
}
|
||||
break;
|
||||
|
||||
case UpdateOperation::OP_DELETE:
|
||||
{
|
||||
// Delete the file.
|
||||
file.appendChild(doc.createTextNode(op.file));
|
||||
removeFiles.appendChild(file);
|
||||
QLOG_DEBUG() << "Will remove file" << op.file;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
QLOG_WARN() << "Can't write update operation of type" << op.type << "to file. Not implemented.";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the XML document to the file.
|
||||
QFile outFile(scriptFile);
|
||||
|
||||
if (outFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
outFile.write(doc.toByteArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
emitFailed(tr("Failed to write update script file."));
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::fileDownloadFinished()
|
||||
{
|
||||
emitSucceeded();
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::fileDownloadFailed()
|
||||
{
|
||||
// TODO: Give more info about the failure.
|
||||
QLOG_ERROR() << "Failed to download update files.";
|
||||
emitFailed(tr("Failed to download update files."));
|
||||
}
|
||||
|
||||
void DownloadUpdateTask::fileDownloadProgressChanged(qint64 current, qint64 total)
|
||||
{
|
||||
setProgress((int)(((float)current / (float)total)*100));
|
||||
}
|
||||
|
||||
QString DownloadUpdateTask::updateFilesDir()
|
||||
{
|
||||
return m_updateFilesDir.path();
|
||||
}
|
||||
|
192
logic/updater/DownloadUpdateTask.h
Normal file
192
logic/updater/DownloadUpdateTask.h
Normal file
@ -0,0 +1,192 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "logic/tasks/Task.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
|
||||
/*!
|
||||
* The DownloadUpdateTask is a task that takes a given version ID and repository URL,
|
||||
* downloads that version's files from the repository, and prepares to install them.
|
||||
*/
|
||||
class DownloadUpdateTask : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DownloadUpdateTask(QString repoUrl, int versionId, QObject* parent=0);
|
||||
|
||||
/*!
|
||||
* Gets the directory that contains the update files.
|
||||
*/
|
||||
QString updateFilesDir();
|
||||
|
||||
protected:
|
||||
// TODO: We should probably put these data structures into a separate header...
|
||||
|
||||
/*!
|
||||
* Struct that describes an entry in a VersionFileEntry's `Sources` list.
|
||||
*/
|
||||
struct FileSource
|
||||
{
|
||||
FileSource(QString type, QString url, QString compression="")
|
||||
{
|
||||
this->type = type;
|
||||
this->url = url;
|
||||
this->compressionType = compression;
|
||||
}
|
||||
|
||||
QString type;
|
||||
QString url;
|
||||
QString compressionType;
|
||||
};
|
||||
|
||||
typedef QList<FileSource> FileSourceList;
|
||||
|
||||
/*!
|
||||
* Structure that describes an entry in a GoUpdate version's `Files` list.
|
||||
*/
|
||||
struct VersionFileEntry
|
||||
{
|
||||
QString path;
|
||||
int mode;
|
||||
FileSourceList sources;
|
||||
QString md5;
|
||||
};
|
||||
|
||||
typedef QList<VersionFileEntry> VersionFileList;
|
||||
|
||||
|
||||
/*!
|
||||
* Structure that describes an operation to perform when installing updates.
|
||||
*/
|
||||
struct UpdateOperation
|
||||
{
|
||||
static UpdateOperation CopyOp(QString fsource, QString fdest, int fmode=0644) { return UpdateOperation{OP_COPY, fsource, fdest, fmode}; }
|
||||
static UpdateOperation MoveOp(QString fsource, QString fdest, int fmode=0644) { return UpdateOperation{OP_MOVE, fsource, fdest, fmode}; }
|
||||
static UpdateOperation DeleteOp(QString file) { return UpdateOperation{OP_DELETE, file, "", 0644}; }
|
||||
static UpdateOperation ChmodOp(QString file, int fmode) { return UpdateOperation{OP_CHMOD, file, "", fmode}; }
|
||||
|
||||
//! Specifies the type of operation that this is.
|
||||
enum Type
|
||||
{
|
||||
OP_COPY,
|
||||
OP_DELETE,
|
||||
OP_MOVE,
|
||||
OP_CHMOD,
|
||||
} type;
|
||||
|
||||
//! The file to operate on. If this is a DELETE or CHMOD operation, this is the file that will be modified.
|
||||
QString file;
|
||||
|
||||
//! The destination file. If this is a DELETE or CHMOD operation, this field will be ignored.
|
||||
QString dest;
|
||||
|
||||
//! The mode to change the source file to. Ignored if this isn't a CHMOD operation.
|
||||
int mode;
|
||||
|
||||
// Yeah yeah, polymorphism blah blah inheritance, blah blah object oriented. I'm lazy, OK?
|
||||
};
|
||||
|
||||
typedef QList<UpdateOperation> UpdateOperationList;
|
||||
|
||||
/*!
|
||||
* Used for arguments to parseVersionInfo and friends to specify which version info file to parse.
|
||||
*/
|
||||
enum VersionInfoFileEnum { NEW_VERSION, CURRENT_VERSION };
|
||||
|
||||
|
||||
//! Entry point for tasks.
|
||||
virtual void executeTask();
|
||||
|
||||
/*!
|
||||
* Attempts to find the version ID and repository URL for the current version.
|
||||
* The function will look up the repository URL in the UpdateChecker's channel list.
|
||||
* If the repository URL can't be found, this function will return false.
|
||||
*/
|
||||
virtual void findCurrentVersionInfo();
|
||||
|
||||
/*!
|
||||
* Downloads the version info files from the repository.
|
||||
* The files for both the current build, and the build that we're updating to need to be downloaded.
|
||||
* If the current version's info file can't be found, MultiMC will not delete files that
|
||||
* were removed between versions. It will still replace files that have changed, however.
|
||||
* Note that although the repository URL for the current version is not given to the update task,
|
||||
* the task will attempt to look it up in the UpdateChecker's channel list.
|
||||
* If an error occurs here, the function will call emitFailed and return false.
|
||||
*/
|
||||
virtual void loadVersionInfo();
|
||||
|
||||
/*!
|
||||
* This function is called when version information is finished downloading.
|
||||
* This handles parsing the JSON downloaded by the version info network job and then calls processFileLists.
|
||||
* Note that this function will sometimes be called even if the version info download emits failed. If
|
||||
* we couldn't download the current version's info file, we can still update. This will be called even if the
|
||||
* current version's info file fails to download, as long as the new version's info file succeeded.
|
||||
*/
|
||||
virtual void parseDownloadedVersionInfo();
|
||||
|
||||
/*!
|
||||
* Loads the file list from the given version info JSON object into the given list.
|
||||
*/
|
||||
virtual void parseVersionInfo(VersionInfoFileEnum vfile, VersionFileList* list);
|
||||
|
||||
/*!
|
||||
* Takes a list of file entries for the current version's files and the new version's files
|
||||
* and populates the downloadList and operationList with information about how to download and install the update.
|
||||
*/
|
||||
virtual void processFileLists();
|
||||
|
||||
/*!
|
||||
* Takes the operations list and writes an install script for the updater to the update files directory.
|
||||
*/
|
||||
virtual void writeInstallScript(UpdateOperationList& opsList, QString scriptFile);
|
||||
|
||||
VersionFileList m_downloadList;
|
||||
UpdateOperationList m_operationList;
|
||||
|
||||
VersionFileList m_nVersionFileList;
|
||||
VersionFileList m_cVersionFileList;
|
||||
|
||||
//! Network job for downloading version info files.
|
||||
NetJobPtr m_vinfoNetJob;
|
||||
|
||||
//! Network job for downloading update files.
|
||||
NetJobPtr m_filesNetJob;
|
||||
|
||||
// Version ID and repo URL for the new version.
|
||||
int m_nVersionId;
|
||||
QString m_nRepoUrl;
|
||||
|
||||
// Version ID and repo URL for the currently installed version.
|
||||
int m_cVersionId;
|
||||
QString m_cRepoUrl;
|
||||
|
||||
/*!
|
||||
* Temporary directory to store update files in.
|
||||
* This will be set to not auto delete. Task will fail if this fails to be created.
|
||||
*/
|
||||
QTemporaryDir m_updateFilesDir;
|
||||
|
||||
protected slots:
|
||||
void vinfoDownloadFinished();
|
||||
void vinfoDownloadFailed();
|
||||
|
||||
void fileDownloadFinished();
|
||||
void fileDownloadFailed();
|
||||
void fileDownloadProgressChanged(qint64 current, qint64 total);
|
||||
};
|
||||
|
247
logic/updater/UpdateChecker.cpp
Normal file
247
logic/updater/UpdateChecker.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "UpdateChecker.h"
|
||||
|
||||
#include "MultiMC.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "logger/QsLog.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
|
||||
#define API_VERSION 0
|
||||
#define CHANLIST_FORMAT 0
|
||||
|
||||
UpdateChecker::UpdateChecker()
|
||||
{
|
||||
m_currentChannel = VERSION_CHANNEL;
|
||||
m_channelListUrl = CHANLIST_URL;
|
||||
m_updateChecking = false;
|
||||
m_chanListLoading = false;
|
||||
m_checkUpdateWaiting = false;
|
||||
m_chanListLoaded = false;
|
||||
}
|
||||
|
||||
QList<UpdateChecker::ChannelListEntry> UpdateChecker::getChannelList() const
|
||||
{
|
||||
return m_channels;
|
||||
}
|
||||
|
||||
bool UpdateChecker::hasChannels() const
|
||||
{
|
||||
return m_channels.isEmpty();
|
||||
}
|
||||
|
||||
void UpdateChecker::checkForUpdate()
|
||||
{
|
||||
QLOG_DEBUG() << "Checking for updates.";
|
||||
|
||||
// If the channel list hasn't loaded yet, load it and defer checking for updates until later.
|
||||
if (!m_chanListLoaded)
|
||||
{
|
||||
QLOG_DEBUG() << "Channel list isn't loaded yet. Loading channel list and deferring update check.";
|
||||
m_checkUpdateWaiting = true;
|
||||
updateChanList();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_updateChecking)
|
||||
{
|
||||
QLOG_DEBUG() << "Ignoring update check request. Already checking for updates.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_updateChecking = true;
|
||||
|
||||
// Get the URL for the channel we're using.
|
||||
// TODO: Allow user to select channels. For now, we'll just use the current channel.
|
||||
QString updateChannel = m_currentChannel;
|
||||
|
||||
// Find the desired channel within the channel list and get its repo URL. If if cannot be found, error.
|
||||
m_repoUrl = "";
|
||||
for (ChannelListEntry entry : m_channels)
|
||||
{
|
||||
if (entry.id == updateChannel)
|
||||
m_repoUrl = entry.url;
|
||||
}
|
||||
|
||||
// If we didn't find our channel, error.
|
||||
if (m_repoUrl.isEmpty())
|
||||
{
|
||||
emit updateCheckFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl indexUrl = QUrl(m_repoUrl).resolved(QUrl("index.json"));
|
||||
|
||||
auto job = new NetJob("GoUpdate Repository Index");
|
||||
job->addNetAction(ByteArrayDownload::make(indexUrl));
|
||||
connect(job, SIGNAL(succeeded()), SLOT(updateCheckFinished()));
|
||||
connect(job, SIGNAL(failed()), SLOT(updateCheckFailed()));
|
||||
indexJob.reset(job);
|
||||
job->start();
|
||||
}
|
||||
|
||||
void UpdateChecker::updateCheckFinished()
|
||||
{
|
||||
QLOG_DEBUG() << "Finished downloading repo index. Checking for new versions.";
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QByteArray data;
|
||||
{
|
||||
ByteArrayDownloadPtr dl = std::dynamic_pointer_cast<ByteArrayDownload>(indexJob->first());
|
||||
data = dl->m_data;
|
||||
indexJob.reset();
|
||||
}
|
||||
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError || !jsonDoc.isObject())
|
||||
{
|
||||
QLOG_ERROR() << "Failed to parse GoUpdate repository index. JSON error" << jsonError.errorString() << "at offset" << jsonError.offset;
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject object = jsonDoc.object();
|
||||
|
||||
bool success = false;
|
||||
int apiVersion = object.value("ApiVersion").toVariant().toInt(&success);
|
||||
if (apiVersion != API_VERSION || !success)
|
||||
{
|
||||
QLOG_ERROR() << "Failed to check for updates. API version mismatch. We're using" << API_VERSION << "server has" << apiVersion;
|
||||
return;
|
||||
}
|
||||
|
||||
QLOG_DEBUG() << "Processing repository version list.";
|
||||
QJsonObject newestVersion;
|
||||
QJsonArray versions = object.value("Versions").toArray();
|
||||
for (QJsonValue versionVal : versions)
|
||||
{
|
||||
QJsonObject version = versionVal.toObject();
|
||||
if (newestVersion.value("Id").toVariant().toInt() < version.value("Id").toVariant().toInt())
|
||||
{
|
||||
QLOG_DEBUG() << "Found newer version with ID" << version.value("Id").toVariant().toInt();
|
||||
newestVersion = version;
|
||||
}
|
||||
}
|
||||
|
||||
// We've got the version with the greatest ID number. Now compare it to our current build number and update if they're different.
|
||||
int newBuildNumber = newestVersion.value("Id").toVariant().toInt();
|
||||
if (newBuildNumber != MMC->version().build)
|
||||
{
|
||||
// Update!
|
||||
emit updateAvailable(m_repoUrl, newestVersion.value("Name").toVariant().toString(), newBuildNumber);
|
||||
}
|
||||
|
||||
m_updateChecking = false;
|
||||
}
|
||||
|
||||
void UpdateChecker::updateCheckFailed()
|
||||
{
|
||||
// TODO: log errors better
|
||||
QLOG_ERROR() << "Update check failed for reasons unknown.";
|
||||
}
|
||||
|
||||
void UpdateChecker::updateChanList()
|
||||
{
|
||||
QLOG_DEBUG() << "Loading the channel list.";
|
||||
|
||||
if (m_channelListUrl.isEmpty())
|
||||
{
|
||||
QLOG_ERROR() << "Failed to update channel list. No channel list URL set."
|
||||
<< "If you'd like to use MultiMC's update system, please pass the channel list URL to CMake at compile time.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_chanListLoading = true;
|
||||
NetJob* job = new NetJob("Update System Channel List");
|
||||
job->addNetAction(ByteArrayDownload::make(QUrl(m_channelListUrl)));
|
||||
QObject::connect(job, &NetJob::succeeded, this, &UpdateChecker::chanListDownloadFinished);
|
||||
QObject::connect(job, &NetJob::failed, this, &UpdateChecker::chanListDownloadFailed);
|
||||
chanListJob.reset(job);
|
||||
job->start();
|
||||
}
|
||||
|
||||
void UpdateChecker::chanListDownloadFinished()
|
||||
{
|
||||
QByteArray data;
|
||||
{
|
||||
ByteArrayDownloadPtr dl = std::dynamic_pointer_cast<ByteArrayDownload>(chanListJob->first());
|
||||
data = dl->m_data;
|
||||
chanListJob.reset();
|
||||
}
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
// TODO: Report errors to the user.
|
||||
QLOG_ERROR() << "Failed to parse channel list JSON:" << jsonError.errorString() << "at" << jsonError.offset;
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject object = jsonDoc.object();
|
||||
|
||||
bool success = false;
|
||||
int formatVersion = object.value("format_version").toVariant().toInt(&success);
|
||||
if (formatVersion != CHANLIST_FORMAT || !success)
|
||||
{
|
||||
QLOG_ERROR() << "Failed to check for updates. Channel list format version mismatch. We're using" << CHANLIST_FORMAT << "server has" << formatVersion;
|
||||
return;
|
||||
}
|
||||
|
||||
// Load channels into a temporary array.
|
||||
QList<ChannelListEntry> loadedChannels;
|
||||
QJsonArray channelArray = object.value("channels").toArray();
|
||||
for (QJsonValue chanVal : channelArray)
|
||||
{
|
||||
QJsonObject channelObj = chanVal.toObject();
|
||||
ChannelListEntry entry{
|
||||
channelObj.value("id").toVariant().toString(),
|
||||
channelObj.value("name").toVariant().toString(),
|
||||
channelObj.value("description").toVariant().toString(),
|
||||
channelObj.value("url").toVariant().toString()
|
||||
};
|
||||
if (entry.id.isEmpty() || entry.name.isEmpty() || entry.url.isEmpty())
|
||||
{
|
||||
QLOG_ERROR() << "Channel list entry with empty ID, name, or URL. Skipping.";
|
||||
continue;
|
||||
}
|
||||
loadedChannels.append(entry);
|
||||
}
|
||||
|
||||
// Swap the channel list we just loaded into the object's channel list.
|
||||
m_channels.swap(loadedChannels);
|
||||
|
||||
m_chanListLoading = false;
|
||||
m_chanListLoaded = true;
|
||||
QLOG_INFO() << "Successfully loaded UpdateChecker channel list.";
|
||||
|
||||
// If we're waiting to check for updates, do that now.
|
||||
if (m_checkUpdateWaiting)
|
||||
checkForUpdate();
|
||||
|
||||
emit channelListLoaded();
|
||||
}
|
||||
|
||||
void UpdateChecker::chanListDownloadFailed()
|
||||
{
|
||||
m_chanListLoading = false;
|
||||
QLOG_ERROR() << "Failed to download channel list.";
|
||||
emit channelListLoaded();
|
||||
}
|
||||
|
106
logic/updater/UpdateChecker.h
Normal file
106
logic/updater/UpdateChecker.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "logic/net/NetJob.h"
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
class UpdateChecker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UpdateChecker();
|
||||
void checkForUpdate();
|
||||
|
||||
/*!
|
||||
* Causes the update checker to download the channel list from the URL specified in config.h (generated by CMake).
|
||||
* If this isn't called before checkForUpdate(), it will automatically be called.
|
||||
*/
|
||||
void updateChanList();
|
||||
|
||||
/*!
|
||||
* An entry in the channel list.
|
||||
*/
|
||||
struct ChannelListEntry
|
||||
{
|
||||
QString id;
|
||||
QString name;
|
||||
QString description;
|
||||
QString url;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Returns a the current channel list.
|
||||
* If the channel list hasn't been loaded, this list will be empty.
|
||||
*/
|
||||
QList<ChannelListEntry> getChannelList() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the channel list is empty.
|
||||
*/
|
||||
bool hasChannels() const;
|
||||
|
||||
signals:
|
||||
//! Signal emitted when an update is available. Passes the URL for the repo and the ID and name for the version.
|
||||
void updateAvailable(QString repoUrl, QString versionName, int versionId);
|
||||
|
||||
//! Signal emitted when the channel list finishes loading or fails to load.
|
||||
void channelListLoaded();
|
||||
|
||||
private slots:
|
||||
void updateCheckFinished();
|
||||
void updateCheckFailed();
|
||||
|
||||
void chanListDownloadFinished();
|
||||
void chanListDownloadFailed();
|
||||
|
||||
private:
|
||||
NetJobPtr indexJob;
|
||||
NetJobPtr chanListJob;
|
||||
|
||||
QString m_repoUrl;
|
||||
|
||||
QString m_channelListUrl;
|
||||
QString m_currentChannel;
|
||||
|
||||
QList<ChannelListEntry> m_channels;
|
||||
|
||||
/*!
|
||||
* True while the system is checking for updates.
|
||||
* If checkForUpdate is called while this is true, it will be ignored.
|
||||
*/
|
||||
bool m_updateChecking;
|
||||
|
||||
/*!
|
||||
* True if the channel list has loaded.
|
||||
* If this is false, trying to check for updates will call updateChanList first.
|
||||
*/
|
||||
bool m_chanListLoaded;
|
||||
|
||||
/*!
|
||||
* Set to true while the channel list is currently loading.
|
||||
*/
|
||||
bool m_chanListLoading;
|
||||
|
||||
/*!
|
||||
* Set to true when checkForUpdate is called while the channel list isn't loaded.
|
||||
* When the channel list finishes loading, if this is true, the update checker will check for updates.
|
||||
*/
|
||||
bool m_checkUpdateWaiting;
|
||||
};
|
||||
|
44
mmc_updater/CMakeLists.txt
Normal file
44
mmc_updater/CMakeLists.txt
Normal file
@ -0,0 +1,44 @@
|
||||
project(updater)
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
enable_testing()
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
include_directories(depends)
|
||||
|
||||
if (WIN32)
|
||||
include_directories(depends/win32cpp)
|
||||
|
||||
if(MSVC)
|
||||
# - Link the updater binary statically with the Visual C++ runtime
|
||||
# so that the executable can function standalone.
|
||||
# - Enable PDB generation for release builds
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "/MT")
|
||||
set(CMAKE_C_FLAGS_DEBUG "/MT")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/MT /Zi /O2 /Ob2 /D NDEBUG")
|
||||
set(CMAKE_C_FLAGS_RELEASE "/MT /Zi /O2 /Ob2 /D NDEBUG")
|
||||
remove_definitions(-DUNICODE -D_UNICODE)
|
||||
endif()
|
||||
else()
|
||||
# optimize for reduced code size
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-Os")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-Os")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
# Build the updater as a dual 32/64bit binary. If only one architecture
|
||||
# is required, removing the other architecture will reduce the size
|
||||
# of the updater binary
|
||||
set(CMAKE_OSX_ARCHITECTURES i386;x86_64)
|
||||
|
||||
# Build the updater so that it works on OS X 10.5 and above.
|
||||
set(MIN_OSX_VERSION 10.5)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=${MIN_OSX_VERSION}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=${MIN_OSX_VERSION}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(depends/AnyOption)
|
||||
add_subdirectory(depends/tinyxml)
|
||||
|
19
mmc_updater/LICENSE
Normal file
19
mmc_updater/LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
This project is licensed under a BSD license.
|
||||
|
||||
The Mendeley Desktop icon graphics and name are trademarks of Mendeley Ltd.
|
||||
and must be removed or replaced - see src/AppInfo.cpp and the files
|
||||
in src/resources.
|
||||
|
||||
===
|
||||
|
||||
Copyright (c) 2011, Mendeley Ltd.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
138
mmc_updater/README.md
Normal file
138
mmc_updater/README.md
Normal file
@ -0,0 +1,138 @@
|
||||
This tool is a component of a cross-platform auto-update system.
|
||||
It is responsible for performing the installation of an update after
|
||||
the necessary files have been downloaded to a temporary directory.
|
||||
|
||||
It was originally written for use with Mendeley Desktop (see www.mendeley.com)
|
||||
|
||||
The tool consists of a single small binary which performs update installation,
|
||||
an XML file format describing the contents of an update (an 'update script')
|
||||
and a tool to create update scripts from a directory containing an installed application.
|
||||
|
||||
To perform an update, the application (or another separate tool) needs to download
|
||||
the updater binary, an update script and one or more compressed packages
|
||||
containing the files for the update to a temporary directory. It then needs
|
||||
to invoke the updater, specifying the location where the application is installed,
|
||||
the location of the compressed packages and the path to the update script.
|
||||
|
||||
Once the updater has been started, it:
|
||||
|
||||
1. Waits for the application to exit
|
||||
2. Acquires the necessary priviledges to install the updates, prompting
|
||||
the user if necessary.
|
||||
3. Installs the updates, displaying progress to the user in a small dialog
|
||||
4. Performs cleanup and any additional actions required as part of the update
|
||||
5. Starts the new version of the main application.
|
||||
|
||||
In the event of a failure during the update, the installation is rolled back
|
||||
to its previous state and a message is presented to the user.
|
||||
|
||||
## Building the Updater
|
||||
|
||||
Create a new directory for the build and from that directory run:
|
||||
|
||||
cmake <path to source directory>
|
||||
make
|
||||
|
||||
The updater binary will be built in the src/ directory.
|
||||
|
||||
You should also run the tests in src/tests to verify that the updater is
|
||||
functioning correctly.
|
||||
|
||||
## Preparing an Update
|
||||
|
||||
1. Create a directory containing your application's files,
|
||||
laid out in the same way and with the same permissions as they would be when installed.
|
||||
2. Create a config file specifying how the application's files should be
|
||||
partitioned into packages - see tools/config-template.json
|
||||
3. Use the tools/create-packages.rb script to create a file_list.xml file
|
||||
and a set of package files required for updates.
|
||||
4. Upload the file_list.xml file and packages to a server
|
||||
|
||||
After step 4 is done, you need to notify existing installs that an update
|
||||
is available. The installed application then needs to download the
|
||||
relevant packages, file_list.xml file and updater binary to a temporary
|
||||
directory and invoke the updater.
|
||||
|
||||
See doc/update-hosting for more details on hosting and delivering the updates.
|
||||
|
||||
## Invoking the Updater
|
||||
|
||||
Once the application has downloaded an update, it needs to invoke it. The syntax is:
|
||||
|
||||
updater --install-dir <install-dir> --package-dir <package-dir> --script <script file>
|
||||
|
||||
Where `<install-dir>` is the directory which the application is installed into,
|
||||
`<package-dir>` is the directory containing the packages required for the update
|
||||
and `<script>` is the `file_list.xml` file describing the update.
|
||||
|
||||
Once the updater has run, it will launch the file specified in the `file_list.xml` file
|
||||
as being the main application binary.
|
||||
|
||||
See the updater test in `src/tests/test-update.rb` for an example
|
||||
of how to invoke the updater.
|
||||
|
||||
You should design the process used to download and launch the updater so that new
|
||||
versions of the updater itself can be delivered as part of the update if necessary.
|
||||
|
||||
## Customizing the Updater
|
||||
|
||||
To customize the application name, organization and messages displayed by the updater:
|
||||
|
||||
1. Edit the AppInfo class (in AppInfo.h, AppInfo.cpp) to set the name
|
||||
of the application and associated organization.
|
||||
2. Replace the icons in src/resources
|
||||
3. Change the product name and organization in src/resources/updater.rc
|
||||
4. If you are building the updater on Windows and have a suitable Authenticode
|
||||
certificate, use it to sign the Windows binary. This will make the application
|
||||
show a less scary UAC prompt if administrator permissions are required
|
||||
to complete the installation.
|
||||
|
||||
## Updater Dependencies
|
||||
|
||||
The external dependencies of the updater binary are:
|
||||
|
||||
* The C/C++ runtime libraries (Linux, Mac),
|
||||
* pthreads (Linux, Mac),
|
||||
* zlib (Linux, Mac)
|
||||
* native UI library (Win32 API on Windows, Cocoa on Mac, GTK on Linux if available)
|
||||
|
||||
## Full and Delta Updates
|
||||
|
||||
The simplest auto-update implementation is for existing installs
|
||||
to download a complete copy of the new version and install it. This is
|
||||
appropriate if a full download and install will not take a long time for most users
|
||||
(eg. if the application is small or they have a fast internet connection).
|
||||
|
||||
With this tool, a full-update involves putting all files in a build of
|
||||
the application into a single package.
|
||||
|
||||
To reduce the download size, delta updates can be created which only include
|
||||
the necessary files or components to update from the old to the new version.
|
||||
|
||||
The file_list.xml file format can be used to represent either a complete
|
||||
install - in which every file that makes up the application is included,
|
||||
or a delta update - in which case only new or updated files and packages
|
||||
are included.
|
||||
|
||||
There are several ways in which this can be done:
|
||||
|
||||
* Pre-computed Delta Updates
|
||||
For each release, create a full update plus delta updates from the
|
||||
previous N releases. Users of recent releases will receive a small
|
||||
delta update. Users of older releases will receive the full update.
|
||||
|
||||
* Server-computed Delta Updates
|
||||
The server receives a request for an update from client version X and in response,
|
||||
computes an update from version X to the current version Y, possibly
|
||||
caching that information for future use. The client then receives the
|
||||
delta file_list.xml file and downloads only the listed packages.
|
||||
|
||||
Applications such as Chrome and Firefox use a mixture of the above methods.
|
||||
|
||||
* Client-computed Delta Updates
|
||||
The client downloads the file_list.xml file for the latest version and
|
||||
computes a delta update file locally. It then downloads only the required
|
||||
packages and invokes the updater, which installs only the changed or updated
|
||||
files from those packages.
|
||||
|
||||
This is similar to Linux package management systems.
|
23
mmc_updater/cmake/modules/GenerateCppResourceFile.cmake
Normal file
23
mmc_updater/cmake/modules/GenerateCppResourceFile.cmake
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
# Convert a binary data file into a C++
|
||||
# source file for embedding into an application binary
|
||||
#
|
||||
# Currently only implemented for Unix. Requires the 'xxd'
|
||||
# tool to be installed.
|
||||
#
|
||||
# TARGET_NAME : The name of the target to generate
|
||||
#
|
||||
# INPUT_DIR : The directory containing the input binary data file
|
||||
#
|
||||
# INPUT_FILE : The name of the binary data file in ${INPUT_DIR} to be converted into a C++
|
||||
# source file. The name of the input file will be used as the basis for the
|
||||
# symbols in the generated C++ file referring to the data buffer and its length.
|
||||
#
|
||||
# CPP_FILE : The path of the C++ source file to be generated.
|
||||
# See the documentation for xxd for information on
|
||||
# the structure of the generated source file.
|
||||
#
|
||||
function (generate_cpp_resource_file TARGET_NAME INPUT_FILE CPP_FILE)
|
||||
add_custom_command(OUTPUT ${CPP_FILE} COMMAND cd `dirname ${INPUT_FILE}` && xxd -i `basename ${INPUT_FILE}` ${CPP_FILE} DEPENDS ${INPUT_FILE})
|
||||
add_custom_target(${TARGET_NAME} ALL DEPENDS ${CPP_FILE})
|
||||
endfunction()
|
9
mmc_updater/depends/AnyOption/CMakeLists.txt
Normal file
9
mmc_updater/depends/AnyOption/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
project(AnyOption)
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
add_library(anyoption
|
||||
anyoption.cpp
|
||||
anyoption.h
|
||||
)
|
||||
|
16
mmc_updater/depends/AnyOption/README
Normal file
16
mmc_updater/depends/AnyOption/README
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
http://www.hackorama.com/anyoption/
|
||||
|
||||
AnyOption is a C++ class for easy parsing of complex commandline options. It also parses options from a rsourcefile in option value pair format.
|
||||
|
||||
AnyOption implements the traditional POSIX style character options ( -n ) as well as the newer GNU style long options ( --name ). Or you can use a simpler long option version ( -name ) by asking to ignore the POSIX style options.
|
||||
|
||||
AnyOption supports the traditional UNIX resourcefile syntax of, any line starting with "#" is a comment and the value pairs use ":" as a delimiter.
|
||||
|
||||
An option which expects a value is considered as an option value pair, while options without a value are considered flags.
|
||||
|
||||
Please read the header file for the documented public interface, and demo.cpp for an example of how easy it is to use AnyOption.
|
||||
|
||||
August 2004, added bug-fixes, and updates send by Michael Peters of Sandia Lab.
|
||||
September 2006, fix from Boyan Asenov for a bug in mixing up option type indexes.
|
||||
July 2011, fix from Min KJ and Costantino G for string allocation.
|
1176
mmc_updater/depends/AnyOption/anyoption.cpp
Normal file
1176
mmc_updater/depends/AnyOption/anyoption.cpp
Normal file
File diff suppressed because it is too large
Load Diff
270
mmc_updater/depends/AnyOption/anyoption.h
Normal file
270
mmc_updater/depends/AnyOption/anyoption.h
Normal file
@ -0,0 +1,270 @@
|
||||
#ifndef _ANYOPTION_H
|
||||
#define _ANYOPTION_H
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
#define COMMON_OPT 1
|
||||
#define COMMAND_OPT 2
|
||||
#define FILE_OPT 3
|
||||
#define COMMON_FLAG 4
|
||||
#define COMMAND_FLAG 5
|
||||
#define FILE_FLAG 6
|
||||
|
||||
#define COMMAND_OPTION_TYPE 1
|
||||
#define COMMAND_FLAG_TYPE 2
|
||||
#define FILE_OPTION_TYPE 3
|
||||
#define FILE_FLAG_TYPE 4
|
||||
#define UNKNOWN_TYPE 5
|
||||
|
||||
#define DEFAULT_MAXOPTS 10
|
||||
#define MAX_LONG_PREFIX_LENGTH 2
|
||||
|
||||
#define DEFAULT_MAXUSAGE 3
|
||||
#define DEFAULT_MAXHELP 10
|
||||
|
||||
#define TRUE_FLAG "true"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class AnyOption
|
||||
{
|
||||
|
||||
public: /* the public interface */
|
||||
AnyOption();
|
||||
AnyOption(int maxoptions );
|
||||
AnyOption(int maxoptions , int maxcharoptions);
|
||||
~AnyOption();
|
||||
|
||||
/*
|
||||
* following set methods specifies the
|
||||
* special characters and delimiters
|
||||
* if not set traditional defaults will be used
|
||||
*/
|
||||
|
||||
void setCommandPrefixChar( char _prefix ); /* '-' in "-w" */
|
||||
void setCommandLongPrefix( char *_prefix ); /* '--' in "--width" */
|
||||
void setFileCommentChar( char _comment ); /* '#' in shellscripts */
|
||||
void setFileDelimiterChar( char _delimiter );/* ':' in "width : 100" */
|
||||
|
||||
/*
|
||||
* provide the input for the options
|
||||
* like argv[] for commndline and the
|
||||
* option file name to use;
|
||||
*/
|
||||
|
||||
void useCommandArgs( int _argc, char **_argv );
|
||||
void useFiileName( const char *_filename );
|
||||
|
||||
/*
|
||||
* turn off the POSIX style options
|
||||
* this means anything starting with a '-' or "--"
|
||||
* will be considered a valid option
|
||||
* which alo means you cannot add a bunch of
|
||||
* POIX options chars together like "-lr" for "-l -r"
|
||||
*
|
||||
*/
|
||||
|
||||
void noPOSIX();
|
||||
|
||||
/*
|
||||
* prints warning verbose if you set anything wrong
|
||||
*/
|
||||
void setVerbose();
|
||||
|
||||
|
||||
/*
|
||||
* there are two types of options
|
||||
*
|
||||
* Option - has an associated value ( -w 100 )
|
||||
* Flag - no value, just a boolean flag ( -nogui )
|
||||
*
|
||||
* the options can be either a string ( GNU style )
|
||||
* or a character ( traditional POSIX style )
|
||||
* or both ( --width, -w )
|
||||
*
|
||||
* the options can be common to the commandline and
|
||||
* the optionfile, or can belong only to either of
|
||||
* commandline and optionfile
|
||||
*
|
||||
* following set methods, handle all the aboove
|
||||
* cases of options.
|
||||
*/
|
||||
|
||||
/* options comman to command line and option file */
|
||||
void setOption( const char *opt_string );
|
||||
void setOption( char opt_char );
|
||||
void setOption( const char *opt_string , char opt_char );
|
||||
void setFlag( const char *opt_string );
|
||||
void setFlag( char opt_char );
|
||||
void setFlag( const char *opt_string , char opt_char );
|
||||
|
||||
/* options read from commandline only */
|
||||
void setCommandOption( const char *opt_string );
|
||||
void setCommandOption( char opt_char );
|
||||
void setCommandOption( const char *opt_string , char opt_char );
|
||||
void setCommandFlag( const char *opt_string );
|
||||
void setCommandFlag( char opt_char );
|
||||
void setCommandFlag( const char *opt_string , char opt_char );
|
||||
|
||||
/* options read from an option file only */
|
||||
void setFileOption( const char *opt_string );
|
||||
void setFileOption( char opt_char );
|
||||
void setFileOption( const char *opt_string , char opt_char );
|
||||
void setFileFlag( const char *opt_string );
|
||||
void setFileFlag( char opt_char );
|
||||
void setFileFlag( const char *opt_string , char opt_char );
|
||||
|
||||
/*
|
||||
* process the options, registerd using
|
||||
* useCommandArgs() and useFileName();
|
||||
*/
|
||||
void processOptions();
|
||||
void processCommandArgs();
|
||||
void processCommandArgs( int max_args );
|
||||
bool processFile();
|
||||
|
||||
/*
|
||||
* process the specified options
|
||||
*/
|
||||
void processCommandArgs( int _argc, char **_argv );
|
||||
void processCommandArgs( int _argc, char **_argv, int max_args );
|
||||
bool processFile( const char *_filename );
|
||||
|
||||
/*
|
||||
* get the value of the options
|
||||
* will return NULL if no value is set
|
||||
*/
|
||||
char *getValue( const char *_option );
|
||||
bool getFlag( const char *_option );
|
||||
char *getValue( char _optchar );
|
||||
bool getFlag( char _optchar );
|
||||
|
||||
/*
|
||||
* Print Usage
|
||||
*/
|
||||
void printUsage();
|
||||
void printAutoUsage();
|
||||
void addUsage( const char *line );
|
||||
void printHelp();
|
||||
/* print auto usage printing for unknown options or flag */
|
||||
void autoUsagePrint(bool flag);
|
||||
|
||||
/*
|
||||
* get the argument count and arguments sans the options
|
||||
*/
|
||||
int getArgc();
|
||||
char* getArgv( int index );
|
||||
bool hasOptions();
|
||||
|
||||
private: /* the hidden data structure */
|
||||
int argc; /* commandline arg count */
|
||||
char **argv; /* commndline args */
|
||||
const char* filename; /* the option file */
|
||||
char* appname; /* the application name from argv[0] */
|
||||
|
||||
int *new_argv; /* arguments sans options (index to argv) */
|
||||
int new_argc; /* argument count sans the options */
|
||||
int max_legal_args; /* ignore extra arguments */
|
||||
|
||||
|
||||
/* option strings storage + indexing */
|
||||
int max_options; /* maximum number of options */
|
||||
const char **options; /* storage */
|
||||
int *optiontype; /* type - common, command, file */
|
||||
int *optionindex; /* index into value storage */
|
||||
int option_counter; /* counter for added options */
|
||||
|
||||
/* option chars storage + indexing */
|
||||
int max_char_options; /* maximum number options */
|
||||
char *optionchars; /* storage */
|
||||
int *optchartype; /* type - common, command, file */
|
||||
int *optcharindex; /* index into value storage */
|
||||
int optchar_counter; /* counter for added options */
|
||||
|
||||
/* values */
|
||||
char **values; /* common value storage */
|
||||
int g_value_counter; /* globally updated value index LAME! */
|
||||
|
||||
/* help and usage */
|
||||
const char **usage; /* usage */
|
||||
int max_usage_lines; /* max usage lines reseverd */
|
||||
int usage_lines; /* number of usage lines */
|
||||
|
||||
bool command_set; /* if argc/argv were provided */
|
||||
bool file_set; /* if a filename was provided */
|
||||
bool mem_allocated; /* if memory allocated in init() */
|
||||
bool posix_style; /* enables to turn off POSIX style options */
|
||||
bool verbose; /* silent|verbose */
|
||||
bool print_usage; /* usage verbose */
|
||||
bool print_help; /* help verbose */
|
||||
|
||||
char opt_prefix_char; /* '-' in "-w" */
|
||||
char long_opt_prefix[MAX_LONG_PREFIX_LENGTH + 1]; /* '--' in "--width" */
|
||||
char file_delimiter_char; /* ':' in width : 100 */
|
||||
char file_comment_char; /* '#' in "#this is a comment" */
|
||||
char equalsign;
|
||||
char comment;
|
||||
char delimiter;
|
||||
char endofline;
|
||||
char whitespace;
|
||||
char nullterminate;
|
||||
|
||||
bool set; //was static member
|
||||
bool once; //was static member
|
||||
|
||||
bool hasoptions;
|
||||
bool autousage;
|
||||
|
||||
private: /* the hidden utils */
|
||||
void init();
|
||||
void init(int maxopt, int maxcharopt );
|
||||
bool alloc();
|
||||
void cleanup();
|
||||
bool valueStoreOK();
|
||||
|
||||
/* grow storage arrays as required */
|
||||
bool doubleOptStorage();
|
||||
bool doubleCharStorage();
|
||||
bool doubleUsageStorage();
|
||||
|
||||
bool setValue( const char *option , char *value );
|
||||
bool setFlagOn( const char *option );
|
||||
bool setValue( char optchar , char *value);
|
||||
bool setFlagOn( char optchar );
|
||||
|
||||
void addOption( const char* option , int type );
|
||||
void addOption( char optchar , int type );
|
||||
void addOptionError( const char *opt);
|
||||
void addOptionError( char opt);
|
||||
bool findFlag( char* value );
|
||||
void addUsageError( const char *line );
|
||||
bool CommandSet();
|
||||
bool FileSet();
|
||||
bool POSIX();
|
||||
|
||||
char parsePOSIX( char* arg );
|
||||
int parseGNU( char *arg );
|
||||
bool matchChar( char c );
|
||||
int matchOpt( char *opt );
|
||||
|
||||
/* dot file methods */
|
||||
char *readFile();
|
||||
char *readFile( const char* fname );
|
||||
bool consumeFile( char *buffer );
|
||||
void processLine( char *theline, int length );
|
||||
char *chomp( char *str );
|
||||
void valuePairs( char *type, char *value );
|
||||
void justValue( char *value );
|
||||
|
||||
void printVerbose( const char *msg );
|
||||
void printVerbose( char *msg );
|
||||
void printVerbose( char ch );
|
||||
void printVerbose( );
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* ! _ANYOPTION_H */
|
24
mmc_updater/depends/tinyxml/CMakeLists.txt
Normal file
24
mmc_updater/depends/tinyxml/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
# TinyXML 1.0.1
|
||||
project(tinyxml)
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
Add_definitions(-DTIXML_USE_STL)
|
||||
|
||||
set(SOURCES
|
||||
tinystr.cpp
|
||||
tinyxml.cpp
|
||||
tinyxmlerror.cpp
|
||||
tinyxmlparser.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
tinystr.h
|
||||
tinyxml.h
|
||||
)
|
||||
|
||||
add_library(tinyxml
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
)
|
||||
|
530
mmc_updater/depends/tinyxml/readme.txt
Normal file
530
mmc_updater/depends/tinyxml/readme.txt
Normal file
@ -0,0 +1,530 @@
|
||||
/** @mainpage
|
||||
|
||||
<h1> TinyXML </h1>
|
||||
|
||||
TinyXML is a simple, small, C++ XML parser that can be easily
|
||||
integrated into other programs.
|
||||
|
||||
<h2> What it does. </h2>
|
||||
|
||||
In brief, TinyXML parses an XML document, and builds from that a
|
||||
Document Object Model (DOM) that can be read, modified, and saved.
|
||||
|
||||
XML stands for "eXtensible Markup Language." It allows you to create
|
||||
your own document markups. Where HTML does a very good job of marking
|
||||
documents for browsers, XML allows you to define any kind of document
|
||||
markup, for example a document that describes a "to do" list for an
|
||||
organizer application. XML is a very structured and convenient format.
|
||||
All those random file formats created to store application data can
|
||||
all be replaced with XML. One parser for everything.
|
||||
|
||||
The best place for the complete, correct, and quite frankly hard to
|
||||
read spec is at <a href="http://www.w3.org/TR/2004/REC-xml-20040204/">
|
||||
http://www.w3.org/TR/2004/REC-xml-20040204/</a>. An intro to XML
|
||||
(that I really like) can be found at
|
||||
<a href="http://skew.org/xml/tutorial/">http://skew.org/xml/tutorial</a>.
|
||||
|
||||
There are different ways to access and interact with XML data.
|
||||
TinyXML uses a Document Object Model (DOM), meaning the XML data is parsed
|
||||
into a C++ objects that can be browsed and manipulated, and then
|
||||
written to disk or another output stream. You can also construct an XML document
|
||||
from scratch with C++ objects and write this to disk or another output
|
||||
stream.
|
||||
|
||||
TinyXML is designed to be easy and fast to learn. It is two headers
|
||||
and four cpp files. Simply add these to your project and off you go.
|
||||
There is an example file - xmltest.cpp - to get you started.
|
||||
|
||||
TinyXML is released under the ZLib license,
|
||||
so you can use it in open source or commercial code. The details
|
||||
of the license are at the top of every source file.
|
||||
|
||||
TinyXML attempts to be a flexible parser, but with truly correct and
|
||||
compliant XML output. TinyXML should compile on any reasonably C++
|
||||
compliant system. It does not rely on exceptions or RTTI. It can be
|
||||
compiled with or without STL support. TinyXML fully supports
|
||||
the UTF-8 encoding, and the first 64k character entities.
|
||||
|
||||
|
||||
<h2> What it doesn't do. </h2>
|
||||
|
||||
TinyXML doesn't parse or use DTDs (Document Type Definitions) or XSLs
|
||||
(eXtensible Stylesheet Language.) There are other parsers out there
|
||||
(check out www.sourceforge.org, search for XML) that are much more fully
|
||||
featured. But they are also much bigger, take longer to set up in
|
||||
your project, have a higher learning curve, and often have a more
|
||||
restrictive license. If you are working with browsers or have more
|
||||
complete XML needs, TinyXML is not the parser for you.
|
||||
|
||||
The following DTD syntax will not parse at this time in TinyXML:
|
||||
|
||||
@verbatim
|
||||
<!DOCTYPE Archiv [
|
||||
<!ELEMENT Comment (#PCDATA)>
|
||||
]>
|
||||
@endverbatim
|
||||
|
||||
because TinyXML sees this as a !DOCTYPE node with an illegally
|
||||
embedded !ELEMENT node. This may be addressed in the future.
|
||||
|
||||
<h2> Tutorials. </h2>
|
||||
|
||||
For the impatient, here is a tutorial to get you going. A great way to get started,
|
||||
but it is worth your time to read this (very short) manual completely.
|
||||
|
||||
- @subpage tutorial0
|
||||
|
||||
<h2> Code Status. </h2>
|
||||
|
||||
TinyXML is mature, tested code. It is very stable. If you find
|
||||
bugs, please file a bug report on the sourceforge web site
|
||||
(www.sourceforge.net/projects/tinyxml). We'll get them straightened
|
||||
out as soon as possible.
|
||||
|
||||
There are some areas of improvement; please check sourceforge if you are
|
||||
interested in working on TinyXML.
|
||||
|
||||
<h2> Related Projects </h2>
|
||||
|
||||
TinyXML projects you may find useful! (Descriptions provided by the projects.)
|
||||
|
||||
<ul>
|
||||
<li> <b>TinyXPath</b> (http://tinyxpath.sourceforge.net). TinyXPath is a small footprint
|
||||
XPath syntax decoder, written in C++.</li>
|
||||
<li> <b>TinyXML++</b> (http://code.google.com/p/ticpp/). TinyXML++ is a completely new
|
||||
interface to TinyXML that uses MANY of the C++ strengths. Templates,
|
||||
exceptions, and much better error handling.</li>
|
||||
</ul>
|
||||
|
||||
<h2> Features </h2>
|
||||
|
||||
<h3> Using STL </h3>
|
||||
|
||||
TinyXML can be compiled to use or not use STL. When using STL, TinyXML
|
||||
uses the std::string class, and fully supports std::istream, std::ostream,
|
||||
operator<<, and operator>>. Many API methods have both 'const char*' and
|
||||
'const std::string&' forms.
|
||||
|
||||
When STL support is compiled out, no STL files are included whatsoever. All
|
||||
the string classes are implemented by TinyXML itself. API methods
|
||||
all use the 'const char*' form for input.
|
||||
|
||||
Use the compile time #define:
|
||||
|
||||
TIXML_USE_STL
|
||||
|
||||
to compile one version or the other. This can be passed by the compiler,
|
||||
or set as the first line of "tinyxml.h".
|
||||
|
||||
Note: If compiling the test code in Linux, setting the environment
|
||||
variable TINYXML_USE_STL=YES/NO will control STL compilation. In the
|
||||
Windows project file, STL and non STL targets are provided. In your project,
|
||||
It's probably easiest to add the line "#define TIXML_USE_STL" as the first
|
||||
line of tinyxml.h.
|
||||
|
||||
<h3> UTF-8 </h3>
|
||||
|
||||
TinyXML supports UTF-8 allowing to manipulate XML files in any language. TinyXML
|
||||
also supports "legacy mode" - the encoding used before UTF-8 support and
|
||||
probably best described as "extended ascii".
|
||||
|
||||
Normally, TinyXML will try to detect the correct encoding and use it. However,
|
||||
by setting the value of TIXML_DEFAULT_ENCODING in the header file, TinyXML
|
||||
can be forced to always use one encoding.
|
||||
|
||||
TinyXML will assume Legacy Mode until one of the following occurs:
|
||||
<ol>
|
||||
<li> If the non-standard but common "UTF-8 lead bytes" (0xef 0xbb 0xbf)
|
||||
begin the file or data stream, TinyXML will read it as UTF-8. </li>
|
||||
<li> If the declaration tag is read, and it has an encoding="UTF-8", then
|
||||
TinyXML will read it as UTF-8. </li>
|
||||
<li> If the declaration tag is read, and it has no encoding specified, then TinyXML will
|
||||
read it as UTF-8. </li>
|
||||
<li> If the declaration tag is read, and it has an encoding="something else", then TinyXML
|
||||
will read it as Legacy Mode. In legacy mode, TinyXML will work as it did before. It's
|
||||
not clear what that mode does exactly, but old content should keep working.</li>
|
||||
<li> Until one of the above criteria is met, TinyXML runs in Legacy Mode.</li>
|
||||
</ol>
|
||||
|
||||
What happens if the encoding is incorrectly set or detected? TinyXML will try
|
||||
to read and pass through text seen as improperly encoded. You may get some strange results or
|
||||
mangled characters. You may want to force TinyXML to the correct mode.
|
||||
|
||||
You may force TinyXML to Legacy Mode by using LoadFile( TIXML_ENCODING_LEGACY ) or
|
||||
LoadFile( filename, TIXML_ENCODING_LEGACY ). You may force it to use legacy mode all
|
||||
the time by setting TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY. Likewise, you may
|
||||
force it to TIXML_ENCODING_UTF8 with the same technique.
|
||||
|
||||
For English users, using English XML, UTF-8 is the same as low-ASCII. You
|
||||
don't need to be aware of UTF-8 or change your code in any way. You can think
|
||||
of UTF-8 as a "superset" of ASCII.
|
||||
|
||||
UTF-8 is not a double byte format - but it is a standard encoding of Unicode!
|
||||
TinyXML does not use or directly support wchar, TCHAR, or Microsoft's _UNICODE at this time.
|
||||
It is common to see the term "Unicode" improperly refer to UTF-16, a wide byte encoding
|
||||
of unicode. This is a source of confusion.
|
||||
|
||||
For "high-ascii" languages - everything not English, pretty much - TinyXML can
|
||||
handle all languages, at the same time, as long as the XML is encoded
|
||||
in UTF-8. That can be a little tricky, older programs and operating systems
|
||||
tend to use the "default" or "traditional" code page. Many apps (and almost all
|
||||
modern ones) can output UTF-8, but older or stubborn (or just broken) ones
|
||||
still output text in the default code page.
|
||||
|
||||
For example, Japanese systems traditionally use SHIFT-JIS encoding.
|
||||
Text encoded as SHIFT-JIS can not be read by TinyXML.
|
||||
A good text editor can import SHIFT-JIS and then save as UTF-8.
|
||||
|
||||
The <a href="http://skew.org/xml/tutorial/">Skew.org link</a> does a great
|
||||
job covering the encoding issue.
|
||||
|
||||
The test file "utf8test.xml" is an XML containing English, Spanish, Russian,
|
||||
and Simplified Chinese. (Hopefully they are translated correctly). The file
|
||||
"utf8test.gif" is a screen capture of the XML file, rendered in IE. Note that
|
||||
if you don't have the correct fonts (Simplified Chinese or Russian) on your
|
||||
system, you won't see output that matches the GIF file even if you can parse
|
||||
it correctly. Also note that (at least on my Windows machine) console output
|
||||
is in a Western code page, so that Print() or printf() cannot correctly display
|
||||
the file. This is not a bug in TinyXML - just an OS issue. No data is lost or
|
||||
destroyed by TinyXML. The console just doesn't render UTF-8.
|
||||
|
||||
|
||||
<h3> Entities </h3>
|
||||
TinyXML recognizes the pre-defined "character entities", meaning special
|
||||
characters. Namely:
|
||||
|
||||
@verbatim
|
||||
& &
|
||||
< <
|
||||
> >
|
||||
" "
|
||||
' '
|
||||
@endverbatim
|
||||
|
||||
These are recognized when the XML document is read, and translated to there
|
||||
UTF-8 equivalents. For instance, text with the XML of:
|
||||
|
||||
@verbatim
|
||||
Far & Away
|
||||
@endverbatim
|
||||
|
||||
will have the Value() of "Far & Away" when queried from the TiXmlText object,
|
||||
and will be written back to the XML stream/file as an ampersand. Older versions
|
||||
of TinyXML "preserved" character entities, but the newer versions will translate
|
||||
them into characters.
|
||||
|
||||
Additionally, any character can be specified by its Unicode code point:
|
||||
The syntax " " or " " are both to the non-breaking space characher.
|
||||
|
||||
<h3> Printing </h3>
|
||||
TinyXML can print output in several different ways that all have strengths and limitations.
|
||||
|
||||
- Print( FILE* ). Output to a std-C stream, which includes all C files as well as stdout.
|
||||
- "Pretty prints", but you don't have control over printing options.
|
||||
- The output is streamed directly to the FILE object, so there is no memory overhead
|
||||
in the TinyXML code.
|
||||
- used by Print() and SaveFile()
|
||||
|
||||
- operator<<. Output to a c++ stream.
|
||||
- Integrates with standart C++ iostreams.
|
||||
- Outputs in "network printing" mode without line breaks. Good for network transmission
|
||||
and moving XML between C++ objects, but hard for a human to read.
|
||||
|
||||
- TiXmlPrinter. Output to a std::string or memory buffer.
|
||||
- API is less concise
|
||||
- Future printing options will be put here.
|
||||
- Printing may change slightly in future versions as it is refined and expanded.
|
||||
|
||||
<h3> Streams </h3>
|
||||
With TIXML_USE_STL on TinyXML supports C++ streams (operator <<,>>) streams as well
|
||||
as C (FILE*) streams. There are some differences that you may need to be aware of.
|
||||
|
||||
C style output:
|
||||
- based on FILE*
|
||||
- the Print() and SaveFile() methods
|
||||
|
||||
Generates formatted output, with plenty of white space, intended to be as
|
||||
human-readable as possible. They are very fast, and tolerant of ill formed
|
||||
XML documents. For example, an XML document that contains 2 root elements
|
||||
and 2 declarations, will still print.
|
||||
|
||||
C style input:
|
||||
- based on FILE*
|
||||
- the Parse() and LoadFile() methods
|
||||
|
||||
A fast, tolerant read. Use whenever you don't need the C++ streams.
|
||||
|
||||
C++ style output:
|
||||
- based on std::ostream
|
||||
- operator<<
|
||||
|
||||
Generates condensed output, intended for network transmission rather than
|
||||
readability. Depending on your system's implementation of the ostream class,
|
||||
these may be somewhat slower. (Or may not.) Not tolerant of ill formed XML:
|
||||
a document should contain the correct one root element. Additional root level
|
||||
elements will not be streamed out.
|
||||
|
||||
C++ style input:
|
||||
- based on std::istream
|
||||
- operator>>
|
||||
|
||||
Reads XML from a stream, making it useful for network transmission. The tricky
|
||||
part is knowing when the XML document is complete, since there will almost
|
||||
certainly be other data in the stream. TinyXML will assume the XML data is
|
||||
complete after it reads the root element. Put another way, documents that
|
||||
are ill-constructed with more than one root element will not read correctly.
|
||||
Also note that operator>> is somewhat slower than Parse, due to both
|
||||
implementation of the STL and limitations of TinyXML.
|
||||
|
||||
<h3> White space </h3>
|
||||
The world simply does not agree on whether white space should be kept, or condensed.
|
||||
For example, pretend the '_' is a space, and look at "Hello____world". HTML, and
|
||||
at least some XML parsers, will interpret this as "Hello_world". They condense white
|
||||
space. Some XML parsers do not, and will leave it as "Hello____world". (Remember
|
||||
to keep pretending the _ is a space.) Others suggest that __Hello___world__ should become
|
||||
Hello___world.
|
||||
|
||||
It's an issue that hasn't been resolved to my satisfaction. TinyXML supports the
|
||||
first 2 approaches. Call TiXmlBase::SetCondenseWhiteSpace( bool ) to set the desired behavior.
|
||||
The default is to condense white space.
|
||||
|
||||
If you change the default, you should call TiXmlBase::SetCondenseWhiteSpace( bool )
|
||||
before making any calls to Parse XML data, and I don't recommend changing it after
|
||||
it has been set.
|
||||
|
||||
|
||||
<h3> Handles </h3>
|
||||
|
||||
Where browsing an XML document in a robust way, it is important to check
|
||||
for null returns from method calls. An error safe implementation can
|
||||
generate a lot of code like:
|
||||
|
||||
@verbatim
|
||||
TiXmlElement* root = document.FirstChildElement( "Document" );
|
||||
if ( root )
|
||||
{
|
||||
TiXmlElement* element = root->FirstChildElement( "Element" );
|
||||
if ( element )
|
||||
{
|
||||
TiXmlElement* child = element->FirstChildElement( "Child" );
|
||||
if ( child )
|
||||
{
|
||||
TiXmlElement* child2 = child->NextSiblingElement( "Child" );
|
||||
if ( child2 )
|
||||
{
|
||||
// Finally do something useful.
|
||||
@endverbatim
|
||||
|
||||
Handles have been introduced to clean this up. Using the TiXmlHandle class,
|
||||
the previous code reduces to:
|
||||
|
||||
@verbatim
|
||||
TiXmlHandle docHandle( &document );
|
||||
TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
|
||||
if ( child2 )
|
||||
{
|
||||
// do something useful
|
||||
@endverbatim
|
||||
|
||||
Which is much easier to deal with. See TiXmlHandle for more information.
|
||||
|
||||
|
||||
<h3> Row and Column tracking </h3>
|
||||
Being able to track nodes and attributes back to their origin location
|
||||
in source files can be very important for some applications. Additionally,
|
||||
knowing where parsing errors occured in the original source can be very
|
||||
time saving.
|
||||
|
||||
TinyXML can tracks the row and column origin of all nodes and attributes
|
||||
in a text file. The TiXmlBase::Row() and TiXmlBase::Column() methods return
|
||||
the origin of the node in the source text. The correct tabs can be
|
||||
configured in TiXmlDocument::SetTabSize().
|
||||
|
||||
|
||||
<h2> Using and Installing </h2>
|
||||
|
||||
To Compile and Run xmltest:
|
||||
|
||||
A Linux Makefile and a Windows Visual C++ .dsw file is provided.
|
||||
Simply compile and run. It will write the file demotest.xml to your
|
||||
disk and generate output on the screen. It also tests walking the
|
||||
DOM by printing out the number of nodes found using different
|
||||
techniques.
|
||||
|
||||
The Linux makefile is very generic and runs on many systems - it
|
||||
is currently tested on mingw and
|
||||
MacOSX. You do not need to run 'make depend'. The dependecies have been
|
||||
hard coded.
|
||||
|
||||
<h3>Windows project file for VC6</h3>
|
||||
<ul>
|
||||
<li>tinyxml: tinyxml library, non-STL </li>
|
||||
<li>tinyxmlSTL: tinyxml library, STL </li>
|
||||
<li>tinyXmlTest: test app, non-STL </li>
|
||||
<li>tinyXmlTestSTL: test app, STL </li>
|
||||
</ul>
|
||||
|
||||
<h3>Makefile</h3>
|
||||
At the top of the makefile you can set:
|
||||
|
||||
PROFILE, DEBUG, and TINYXML_USE_STL. Details (such that they are) are in
|
||||
the makefile.
|
||||
|
||||
In the tinyxml directory, type "make clean" then "make". The executable
|
||||
file 'xmltest' will be created.
|
||||
|
||||
|
||||
|
||||
<h3>To Use in an Application:</h3>
|
||||
|
||||
Add tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp, and tinystr.h to your
|
||||
project or make file. That's it! It should compile on any reasonably
|
||||
compliant C++ system. You do not need to enable exceptions or
|
||||
RTTI for TinyXML.
|
||||
|
||||
|
||||
<h2> How TinyXML works. </h2>
|
||||
|
||||
An example is probably the best way to go. Take:
|
||||
@verbatim
|
||||
<?xml version="1.0" standalone=no>
|
||||
<!-- Our to do list data -->
|
||||
<ToDo>
|
||||
<Item priority="1"> Go to the <bold>Toy store!</bold></Item>
|
||||
<Item priority="2"> Do bills</Item>
|
||||
</ToDo>
|
||||
@endverbatim
|
||||
|
||||
Its not much of a To Do list, but it will do. To read this file
|
||||
(say "demo.xml") you would create a document, and parse it in:
|
||||
@verbatim
|
||||
TiXmlDocument doc( "demo.xml" );
|
||||
doc.LoadFile();
|
||||
@endverbatim
|
||||
|
||||
And its ready to go. Now lets look at some lines and how they
|
||||
relate to the DOM.
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0" standalone=no>
|
||||
@endverbatim
|
||||
|
||||
The first line is a declaration, and gets turned into the
|
||||
TiXmlDeclaration class. It will be the first child of the
|
||||
document node.
|
||||
|
||||
This is the only directive/special tag parsed by TinyXML.
|
||||
Generally directive tags are stored in TiXmlUnknown so the
|
||||
commands wont be lost when it is saved back to disk.
|
||||
|
||||
@verbatim
|
||||
<!-- Our to do list data -->
|
||||
@endverbatim
|
||||
|
||||
A comment. Will become a TiXmlComment object.
|
||||
|
||||
@verbatim
|
||||
<ToDo>
|
||||
@endverbatim
|
||||
|
||||
The "ToDo" tag defines a TiXmlElement object. This one does not have
|
||||
any attributes, but does contain 2 other elements.
|
||||
|
||||
@verbatim
|
||||
<Item priority="1">
|
||||
@endverbatim
|
||||
|
||||
Creates another TiXmlElement which is a child of the "ToDo" element.
|
||||
This element has 1 attribute, with the name "priority" and the value
|
||||
"1".
|
||||
|
||||
@verbatim
|
||||
Go to the
|
||||
@endverbatim
|
||||
|
||||
A TiXmlText. This is a leaf node and cannot contain other nodes.
|
||||
It is a child of the "Item" TiXmlElement.
|
||||
|
||||
@verbatim
|
||||
<bold>
|
||||
@endverbatim
|
||||
|
||||
|
||||
Another TiXmlElement, this one a child of the "Item" element.
|
||||
|
||||
Etc.
|
||||
|
||||
Looking at the entire object tree, you end up with:
|
||||
@verbatim
|
||||
TiXmlDocument "demo.xml"
|
||||
TiXmlDeclaration "version='1.0'" "standalone=no"
|
||||
TiXmlComment " Our to do list data"
|
||||
TiXmlElement "ToDo"
|
||||
TiXmlElement "Item" Attribtutes: priority = 1
|
||||
TiXmlText "Go to the "
|
||||
TiXmlElement "bold"
|
||||
TiXmlText "Toy store!"
|
||||
TiXmlElement "Item" Attributes: priority=2
|
||||
TiXmlText "Do bills"
|
||||
@endverbatim
|
||||
|
||||
<h2> Documentation </h2>
|
||||
|
||||
The documentation is build with Doxygen, using the 'dox'
|
||||
configuration file.
|
||||
|
||||
<h2> License </h2>
|
||||
|
||||
TinyXML is released under the zlib license:
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
<h2> References </h2>
|
||||
|
||||
The World Wide Web Consortium is the definitive standard body for
|
||||
XML, and their web pages contain huge amounts of information.
|
||||
|
||||
The definitive spec: <a href="http://www.w3.org/TR/2004/REC-xml-20040204/">
|
||||
http://www.w3.org/TR/2004/REC-xml-20040204/</a>
|
||||
|
||||
I also recommend "XML Pocket Reference" by Robert Eckstein and published by
|
||||
OReilly...the book that got the whole thing started.
|
||||
|
||||
<h2> Contributors, Contacts, and a Brief History </h2>
|
||||
|
||||
Thanks very much to everyone who sends suggestions, bugs, ideas, and
|
||||
encouragement. It all helps, and makes this project fun. A special thanks
|
||||
to the contributors on the web pages that keep it lively.
|
||||
|
||||
So many people have sent in bugs and ideas, that rather than list here
|
||||
we try to give credit due in the "changes.txt" file.
|
||||
|
||||
TinyXML was originally written by Lee Thomason. (Often the "I" still
|
||||
in the documentation.) Lee reviews changes and releases new versions,
|
||||
with the help of Yves Berquin, Andrew Ellerton, and the tinyXml community.
|
||||
|
||||
We appreciate your suggestions, and would love to know if you
|
||||
use TinyXML. Hopefully you will enjoy it and find it useful.
|
||||
Please post questions, comments, file bugs, or contact us at:
|
||||
|
||||
www.sourceforge.net/projects/tinyxml
|
||||
|
||||
Lee Thomason, Yves Berquin, Andrew Ellerton
|
||||
*/
|
111
mmc_updater/depends/tinyxml/tinystr.cpp
Normal file
111
mmc_updater/depends/tinyxml/tinystr.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/tinyxml
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TIXML_USE_STL
|
||||
|
||||
#include "tinystr.h"
|
||||
|
||||
// Error value for find primitive
|
||||
const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
|
||||
|
||||
|
||||
// Null rep.
|
||||
TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
|
||||
|
||||
|
||||
void TiXmlString::reserve (size_type cap)
|
||||
{
|
||||
if (cap > capacity())
|
||||
{
|
||||
TiXmlString tmp;
|
||||
tmp.init(length(), cap);
|
||||
memcpy(tmp.start(), data(), length());
|
||||
swap(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TiXmlString& TiXmlString::assign(const char* str, size_type len)
|
||||
{
|
||||
size_type cap = capacity();
|
||||
if (len > cap || cap > 3*(len + 8))
|
||||
{
|
||||
TiXmlString tmp;
|
||||
tmp.init(len);
|
||||
memcpy(tmp.start(), str, len);
|
||||
swap(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(start(), str, len);
|
||||
set_size(len);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
TiXmlString& TiXmlString::append(const char* str, size_type len)
|
||||
{
|
||||
size_type newsize = length() + len;
|
||||
if (newsize > capacity())
|
||||
{
|
||||
reserve (newsize + capacity());
|
||||
}
|
||||
memmove(finish(), str, len);
|
||||
set_size(newsize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
|
||||
{
|
||||
TiXmlString tmp;
|
||||
tmp.reserve(a.length() + b.length());
|
||||
tmp += a;
|
||||
tmp += b;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
TiXmlString operator + (const TiXmlString & a, const char* b)
|
||||
{
|
||||
TiXmlString tmp;
|
||||
TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
|
||||
tmp.reserve(a.length() + b_len);
|
||||
tmp += a;
|
||||
tmp.append(b, b_len);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
TiXmlString operator + (const char* a, const TiXmlString & b)
|
||||
{
|
||||
TiXmlString tmp;
|
||||
TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
|
||||
tmp.reserve(a_len + b.length());
|
||||
tmp.append(a, a_len);
|
||||
tmp += b;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
#endif // TIXML_USE_STL
|
305
mmc_updater/depends/tinyxml/tinystr.h
Normal file
305
mmc_updater/depends/tinyxml/tinystr.h
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/tinyxml
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TIXML_USE_STL
|
||||
|
||||
#ifndef TIXML_STRING_INCLUDED
|
||||
#define TIXML_STRING_INCLUDED
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* The support for explicit isn't that universal, and it isn't really
|
||||
required - it is used to check that the TiXmlString class isn't incorrectly
|
||||
used. Be nice to old compilers and macro it here:
|
||||
*/
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
|
||||
// Microsoft visual studio, version 6 and higher.
|
||||
#define TIXML_EXPLICIT explicit
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 3 )
|
||||
// GCC version 3 and higher.s
|
||||
#define TIXML_EXPLICIT explicit
|
||||
#else
|
||||
#define TIXML_EXPLICIT
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
TiXmlString is an emulation of a subset of the std::string template.
|
||||
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
|
||||
Only the member functions relevant to the TinyXML project have been implemented.
|
||||
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
|
||||
a string and there's no more room, we allocate a buffer twice as big as we need.
|
||||
*/
|
||||
class TiXmlString
|
||||
{
|
||||
public :
|
||||
// The size type used
|
||||
typedef size_t size_type;
|
||||
|
||||
// Error value for find primitive
|
||||
static const size_type npos; // = -1;
|
||||
|
||||
|
||||
// TiXmlString empty constructor
|
||||
TiXmlString () : rep_(&nullrep_)
|
||||
{
|
||||
}
|
||||
|
||||
// TiXmlString copy constructor
|
||||
TiXmlString ( const TiXmlString & copy) : rep_(0)
|
||||
{
|
||||
init(copy.length());
|
||||
memcpy(start(), copy.data(), length());
|
||||
}
|
||||
|
||||
// TiXmlString constructor, based on a string
|
||||
TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
|
||||
{
|
||||
init( static_cast<size_type>( strlen(copy) ));
|
||||
memcpy(start(), copy, length());
|
||||
}
|
||||
|
||||
// TiXmlString constructor, based on a string
|
||||
TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
|
||||
{
|
||||
init(len);
|
||||
memcpy(start(), str, len);
|
||||
}
|
||||
|
||||
// TiXmlString destructor
|
||||
~TiXmlString ()
|
||||
{
|
||||
quit();
|
||||
}
|
||||
|
||||
TiXmlString& operator = (const char * copy)
|
||||
{
|
||||
return assign( copy, (size_type)strlen(copy));
|
||||
}
|
||||
|
||||
TiXmlString& operator = (const TiXmlString & copy)
|
||||
{
|
||||
return assign(copy.start(), copy.length());
|
||||
}
|
||||
|
||||
|
||||
// += operator. Maps to append
|
||||
TiXmlString& operator += (const char * suffix)
|
||||
{
|
||||
return append(suffix, static_cast<size_type>( strlen(suffix) ));
|
||||
}
|
||||
|
||||
// += operator. Maps to append
|
||||
TiXmlString& operator += (char single)
|
||||
{
|
||||
return append(&single, 1);
|
||||
}
|
||||
|
||||
// += operator. Maps to append
|
||||
TiXmlString& operator += (const TiXmlString & suffix)
|
||||
{
|
||||
return append(suffix.data(), suffix.length());
|
||||
}
|
||||
|
||||
|
||||
// Convert a TiXmlString into a null-terminated char *
|
||||
const char * c_str () const { return rep_->str; }
|
||||
|
||||
// Convert a TiXmlString into a char * (need not be null terminated).
|
||||
const char * data () const { return rep_->str; }
|
||||
|
||||
// Return the length of a TiXmlString
|
||||
size_type length () const { return rep_->size; }
|
||||
|
||||
// Alias for length()
|
||||
size_type size () const { return rep_->size; }
|
||||
|
||||
// Checks if a TiXmlString is empty
|
||||
bool empty () const { return rep_->size == 0; }
|
||||
|
||||
// Return capacity of string
|
||||
size_type capacity () const { return rep_->capacity; }
|
||||
|
||||
|
||||
// single char extraction
|
||||
const char& at (size_type index) const
|
||||
{
|
||||
assert( index < length() );
|
||||
return rep_->str[ index ];
|
||||
}
|
||||
|
||||
// [] operator
|
||||
char& operator [] (size_type index) const
|
||||
{
|
||||
assert( index < length() );
|
||||
return rep_->str[ index ];
|
||||
}
|
||||
|
||||
// find a char in a string. Return TiXmlString::npos if not found
|
||||
size_type find (char lookup) const
|
||||
{
|
||||
return find(lookup, 0);
|
||||
}
|
||||
|
||||
// find a char in a string from an offset. Return TiXmlString::npos if not found
|
||||
size_type find (char tofind, size_type offset) const
|
||||
{
|
||||
if (offset >= length()) return npos;
|
||||
|
||||
for (const char* p = c_str() + offset; *p != '\0'; ++p)
|
||||
{
|
||||
if (*p == tofind) return static_cast< size_type >( p - c_str() );
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
//Lee:
|
||||
//The original was just too strange, though correct:
|
||||
// TiXmlString().swap(*this);
|
||||
//Instead use the quit & re-init:
|
||||
quit();
|
||||
init(0,0);
|
||||
}
|
||||
|
||||
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this
|
||||
function DOES NOT clear the content of the TiXmlString if any exists.
|
||||
*/
|
||||
void reserve (size_type cap);
|
||||
|
||||
TiXmlString& assign (const char* str, size_type len);
|
||||
|
||||
TiXmlString& append (const char* str, size_type len);
|
||||
|
||||
void swap (TiXmlString& other)
|
||||
{
|
||||
Rep* r = rep_;
|
||||
rep_ = other.rep_;
|
||||
other.rep_ = r;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init(size_type sz) { init(sz, sz); }
|
||||
void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
|
||||
char* start() const { return rep_->str; }
|
||||
char* finish() const { return rep_->str + rep_->size; }
|
||||
|
||||
struct Rep
|
||||
{
|
||||
size_type size, capacity;
|
||||
char str[1];
|
||||
};
|
||||
|
||||
void init(size_type sz, size_type cap)
|
||||
{
|
||||
if (cap)
|
||||
{
|
||||
// Lee: the original form:
|
||||
// rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
|
||||
// doesn't work in some cases of new being overloaded. Switching
|
||||
// to the normal allocation, although use an 'int' for systems
|
||||
// that are overly picky about structure alignment.
|
||||
const size_type bytesNeeded = sizeof(Rep) + cap;
|
||||
const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
|
||||
rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
|
||||
|
||||
rep_->str[ rep_->size = sz ] = '\0';
|
||||
rep_->capacity = cap;
|
||||
}
|
||||
else
|
||||
{
|
||||
rep_ = &nullrep_;
|
||||
}
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
if (rep_ != &nullrep_)
|
||||
{
|
||||
// The rep_ is really an array of ints. (see the allocator, above).
|
||||
// Cast it back before delete, so the compiler won't incorrectly call destructors.
|
||||
delete [] ( reinterpret_cast<int*>( rep_ ) );
|
||||
}
|
||||
}
|
||||
|
||||
Rep * rep_;
|
||||
static Rep nullrep_;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
inline bool operator == (const TiXmlString & a, const TiXmlString & b)
|
||||
{
|
||||
return ( a.length() == b.length() ) // optimization on some platforms
|
||||
&& ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
|
||||
}
|
||||
inline bool operator < (const TiXmlString & a, const TiXmlString & b)
|
||||
{
|
||||
return strcmp(a.c_str(), b.c_str()) < 0;
|
||||
}
|
||||
|
||||
inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
|
||||
inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
|
||||
inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
|
||||
inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
|
||||
|
||||
inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
|
||||
inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
|
||||
inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
|
||||
inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
|
||||
|
||||
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
|
||||
TiXmlString operator + (const TiXmlString & a, const char* b);
|
||||
TiXmlString operator + (const char* a, const TiXmlString & b);
|
||||
|
||||
|
||||
/*
|
||||
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
|
||||
Only the operators that we need for TinyXML have been developped.
|
||||
*/
|
||||
class TiXmlOutStream : public TiXmlString
|
||||
{
|
||||
public :
|
||||
|
||||
// TiXmlOutStream << operator.
|
||||
TiXmlOutStream & operator << (const TiXmlString & in)
|
||||
{
|
||||
*this += in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TiXmlOutStream << operator.
|
||||
TiXmlOutStream & operator << (const char * in)
|
||||
{
|
||||
*this += in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
#endif // TIXML_STRING_INCLUDED
|
||||
#endif // TIXML_USE_STL
|
1886
mmc_updater/depends/tinyxml/tinyxml.cpp
Normal file
1886
mmc_updater/depends/tinyxml/tinyxml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1805
mmc_updater/depends/tinyxml/tinyxml.h
Normal file
1805
mmc_updater/depends/tinyxml/tinyxml.h
Normal file
File diff suppressed because it is too large
Load Diff
52
mmc_updater/depends/tinyxml/tinyxmlerror.cpp
Normal file
52
mmc_updater/depends/tinyxml/tinyxmlerror.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/tinyxml
|
||||
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "tinyxml.h"
|
||||
|
||||
// The goal of the seperate error file is to make the first
|
||||
// step towards localization. tinyxml (currently) only supports
|
||||
// english error messages, but the could now be translated.
|
||||
//
|
||||
// It also cleans up the code a bit.
|
||||
//
|
||||
|
||||
const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] =
|
||||
{
|
||||
"No error",
|
||||
"Error",
|
||||
"Failed to open file",
|
||||
"Error parsing Element.",
|
||||
"Failed to read Element name",
|
||||
"Error reading Element value.",
|
||||
"Error reading Attributes.",
|
||||
"Error: empty tag.",
|
||||
"Error reading end tag.",
|
||||
"Error parsing Unknown.",
|
||||
"Error parsing Comment.",
|
||||
"Error parsing Declaration.",
|
||||
"Error document empty.",
|
||||
"Error null (0) or unexpected EOF found in input stream.",
|
||||
"Error parsing CDATA.",
|
||||
"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
|
||||
};
|
1638
mmc_updater/depends/tinyxml/tinyxmlparser.cpp
Normal file
1638
mmc_updater/depends/tinyxml/tinyxmlparser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1074
mmc_updater/depends/win32cpp/controls.h
Normal file
1074
mmc_updater/depends/win32cpp/controls.h
Normal file
File diff suppressed because it is too large
Load Diff
33
mmc_updater/depends/win32cpp/copyright.txt
Normal file
33
mmc_updater/depends/win32cpp/copyright.txt
Normal file
@ -0,0 +1,33 @@
|
||||
Win32++ Version 7.2
|
||||
Released: 5th AUgust 2011
|
||||
|
||||
David Nash
|
||||
email: dnash@bigpond.net.au
|
||||
url: https://sourceforge.net/projects/win32-framework
|
||||
|
||||
|
||||
Copyright (c) 2005-2011 David Nash
|
||||
|
||||
Permission is hereby granted, free of charge, to
|
||||
any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
905
mmc_updater/depends/win32cpp/cstring.h
Normal file
905
mmc_updater/depends/win32cpp/cstring.h
Normal file
@ -0,0 +1,905 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Acknowledgements:
|
||||
// Thanks to Adam Szulc for his initial CString code.
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// cstring.h
|
||||
// Declaration of the cstring.h
|
||||
|
||||
// This class is intended to provide a simple alternative to the MFC/ATL
|
||||
// CString class that ships with Microsoft compilers. The CString class
|
||||
// specified here is compatible with other compilers such as Borland 5.5
|
||||
// and MinGW.
|
||||
|
||||
// Differences between this class and the MFC/ATL CString class
|
||||
// ------------------------------------------------------------
|
||||
// 1) The constructors for this class accepts only TCHARs. The various text conversion
|
||||
// functions can be used to convert from other character types to TCHARs.
|
||||
//
|
||||
// 2) This class is not reference counted, so these CStrings should be passed as
|
||||
// references or const references when used as function arguments. As a result there
|
||||
// is no need for functions like LockBuffer and UnLockBuffer.
|
||||
//
|
||||
// 3) The Format functions only accepts POD (Plain Old Data) arguments. It does not
|
||||
// accept arguments which are class or struct objects. In particular it does not
|
||||
// accept CString objects, unless these are cast to LPCTSTR.
|
||||
// This is demonstrates valid and invalid usage:
|
||||
// CString string1(_T("Hello World"));
|
||||
// CString string2;
|
||||
//
|
||||
// // This is invalid, and produces undefined behaviour.
|
||||
// string2.Format(_T("String1 is: %s"), string1); // No! you can't do this
|
||||
//
|
||||
// // This is ok
|
||||
// string2.Format(_T("String1 is: %s"), (LPCTSTR)string1); // Yes, this is correct
|
||||
//
|
||||
// Note: The MFC/ATL CString class uses a non portable hack to make its CString class
|
||||
// behave like a POD. Other compilers (such as the MinGW compiler) specifically
|
||||
// prohibit the use of non POD types for functions with variable argument lists.
|
||||
//
|
||||
// 4) This class provides a few additional functions:
|
||||
// b_str Returns a BSTR string. This an an alternative for casting to BSTR.
|
||||
// c_str Returns a const TCHAR string. This is an alternative for casting to LPCTSTR.
|
||||
// GetErrorString Assigns CString to the error string for the specified System Error Code
|
||||
// (from ::GetLastErrror() for example).
|
||||
// GetString Returns a reference to the underlying std::basic_string<TCHAR>. This
|
||||
// reference can be used to modify the string directly.
|
||||
|
||||
|
||||
|
||||
#ifndef _WIN32XX_CSTRING_H_
|
||||
#define _WIN32XX_CSTRING_H_
|
||||
|
||||
|
||||
#include "wincore.h"
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
class CString
|
||||
{
|
||||
// friend functions allow the left hand side to be something other than CString
|
||||
friend CString operator + (const CString& string1, const CString& string2);
|
||||
friend CString operator + (const CString& string, LPCTSTR pszText);
|
||||
friend CString operator + (const CString& string, TCHAR ch);
|
||||
friend CString operator + (LPCTSTR pszText, const CString& string);
|
||||
friend CString operator + (TCHAR ch, const CString& string);
|
||||
|
||||
public:
|
||||
CString();
|
||||
~CString();
|
||||
CString(const CString& str);
|
||||
CString(LPCTSTR pszText);
|
||||
CString(TCHAR ch, int nLength = 1);
|
||||
CString(LPCTSTR pszText, int nLength);
|
||||
|
||||
CString& operator = (const CString& str);
|
||||
CString& operator = (const TCHAR ch);
|
||||
CString& operator = (LPCTSTR pszText);
|
||||
BOOL operator == (LPCTSTR pszText);
|
||||
BOOL operator != (LPCTSTR pszText);
|
||||
BOOL operator < (LPCTSTR pszText);
|
||||
BOOL operator > (LPCTSTR pszText);
|
||||
BOOL operator <= (LPCTSTR pszText);
|
||||
BOOL operator >= (LPCTSTR pszText);
|
||||
operator LPCTSTR() const;
|
||||
operator BSTR() const;
|
||||
TCHAR& operator [] (int nIndex);
|
||||
CString& operator += (const CString& str);
|
||||
|
||||
// Attributes
|
||||
BSTR b_str() const { return T2W(m_str.c_str()); } // alternative for casting to BSTR
|
||||
LPCTSTR c_str() const { return m_str.c_str(); } // alternative for casting to LPCTSTR
|
||||
tString& GetString() { return m_str; } // returns a reference to the underlying std::basic_string<TCHAR>
|
||||
int GetLength() const { return (int)m_str.length(); } // returns the length in characters
|
||||
|
||||
// Operations
|
||||
BSTR AllocSysString() const;
|
||||
void AppendFormat(LPCTSTR pszFormat,...);
|
||||
void AppendFormat(UINT nFormatID, ...);
|
||||
int Compare(LPCTSTR pszText) const;
|
||||
int CompareNoCase(LPCTSTR pszText) const;
|
||||
int Delete(int nIndex, int nCount = 1);
|
||||
int Find(TCHAR ch, int nIndex = 0 ) const;
|
||||
int Find(LPCTSTR pszText, int nStart = 0) const;
|
||||
int FindOneOf(LPCTSTR pszText) const;
|
||||
void Format(UINT nID, ...);
|
||||
void Format(LPCTSTR pszFormat,...);
|
||||
void FormatV(LPCTSTR pszFormat, va_list args);
|
||||
void FormatMessage(LPCTSTR pszFormat,...);
|
||||
void FormatMessageV(LPCTSTR pszFormat, va_list args);
|
||||
TCHAR GetAt(int nIndex) const;
|
||||
LPTSTR GetBuffer(int nMinBufLength);
|
||||
void GetErrorString(DWORD dwError);
|
||||
void Empty();
|
||||
int Insert(int nIndex, TCHAR ch);
|
||||
int Insert(int nIndex, const CString& str);
|
||||
BOOL IsEmpty() const;
|
||||
CString Left(int nCount) const;
|
||||
BOOL LoadString(UINT nID);
|
||||
void MakeLower();
|
||||
void MakeReverse();
|
||||
void MakeUpper();
|
||||
CString Mid(int nFirst) const;
|
||||
CString Mid(int nFirst, int nCount) const;
|
||||
void ReleaseBuffer( int nNewLength = -1 );
|
||||
int Remove(LPCTSTR pszText);
|
||||
int Replace(TCHAR chOld, TCHAR chNew);
|
||||
int Replace(const LPCTSTR pszOld, LPCTSTR pszNew);
|
||||
int ReverseFind(LPCTSTR pszText, int nStart = -1) const;
|
||||
CString Right(int nCount) const;
|
||||
void SetAt(int nIndex, TCHAR ch);
|
||||
BSTR SetSysString(BSTR* pBstr) const;
|
||||
CString SpanExcluding(LPCTSTR pszText) const;
|
||||
CString SpanIncluding(LPCTSTR pszText) const;
|
||||
CString Tokenize(LPCTSTR pszTokens, int& iStart) const;
|
||||
void Trim();
|
||||
void TrimLeft();
|
||||
void TrimLeft(TCHAR chTarget);
|
||||
void TrimLeft(LPCTSTR pszTargets);
|
||||
void TrimRight();
|
||||
void TrimRight(TCHAR chTarget);
|
||||
void TrimRight(LPCTSTR pszTargets);
|
||||
void Truncate(int nNewLength);
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
int Collate(LPCTSTR pszText) const;
|
||||
int CollateNoCase(LPCTSTR pszText) const;
|
||||
BOOL GetEnvironmentVariable(LPCTSTR pszVar);
|
||||
#endif
|
||||
|
||||
private:
|
||||
tString m_str;
|
||||
std::vector<TCHAR> m_buf;
|
||||
};
|
||||
|
||||
inline CString::CString()
|
||||
{
|
||||
}
|
||||
|
||||
inline CString::~CString()
|
||||
{
|
||||
}
|
||||
|
||||
inline CString::CString(const CString& str)
|
||||
{
|
||||
m_str.assign(str);
|
||||
}
|
||||
|
||||
inline CString::CString(LPCTSTR pszText)
|
||||
{
|
||||
m_str.assign(pszText);
|
||||
}
|
||||
|
||||
inline CString::CString(TCHAR ch, int nLength)
|
||||
{
|
||||
m_str.assign(nLength, ch);
|
||||
}
|
||||
|
||||
inline CString::CString(LPCTSTR pszText, int nLength)
|
||||
{
|
||||
m_str.assign(pszText, nLength);
|
||||
}
|
||||
|
||||
inline CString& CString::operator = (const CString& str)
|
||||
{
|
||||
m_str.assign(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CString& CString::operator = (const TCHAR ch)
|
||||
{
|
||||
m_str.assign(1, ch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CString& CString::operator = (LPCTSTR pszText)
|
||||
{
|
||||
m_str.assign(pszText);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline BOOL CString::operator == (LPCTSTR pszText)
|
||||
// Returns TRUE if the strings have the same content
|
||||
{
|
||||
assert(pszText);
|
||||
return (0 == Compare(pszText));
|
||||
}
|
||||
|
||||
inline BOOL CString::operator != (LPCTSTR pszText)
|
||||
// Returns TRUE if the strings have a different content
|
||||
{
|
||||
assert(pszText);
|
||||
return Compare(pszText) != 0;
|
||||
}
|
||||
|
||||
inline BOOL CString::operator < (LPCTSTR pszText)
|
||||
{
|
||||
assert(pszText);
|
||||
return Compare(pszText) < 0;
|
||||
}
|
||||
|
||||
inline BOOL CString::operator > (LPCTSTR pszText)
|
||||
{
|
||||
assert(pszText);
|
||||
return Compare(pszText) > 0;
|
||||
}
|
||||
|
||||
inline BOOL CString::operator <= (LPCTSTR pszText)
|
||||
{
|
||||
assert(pszText);
|
||||
return Compare(pszText) <= 0;
|
||||
}
|
||||
|
||||
inline BOOL CString::operator >= (LPCTSTR pszText)
|
||||
{
|
||||
assert(pszText);
|
||||
return Compare(pszText) >= 0;
|
||||
}
|
||||
|
||||
inline CString::operator LPCTSTR() const
|
||||
{
|
||||
return m_str.c_str();
|
||||
}
|
||||
|
||||
inline TCHAR& CString::operator [] (int nIndex)
|
||||
{
|
||||
assert(nIndex >= 0);
|
||||
assert(nIndex < GetLength());
|
||||
return m_str[nIndex];
|
||||
}
|
||||
|
||||
inline CString& CString::operator += (const CString& str)
|
||||
{
|
||||
m_str.append(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline BSTR CString::AllocSysString() const
|
||||
// Allocates a BSTR from the CString content.
|
||||
{
|
||||
return ::SysAllocStringLen(T2W(m_str.c_str()), (UINT)m_str.size());
|
||||
}
|
||||
|
||||
inline void CString::AppendFormat(LPCTSTR pszFormat,...)
|
||||
// Appends formatted data to an the CString content.
|
||||
{
|
||||
CString str;
|
||||
str.Format(pszFormat);
|
||||
m_str.append(str);
|
||||
}
|
||||
|
||||
inline void CString::AppendFormat(UINT nFormatID, ...)
|
||||
// Appends formatted data to an the CString content.
|
||||
{
|
||||
CString str1;
|
||||
CString str2;
|
||||
if (str1.LoadString(nFormatID))
|
||||
{
|
||||
str2.Format(str1);
|
||||
m_str.append(str2);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
inline int CString::Collate(LPCTSTR pszText) const
|
||||
// Performs a case sensitive comparison of the two strings using locale-specific information.
|
||||
{
|
||||
assert(pszText);
|
||||
return _tcscoll(m_str.c_str(), pszText);
|
||||
}
|
||||
|
||||
inline int CString::CollateNoCase(LPCTSTR pszText) const
|
||||
// Performs a case insensitive comparison of the two strings using locale-specific information.
|
||||
{
|
||||
assert(pszText);
|
||||
return _tcsicoll(m_str.c_str(), pszText);
|
||||
}
|
||||
#endif // _WIN32_WCE
|
||||
|
||||
inline int CString::Compare(LPCTSTR pszText) const
|
||||
// Performs a case sensitive comparison of the two strings.
|
||||
{
|
||||
assert(pszText);
|
||||
return m_str.compare(pszText);
|
||||
}
|
||||
|
||||
inline int CString::CompareNoCase(LPCTSTR pszText) const
|
||||
// Performs a case insensitive comparison of the two strings.
|
||||
{
|
||||
assert(pszText);
|
||||
return _tcsicmp(m_str.data(), pszText);
|
||||
}
|
||||
|
||||
inline int CString::Delete(int nIndex, int nCount /* = 1 */)
|
||||
// Deletes a character or characters from the string.
|
||||
{
|
||||
assert(nIndex >= 0);
|
||||
assert(nCount >= 0);
|
||||
|
||||
m_str.erase(nIndex, nCount);
|
||||
return (int)m_str.size();
|
||||
}
|
||||
|
||||
inline void CString::Empty()
|
||||
// Erases the contents of the string.
|
||||
{
|
||||
m_str.erase();
|
||||
}
|
||||
|
||||
inline int CString::Find(TCHAR ch, int nIndex /* = 0 */) const
|
||||
// Finds a character in the string.
|
||||
{
|
||||
assert(nIndex >= 0);
|
||||
return (int)m_str.find(ch, nIndex);
|
||||
}
|
||||
|
||||
inline int CString::Find(LPCTSTR pszText, int nIndex /* = 0 */) const
|
||||
// Finds a substring within the string.
|
||||
{
|
||||
assert(pszText);
|
||||
assert(nIndex >= 0);
|
||||
return (int)m_str.find(pszText, nIndex);
|
||||
}
|
||||
|
||||
inline int CString::FindOneOf(LPCTSTR pszText) const
|
||||
// Finds the first matching character from a set.
|
||||
{
|
||||
assert(pszText);
|
||||
return (int)m_str.find_first_of(pszText);
|
||||
}
|
||||
|
||||
inline void CString::Format(LPCTSTR pszFormat,...)
|
||||
// Formats the string as sprintf does.
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, pszFormat);
|
||||
FormatV(pszFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
inline void CString::Format(UINT nID, ...)
|
||||
// Formats the string as sprintf does.
|
||||
{
|
||||
Empty();
|
||||
CString str;
|
||||
if (str.LoadString(nID))
|
||||
Format(str);
|
||||
}
|
||||
|
||||
inline void CString::FormatV(LPCTSTR pszFormat, va_list args)
|
||||
// Formats the string using a variable list of arguments.
|
||||
{
|
||||
if (pszFormat)
|
||||
{
|
||||
int nResult = -1, nLength = 256;
|
||||
|
||||
// A vector is used to store the TCHAR array
|
||||
std::vector<TCHAR> vBuffer;( nLength+1, _T('\0') );
|
||||
|
||||
while (-1 == nResult)
|
||||
{
|
||||
vBuffer.assign( nLength+1, _T('\0') );
|
||||
nResult = _vsntprintf(&vBuffer[0], nLength, pszFormat, args);
|
||||
nLength *= 2;
|
||||
}
|
||||
m_str.assign(&vBuffer[0]);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CString::FormatMessage(LPCTSTR pszFormat,...)
|
||||
// Formats a message string.
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, pszFormat);
|
||||
FormatMessageV(pszFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
inline void CString::FormatMessageV(LPCTSTR pszFormat, va_list args)
|
||||
// Formats a message string using a variable argument list.
|
||||
{
|
||||
LPTSTR pszTemp = 0;
|
||||
if (pszFormat)
|
||||
{
|
||||
DWORD dwResult = ::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER, pszFormat, 0, 0, pszTemp, 0, &args);
|
||||
|
||||
if (0 == dwResult || 0 == pszTemp )
|
||||
throw std::bad_alloc();
|
||||
|
||||
m_str = pszTemp;
|
||||
LocalFree(pszTemp);
|
||||
}
|
||||
}
|
||||
|
||||
inline TCHAR CString::GetAt(int nIndex) const
|
||||
// Returns the character at the specified location within the string.
|
||||
{
|
||||
assert(nIndex >= 0);
|
||||
assert(nIndex < GetLength());
|
||||
return m_str[nIndex];
|
||||
}
|
||||
|
||||
inline LPTSTR CString::GetBuffer(int nMinBufLength)
|
||||
// Creates a buffer of nMinBufLength charaters (+1 extra for NULL termination) and returns
|
||||
// a pointer to this buffer. This buffer can be used by any function which accepts a LPTSTR.
|
||||
// Care must be taken not to exceed the length of the buffer. Use ReleaseBuffer to safely
|
||||
// copy this buffer back to the CString object.
|
||||
//
|
||||
// Note: The buffer uses a vector. Vectors are required to be contiguous in memory under
|
||||
// the current standard, whereas std::strings do not have this requirement.
|
||||
{
|
||||
assert (nMinBufLength >= 0);
|
||||
|
||||
m_buf.assign(nMinBufLength + 1, _T('\0'));
|
||||
tString::iterator it_end;
|
||||
|
||||
if (m_str.length() >= (size_t)nMinBufLength)
|
||||
{
|
||||
it_end = m_str.begin();
|
||||
std::advance(it_end, nMinBufLength);
|
||||
}
|
||||
else
|
||||
it_end = m_str.end();
|
||||
|
||||
std::copy(m_str.begin(), it_end, m_buf.begin());
|
||||
|
||||
return &m_buf[0];
|
||||
}
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
inline BOOL CString::GetEnvironmentVariable(LPCTSTR pszVar)
|
||||
// Sets the string to the value of the specified environment variable.
|
||||
{
|
||||
assert(pszVar);
|
||||
Empty();
|
||||
|
||||
int nLength = ::GetEnvironmentVariable(pszVar, NULL, 0);
|
||||
if (nLength > 0)
|
||||
{
|
||||
std::vector<TCHAR> vBuffer( nLength+1, _T('\0') );
|
||||
::GetEnvironmentVariable(pszVar, &vBuffer[0], nLength);
|
||||
m_str = &vBuffer[0];
|
||||
}
|
||||
|
||||
return (BOOL)nLength;
|
||||
}
|
||||
#endif // _WIN32_WCE
|
||||
|
||||
inline void CString::GetErrorString(DWORD dwError)
|
||||
// Returns the error string for the specified System Error Code (e.g from GetLastErrror).
|
||||
{
|
||||
m_str.erase();
|
||||
|
||||
if (dwError != 0)
|
||||
{
|
||||
TCHAR* pTemp = 0;
|
||||
DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
::FormatMessage(dwFlags, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pTemp, 1, NULL);
|
||||
m_str.assign(pTemp);
|
||||
::LocalFree(pTemp);
|
||||
}
|
||||
}
|
||||
|
||||
inline int CString::Insert(int nIndex, TCHAR ch)
|
||||
// Inserts a single character or a substring at the given index within the string.
|
||||
{
|
||||
assert(nIndex >= 0);
|
||||
assert(ch);
|
||||
|
||||
m_str.insert(nIndex, &ch, 1);
|
||||
return (int)m_str.size();
|
||||
}
|
||||
|
||||
inline int CString::Insert(int nIndex, const CString& str)
|
||||
// Inserts a single character or a substring at the given index within the string.
|
||||
{
|
||||
assert(nIndex >= 0);
|
||||
|
||||
m_str.insert(nIndex, str);
|
||||
return (int)m_str.size();
|
||||
}
|
||||
|
||||
inline BOOL CString::IsEmpty() const
|
||||
// Returns TRUE if the string is empty
|
||||
{
|
||||
return m_str.empty();
|
||||
}
|
||||
|
||||
inline CString CString::Left(int nCount) const
|
||||
// Extracts the left part of a string.
|
||||
{
|
||||
assert(nCount >= 0);
|
||||
|
||||
CString str;
|
||||
str.m_str.assign(c_str(), 0, nCount);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline BOOL CString::LoadString(UINT nID)
|
||||
// Loads the string from a Windows resource.
|
||||
{
|
||||
assert (GetApp());
|
||||
|
||||
int nSize = 64;
|
||||
TCHAR* pTCharArray = 0;
|
||||
std::vector<TCHAR> vString;
|
||||
int nTChars = nSize;
|
||||
|
||||
Empty();
|
||||
|
||||
// Increase the size of our array in a loop until we load the entire string
|
||||
// The ANSI and _UNICODE versions of LoadString behave differently. This technique works for both.
|
||||
while ( nSize-1 <= nTChars )
|
||||
{
|
||||
nSize = nSize * 4;
|
||||
vString.assign(nSize+1, _T('\0'));
|
||||
pTCharArray = &vString[0];
|
||||
nTChars = ::LoadString (GetApp()->GetResourceHandle(), nID, pTCharArray, nSize);
|
||||
}
|
||||
|
||||
if (nTChars > 0)
|
||||
m_str.assign(pTCharArray);
|
||||
|
||||
return (nTChars != 0);
|
||||
}
|
||||
|
||||
inline void CString::MakeLower()
|
||||
// Converts all the characters in this string to lowercase characters.
|
||||
{
|
||||
std::transform(m_str.begin(), m_str.end(), m_str.begin(), &::tolower);
|
||||
}
|
||||
|
||||
inline void CString::MakeReverse()
|
||||
// Reverses the string.
|
||||
{
|
||||
std::reverse(m_str.begin(), m_str.end());
|
||||
}
|
||||
|
||||
inline void CString::MakeUpper()
|
||||
// Converts all the characters in this string to uppercase characters.
|
||||
{
|
||||
std::transform(m_str.begin(), m_str.end(), m_str.begin(), &::toupper);
|
||||
}
|
||||
|
||||
inline CString CString::Mid(int nFirst) const
|
||||
// Extracts the middle part of a string.
|
||||
{
|
||||
return Mid(nFirst, GetLength());
|
||||
}
|
||||
|
||||
inline CString CString::Mid(int nFirst, int nCount) const
|
||||
// Extracts the middle part of a string.
|
||||
{
|
||||
assert(nFirst >= 0);
|
||||
assert(nCount >= 0);
|
||||
|
||||
CString str;
|
||||
str.m_str.assign(c_str(), nFirst, nFirst + nCount);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline int CString::ReverseFind(LPCTSTR pszText, int nIndex /* = -1 */) const
|
||||
// Search for a substring within the string, starting from the end.
|
||||
{
|
||||
assert(pszText);
|
||||
return (int)m_str.rfind(pszText, nIndex);
|
||||
}
|
||||
|
||||
inline void CString::SetAt(int nIndex, TCHAR ch)
|
||||
// Sets the character at the specificed position to the specified value.
|
||||
{
|
||||
assert(nIndex >= 0);
|
||||
assert(nIndex < GetLength());
|
||||
m_str[nIndex] = ch;
|
||||
}
|
||||
|
||||
inline void CString::ReleaseBuffer( int nNewLength /*= -1*/ )
|
||||
// This copies the contents of the buffer (acquired by GetBuffer) to this CString,
|
||||
// and releases the contents of the buffer. The default length of -1 copies from the
|
||||
// buffer until a null terminator is reached. If the buffer doesn't contain a null
|
||||
// terminator, you must specify the buffer's length.
|
||||
{
|
||||
assert (nNewLength > 0 || -1 == nNewLength);
|
||||
assert (nNewLength < (int)m_buf.size());
|
||||
|
||||
if (-1 == nNewLength)
|
||||
nNewLength = lstrlen(&m_buf[0]);
|
||||
m_str.assign(nNewLength+1, _T('\0'));
|
||||
|
||||
std::vector<TCHAR>::iterator it_end = m_buf.begin();
|
||||
std::advance(it_end, nNewLength);
|
||||
|
||||
std::copy(m_buf.begin(), it_end, m_str.begin());
|
||||
m_buf.clear();
|
||||
}
|
||||
|
||||
inline int CString::Remove(LPCTSTR pszText)
|
||||
// Removes each occurrence of the specified substring from the string.
|
||||
{
|
||||
assert(pszText);
|
||||
|
||||
int nCount = 0;
|
||||
size_t pos = 0;
|
||||
while ((pos = m_str.find(pszText, pos)) != std::string::npos)
|
||||
{
|
||||
m_str.erase(pos, lstrlen(pszText));
|
||||
++nCount;
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
inline int CString::Replace(TCHAR chOld, TCHAR chNew)
|
||||
// Replaces each occurance of the old character with the new character.
|
||||
{
|
||||
int nCount = 0;
|
||||
tString::iterator it = m_str.begin();
|
||||
while (it != m_str.end())
|
||||
{
|
||||
if (*it == chOld)
|
||||
{
|
||||
*it = chNew;
|
||||
++nCount;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
inline int CString::Replace(LPCTSTR pszOld, LPCTSTR pszNew)
|
||||
// Replaces each occurance of the old substring with the new substring.
|
||||
{
|
||||
assert(pszOld);
|
||||
assert(pszNew);
|
||||
|
||||
int nCount = 0;
|
||||
size_t pos = 0;
|
||||
while ((pos = m_str.find(pszOld, pos)) != std::string::npos)
|
||||
{
|
||||
m_str.replace(pos, lstrlen(pszOld), pszNew);
|
||||
pos += lstrlen(pszNew);
|
||||
++nCount;
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
inline CString CString::Right(int nCount) const
|
||||
// Extracts the right part of a string.
|
||||
{
|
||||
assert(nCount >= 0);
|
||||
|
||||
CString str;
|
||||
str.m_str.assign(c_str(), m_str.size() - nCount, nCount);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline BSTR CString::SetSysString(BSTR* pBstr) const
|
||||
// Sets an existing BSTR object to the string.
|
||||
{
|
||||
assert(pBstr);
|
||||
|
||||
if ( !::SysReAllocStringLen(pBstr, T2W(m_str.c_str()), (UINT)m_str.length()) )
|
||||
throw std::bad_alloc();
|
||||
|
||||
return *pBstr;
|
||||
}
|
||||
|
||||
inline CString CString::SpanExcluding(LPCTSTR pszText) const
|
||||
// Extracts characters from the string, starting with the first character,
|
||||
// that are not in the set of characters identified by pszCharSet.
|
||||
{
|
||||
assert (pszText);
|
||||
|
||||
CString str;
|
||||
size_t pos = 0;
|
||||
|
||||
while ((pos = m_str.find_first_not_of(pszText, pos)) != std::string::npos)
|
||||
{
|
||||
str.m_str.append(1, m_str[pos++]);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
inline CString CString::SpanIncluding(LPCTSTR pszText) const
|
||||
// Extracts a substring that contains only the characters in a set.
|
||||
{
|
||||
assert (pszText);
|
||||
|
||||
CString str;
|
||||
size_t pos = 0;
|
||||
|
||||
while ((pos = m_str.find_first_of(pszText, pos)) != std::string::npos)
|
||||
{
|
||||
str.m_str.append(1, m_str[pos++]);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
inline CString CString::Tokenize(LPCTSTR pszTokens, int& iStart) const
|
||||
// Extracts specified tokens in a target string.
|
||||
{
|
||||
assert(pszTokens);
|
||||
assert(iStart >= 0);
|
||||
|
||||
CString str;
|
||||
size_t pos1 = m_str.find_first_not_of(pszTokens, iStart);
|
||||
size_t pos2 = m_str.find_first_of(pszTokens, pos1);
|
||||
|
||||
iStart = (int)pos2 + 1;
|
||||
if (pos2 == m_str.npos)
|
||||
iStart = -1;
|
||||
|
||||
if (pos1 != m_str.npos)
|
||||
str.m_str = m_str.substr(pos1, pos2-pos1);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
inline void CString::Trim()
|
||||
// Trims all leading and trailing whitespace characters from the string.
|
||||
{
|
||||
TrimLeft();
|
||||
TrimRight();
|
||||
}
|
||||
|
||||
inline void CString::TrimLeft()
|
||||
// Trims leading whitespace characters from the string.
|
||||
{
|
||||
// This method is supported by the Borland 5.5 compiler
|
||||
tString::iterator iter;
|
||||
for (iter = m_str.begin(); iter < m_str.end(); ++iter)
|
||||
{
|
||||
if (!isspace(*iter))
|
||||
break;
|
||||
}
|
||||
|
||||
m_str.erase(m_str.begin(), iter);
|
||||
}
|
||||
|
||||
inline void CString::TrimLeft(TCHAR chTarget)
|
||||
// Trims the specified character from the beginning of the string.
|
||||
{
|
||||
m_str.erase(0, m_str.find_first_not_of(chTarget));
|
||||
}
|
||||
|
||||
inline void CString::TrimLeft(LPCTSTR pszTargets)
|
||||
// Trims the specified set of characters from the beginning of the string.
|
||||
{
|
||||
assert(pszTargets);
|
||||
m_str.erase(0, m_str.find_first_not_of(pszTargets));
|
||||
}
|
||||
|
||||
inline void CString::TrimRight()
|
||||
// Trims trailing whitespace characters from the string.
|
||||
{
|
||||
// This method is supported by the Borland 5.5 compiler
|
||||
tString::reverse_iterator riter;
|
||||
for (riter = m_str.rbegin(); riter < m_str.rend(); ++riter)
|
||||
{
|
||||
if (!isspace(*riter))
|
||||
break;
|
||||
}
|
||||
|
||||
m_str.erase(riter.base(), m_str.end());
|
||||
}
|
||||
|
||||
inline void CString::TrimRight(TCHAR chTarget)
|
||||
// Trims the specified character from the end of the string.
|
||||
{
|
||||
size_t pos = m_str.find_last_not_of(chTarget);
|
||||
if (pos != std::string::npos)
|
||||
m_str.erase(++pos);
|
||||
}
|
||||
|
||||
inline void CString::TrimRight(LPCTSTR pszTargets)
|
||||
// Trims the specified set of characters from the end of the string.
|
||||
{
|
||||
assert(pszTargets);
|
||||
|
||||
size_t pos = m_str.find_last_not_of(pszTargets);
|
||||
if (pos != std::string::npos)
|
||||
m_str.erase(++pos);
|
||||
}
|
||||
|
||||
inline void CString::Truncate(int nNewLength)
|
||||
// Reduces the length of the string to the specified amount.
|
||||
{
|
||||
if (nNewLength < GetLength())
|
||||
{
|
||||
assert(nNewLength >= 0);
|
||||
m_str.erase(nNewLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
// Global Functions
|
||||
//
|
||||
|
||||
// friend functions of CString
|
||||
inline CString operator + (const CString& string1, const CString& string2)
|
||||
{
|
||||
CString str(string1);
|
||||
str.m_str.append(string2.m_str);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline CString operator + (const CString& string, LPCTSTR pszText)
|
||||
{
|
||||
CString str(string);
|
||||
str.m_str.append(pszText);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline CString operator + (const CString& string, TCHAR ch)
|
||||
{
|
||||
CString str(string);
|
||||
str.m_str.append(1, ch);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline CString operator + (LPCTSTR pszText, const CString& string)
|
||||
{
|
||||
CString str(pszText);
|
||||
str.m_str.append(string);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline CString operator + (TCHAR ch, const CString& string)
|
||||
{
|
||||
CString str(ch);
|
||||
str.m_str.append(string);
|
||||
return str;
|
||||
}
|
||||
|
||||
// Global LoadString
|
||||
inline CString LoadString(UINT nID)
|
||||
{
|
||||
CString str;
|
||||
str.LoadString(nID);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif//_WIN32XX_CSTRING_H_
|
94
mmc_updater/depends/win32cpp/default_resource.h
Normal file
94
mmc_updater/depends/win32cpp/default_resource.h
Normal file
@ -0,0 +1,94 @@
|
||||
// This file contains the resource ID definitions for Win32++.
|
||||
|
||||
|
||||
// The resource ID for MENU, ICON, ToolBar Bitmap, Accelerator,
|
||||
// and Window Caption
|
||||
#define IDW_MAIN 51
|
||||
|
||||
// Resource ID for the About dialog
|
||||
#define IDW_ABOUT 52
|
||||
|
||||
// Resource IDs for menu items
|
||||
#define IDW_VIEW_TOOLBAR 53
|
||||
#define IDW_VIEW_STATUSBAR 54
|
||||
|
||||
// Resource IDs for the Command Bands
|
||||
#define IDW_CMD_BANDS 55
|
||||
#define IDW_MENUBAR 56
|
||||
#define IDW_TOOLBAR 57
|
||||
|
||||
// Resource ID for the Accelerator key
|
||||
#define IDW_QUIT 58
|
||||
|
||||
// Resource IDs for MDI menu items
|
||||
#define IDW_MDI_CASCADE 60
|
||||
#define IDW_MDI_TILE 61
|
||||
#define IDW_MDI_ARRANGE 62
|
||||
#define IDW_MDI_CLOSEALL 63
|
||||
#define IDW_FIRSTCHILD 64
|
||||
#define IDW_CHILD2 65
|
||||
#define IDW_CHILD3 66
|
||||
#define IDW_CHILD4 67
|
||||
#define IDW_CHILD5 68
|
||||
#define IDW_CHILD6 69
|
||||
#define IDW_CHILD7 70
|
||||
#define IDW_CHILD8 71
|
||||
#define IDW_CHILD9 72
|
||||
#define IDW_CHILD10 73
|
||||
|
||||
#define IDW_FILE_MRU_FILE1 75
|
||||
#define IDW_FILE_MRU_FILE2 76
|
||||
#define IDW_FILE_MRU_FILE3 77
|
||||
#define IDW_FILE_MRU_FILE4 78
|
||||
#define IDW_FILE_MRU_FILE5 79
|
||||
#define IDW_FILE_MRU_FILE6 80
|
||||
#define IDW_FILE_MRU_FILE7 81
|
||||
#define IDW_FILE_MRU_FILE8 82
|
||||
#define IDW_FILE_MRU_FILE9 83
|
||||
#define IDW_FILE_MRU_FILE10 84
|
||||
#define IDW_FILE_MRU_FILE11 85
|
||||
#define IDW_FILE_MRU_FILE12 86
|
||||
#define IDW_FILE_MRU_FILE13 87
|
||||
#define IDW_FILE_MRU_FILE14 88
|
||||
#define IDW_FILE_MRU_FILE15 89
|
||||
#define IDW_FILE_MRU_FILE16 90
|
||||
|
||||
// Cursor Resources
|
||||
#define IDW_SPLITH 91
|
||||
#define IDW_SPLITV 92
|
||||
#define IDW_TRACK4WAY 93
|
||||
|
||||
// Docking Bitmap Resources
|
||||
#define IDW_SDBOTTOM 94
|
||||
#define IDW_SDCENTER 95
|
||||
#define IDW_SDLEFT 96
|
||||
#define IDW_SDMIDDLE 97
|
||||
#define IDW_SDRIGHT 98
|
||||
#define IDW_SDTOP 99
|
||||
|
||||
|
||||
// A generic ID for any static control
|
||||
#ifndef IDC_STATIC
|
||||
#define IDC_STATIC -1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Notes about Resource IDs
|
||||
// * In general, resource IDs can have values from 1 to 65535. Programs with
|
||||
// resource IDs higher than 65535 aren't supported on Windows 95
|
||||
//
|
||||
// * CMenuBar uses resource IDs beginning from 0 for the top level menu items.
|
||||
// Win32++ leaves resource IDs below 51 unallocated for top level menu items.
|
||||
//
|
||||
// * Windows uses the icon with the lowest resource ID as the application's
|
||||
// icon. The application's icon is IDW_MAIN, which is the first resource ID
|
||||
// defined by Win32++.
|
||||
//
|
||||
// * When more than one static control is used in a dialog, the controls should
|
||||
// have a unique ID, unless a resource ID of -1 is used.
|
||||
//
|
||||
// * Users of Win32++ are advised to begin their resource IDs from 120 to
|
||||
// allow for possible expansion of Win32++.
|
||||
|
||||
|
250
mmc_updater/depends/win32cpp/default_resource.rc
Normal file
250
mmc_updater/depends/win32cpp/default_resource.rc
Normal file
@ -0,0 +1,250 @@
|
||||
// An example of a resource file
|
||||
//
|
||||
|
||||
#include "resource.h"
|
||||
#include "windows.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RT_MANIFEST
|
||||
//
|
||||
|
||||
1 24 DISCARDABLE "res/Win32++.manifest"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Menu
|
||||
//
|
||||
|
||||
|
||||
IDW_MAIN MENU
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "New &View", IDM_FILE_NEWVIEW
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Recent Files", IDW_FILE_MRU_FILE1, GRAYED
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "E&xit", IDM_FILE_EXIT
|
||||
END
|
||||
POPUP "&Edit"
|
||||
BEGIN
|
||||
MENUITEM "Undo\tCtrl+Z", IDM_EDIT_UNDO
|
||||
MENUITEM "Redo\tShift+Ctrl+Z", IDM_EDIT_REDO
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Cut\tCtrl+X", IDM_EDIT_CUT
|
||||
MENUITEM "Copy\tCtrl+C", IDM_EDIT_COPY
|
||||
MENUITEM "Paste\tCtrl+V", IDM_EDIT_PASTE
|
||||
MENUITEM "Delete\tDel", IDM_EDIT_DELETE
|
||||
END
|
||||
POPUP "&View"
|
||||
BEGIN
|
||||
MENUITEM "&Tool Bar", IDW_VIEW_TOOLBAR, CHECKED
|
||||
MENUITEM "&Status Bar", IDW_VIEW_STATUSBAR, CHECKED
|
||||
END
|
||||
POPUP "&Help"
|
||||
BEGIN
|
||||
MENUITEM "&About", IDM_HELP_ABOUT
|
||||
END
|
||||
END
|
||||
|
||||
MDIMENUVIEW MENU
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "New &View", IDM_FILE_NEWVIEW
|
||||
MENUITEM "&Close", IDM_FILE_CLOSE
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "E&xit", IDM_FILE_EXIT
|
||||
END
|
||||
POPUP "&Edit"
|
||||
BEGIN
|
||||
MENUITEM "Undo", IDM_EDIT_UNDO
|
||||
MENUITEM "Redo", IDM_EDIT_REDO
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Cu&t", IDM_EDIT_CUT
|
||||
MENUITEM "&Copy", IDM_EDIT_COPY
|
||||
MENUITEM "&Paste", IDM_EDIT_PASTE
|
||||
MENUITEM "De&lete", IDM_EDIT_DELETE
|
||||
END
|
||||
POPUP "&View"
|
||||
BEGIN
|
||||
MENUITEM "Tool Bar", IDW_VIEW_TOOLBAR, CHECKED
|
||||
MENUITEM "Status Bar", IDW_VIEW_STATUSBAR, CHECKED
|
||||
END
|
||||
POPUP "&Color"
|
||||
BEGIN
|
||||
MENUITEM "&Black", IDM_COLOR_BLACK
|
||||
MENUITEM "&Red", IDM_COLOR_RED
|
||||
MENUITEM "&Green", IDM_COLOR_GREEN
|
||||
MENUITEM "B&lue", IDM_COLOR_BLUE
|
||||
MENUITEM "&White", IDM_COLOR_WHITE
|
||||
END
|
||||
POPUP "&Window"
|
||||
BEGIN
|
||||
MENUITEM "&Cascade\tShift+F5", IDW_WINDOW_CASCADE
|
||||
MENUITEM "&Tile\tShift+F4", IDW_WINDOW_TILE
|
||||
MENUITEM "Arrange &Icons", IDW_WINDOW_ARRANGE
|
||||
MENUITEM "Close &All", IDW_WINDOW_CLOSEALL
|
||||
END
|
||||
POPUP "&Help"
|
||||
BEGIN
|
||||
MENUITEM "About", IDM_HELP_ABOUT
|
||||
END
|
||||
END
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDW_MAIN ICON "res/mdi.ico"
|
||||
IDI_VIEW ICON "res/view.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bitmap
|
||||
//
|
||||
|
||||
IDW_MAIN BITMAP "res/toolbar.bmp"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDW_ABOUT DIALOGEX 0, 0, 186, 90
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
|
||||
WS_SYSMENU
|
||||
CAPTION "About"
|
||||
FONT 8, "MS Shell Dlg", 400, 0
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "OK",IDOK,68,49,50,14
|
||||
CTEXT "MDI Frame",IDC_STATIC,60,22,64,11
|
||||
ICON IDW_MAIN,0,4,4,20,20
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Accelerator
|
||||
//
|
||||
|
||||
IDW_MAIN ACCELERATORS
|
||||
BEGIN
|
||||
"N", IDM_FILE_NEW, VIRTKEY, CONTROL, NOINVERT
|
||||
"O", IDM_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
|
||||
"P", IDM_FILE_PRINT, VIRTKEY, CONTROL, NOINVERT
|
||||
"S", IDM_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
|
||||
"C", IDM_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
|
||||
"X", IDM_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT
|
||||
"V", IDM_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
|
||||
"Z", IDM_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT
|
||||
"Y", IDM_EDIT_REDO, VIRTKEY, SHIFT, CONTROL, NOINVERT
|
||||
VK_DELETE, IDM_EDIT_DELETE, VIRTKEY, NOINVERT
|
||||
END
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDW_MAIN "MDI Frame"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDM_FILE_NEW "Create a New Document"
|
||||
IDM_FILE_OPEN "Open Existing Document"
|
||||
IDM_FILE_SAVE "Save the Document"
|
||||
IDM_FILE_SAVEAS "Save the Document with a new name"
|
||||
IDM_FILE_PRINT "Print the Document"
|
||||
IDM_FILE_EXIT "End the Program"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDM_EDIT_UNDO "Undo the last action"
|
||||
IDM_EDIT_REDO "Redo the previously undone action"
|
||||
IDM_EDIT_CUT "Cut the Selected Contents to the Clipboard"
|
||||
IDM_EDIT_COPY "Copy the Selected Contents to the Clipboard"
|
||||
IDM_EDIT_PASTE "Paste the Clipboard Contents to the Document"
|
||||
IDM_EDIT_DELETE "Erase the selected Contents"
|
||||
IDW_VIEW_TOOLBAR "Show or hide the tool bar"
|
||||
IDW_VIEW_STATUSBAR "Show or hide the status bar"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDM_HELP_ABOUT "Display Information about this program"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDW_FIRSTCHILD "Activate this window"
|
||||
IDW_CHILD2 "Activate this window"
|
||||
IDW_CHILD3 "Activate this window"
|
||||
IDW_CHILD4 "Activate this window"
|
||||
IDW_CHILD5 "Activate this window"
|
||||
IDW_CHILD6 "Activate this window"
|
||||
IDW_CHILD7 "Activate this window"
|
||||
IDW_CHILD8 "Activate this window"
|
||||
IDW_CHILD9 "Activate this window"
|
||||
IDW_CHILD10 "Select a window"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDM_FILE_NEWVIEW "Create View MDI Child"
|
||||
IDM_FILE_CLOSE "Close MDI Window"
|
||||
IDM_COLOR_BLACK "Use Black Printing"
|
||||
IDM_COLOR_RED "Use Red Printing"
|
||||
IDM_COLOR_GREEN "Use Green Printing"
|
||||
IDM_COLOR_BLUE "Use Blue Printing"
|
||||
IDM_COLOR_WHITE "Use White Printing"
|
||||
IDW_WINDOW_CASCADE "Cascade MDI Windows"
|
||||
IDW_WINDOW_TILE "Tile MDI Windows"
|
||||
IDW_WINDOW_ARRANGE "Arrange Icons"
|
||||
IDW_WINDOW_CLOSEALL "Close All MDI Windows"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
SC_CLOSE "Close the Window"
|
||||
SC_MAXIMIZE "Maximize the Window"
|
||||
SC_MINIMIZE "Minimize the WIndow"
|
||||
SC_MOVE "Move the Window"
|
||||
SC_NEXTWINDOW "Select Next Window"
|
||||
SC_PREVWINDOW "Select Previous Window"
|
||||
SC_RESTORE "Restore the Window"
|
||||
SC_SIZE "Resize the Window"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDW_FILE_MRU_FILE1 "Open this document"
|
||||
IDW_FILE_MRU_FILE2 "Open this document"
|
||||
IDW_FILE_MRU_FILE3 "Open this document"
|
||||
IDW_FILE_MRU_FILE4 "Open this document"
|
||||
IDW_FILE_MRU_FILE5 "Open this document"
|
||||
IDW_FILE_MRU_FILE6 "Open this document"
|
||||
IDW_FILE_MRU_FILE7 "Open this document"
|
||||
IDW_FILE_MRU_FILE8 "Open this document"
|
||||
IDW_FILE_MRU_FILE9 "Open this document"
|
||||
IDW_FILE_MRU_FILE10 "Open this document"
|
||||
IDW_FILE_MRU_FILE11 "Open this document"
|
||||
IDW_FILE_MRU_FILE12 "Open this document"
|
||||
IDW_FILE_MRU_FILE13 "Open this document"
|
||||
IDW_FILE_MRU_FILE14 "Open this document"
|
||||
IDW_FILE_MRU_FILE15 "Open this document"
|
||||
IDW_FILE_MRU_FILE16 "Open this document"
|
||||
END
|
||||
|
||||
|
876
mmc_updater/depends/win32cpp/dialog.h
Normal file
876
mmc_updater/depends/win32cpp/dialog.h
Normal file
@ -0,0 +1,876 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// dialog.h
|
||||
// Declaration of the CDialog class
|
||||
|
||||
// CDialog adds support for dialogs to Win32++. Dialogs are specialised
|
||||
// windows which are a parent window for common controls. Common controls
|
||||
// are special window types such as buttons, edit controls, tree views,
|
||||
// list views, static text etc.
|
||||
|
||||
// The layout of a dialog is typically defined in a resource script file
|
||||
// (often Resource.rc). While this script file can be constructed manually,
|
||||
// it is often created using a resource editor. If your compiler doesn't
|
||||
// include a resource editor, you might find ResEdit useful. It is a free
|
||||
// resource editor available for download at:
|
||||
// http://www.resedit.net/
|
||||
|
||||
// CDialog supports modal and modeless dialogs. It also supports the creation
|
||||
// of dialogs defined in a resource script file, as well as those defined in
|
||||
// a dialog template.
|
||||
|
||||
// Use the Dialog generic program as the starting point for your own dialog
|
||||
// applications.
|
||||
// The DlgSubclass sample demonstrates how to use subclassing to customise
|
||||
// the behaviour of common controls in a dialog.
|
||||
|
||||
|
||||
#ifndef _WIN32XX_DIALOG_H_
|
||||
#define _WIN32XX_DIALOG_H_
|
||||
|
||||
#include "wincore.h"
|
||||
|
||||
#ifndef SWP_NOCOPYBITS
|
||||
#define SWP_NOCOPYBITS 0x0100
|
||||
#endif
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
class CDialog : public CWnd
|
||||
{
|
||||
public:
|
||||
CDialog(UINT nResID, CWnd* pParent = NULL);
|
||||
CDialog(LPCTSTR lpszResName, CWnd* pParent = NULL);
|
||||
CDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent = NULL);
|
||||
virtual ~CDialog();
|
||||
|
||||
// You probably won't need to override these functions
|
||||
virtual void AttachItem(int nID, CWnd& Wnd);
|
||||
virtual HWND Create(CWnd* pParent = NULL);
|
||||
virtual INT_PTR DoModal();
|
||||
virtual HWND DoModeless();
|
||||
virtual void SetDlgParent(CWnd* pParent);
|
||||
BOOL IsModal() const { return m_IsModal; }
|
||||
BOOL IsIndirect() const { return (NULL != m_lpTemplate); }
|
||||
|
||||
protected:
|
||||
// These are the functions you might wish to override
|
||||
virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
virtual INT_PTR DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
virtual void EndDialog(INT_PTR nResult);
|
||||
virtual void OnCancel();
|
||||
virtual BOOL OnInitDialog();
|
||||
virtual void OnOK();
|
||||
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||||
|
||||
// Can't override these functions
|
||||
static INT_PTR CALLBACK StaticDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
static LRESULT CALLBACK StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
private:
|
||||
CDialog(const CDialog&); // Disable copy construction
|
||||
CDialog& operator = (const CDialog&); // Disable assignment operator
|
||||
|
||||
BOOL m_IsModal; // a flag for modal dialogs
|
||||
LPCTSTR m_lpszResName; // the resource name for the dialog
|
||||
LPCDLGTEMPLATE m_lpTemplate; // the dialog template for indirect dialogs
|
||||
HWND m_hParent; // handle to the dialogs's parent window
|
||||
};
|
||||
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
|
||||
//////////////////////////////////////
|
||||
// Declaration of the CResizer class
|
||||
//
|
||||
// The CResizer class can be used to rearrange a dialog's child
|
||||
// windows when the dialog is resized.
|
||||
|
||||
// To use CResizer, follow the following steps:
|
||||
// 1) Use Initialize to specify the dialog's CWnd, and min and max size.
|
||||
// 3) Use AddChild for each child window
|
||||
// 4) Call HandleMessage from within DialogProc.
|
||||
//
|
||||
|
||||
// Resize Dialog Styles
|
||||
#define RD_STRETCH_WIDTH 0x0001 // The item has a variable width
|
||||
#define RD_STRETCH_HEIGHT 0x0002 // The item has a variable height
|
||||
|
||||
// Resize Dialog alignments
|
||||
enum Alignment { topleft, topright, bottomleft, bottomright };
|
||||
|
||||
class CResizer
|
||||
{
|
||||
public:
|
||||
CResizer() : m_pParent(0), m_xScrollPos(0), m_yScrollPos(0) {}
|
||||
virtual ~CResizer() {}
|
||||
|
||||
virtual void AddChild(CWnd* pWnd, Alignment corner, DWORD dwStyle);
|
||||
virtual void AddChild(HWND hWnd, Alignment corner, DWORD dwStyle);
|
||||
virtual void HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
virtual void Initialize(CWnd* pParent, RECT rcMin, RECT rcMax = CRect(0,0,0,0));
|
||||
virtual void OnHScroll(WPARAM wParam, LPARAM lParam);
|
||||
virtual void OnVScroll(WPARAM wParam, LPARAM lParam);
|
||||
virtual void RecalcLayout();
|
||||
CRect GetMinRect() const { return m_rcMin; }
|
||||
CRect GetMaxRect() const { return m_rcMax; }
|
||||
|
||||
struct ResizeData
|
||||
{
|
||||
CRect rcInit;
|
||||
CRect rcOld;
|
||||
Alignment corner;
|
||||
BOOL bFixedWidth;
|
||||
BOOL bFixedHeight;
|
||||
HWND hWnd;
|
||||
};
|
||||
|
||||
private:
|
||||
CWnd* m_pParent;
|
||||
std::vector<ResizeData> m_vResizeData;
|
||||
|
||||
CRect m_rcInit;
|
||||
CRect m_rcMin;
|
||||
CRect m_rcMax;
|
||||
|
||||
int m_xScrollPos;
|
||||
int m_yScrollPos;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
////////////////////////////////////
|
||||
// Definitions for the CDialog class
|
||||
//
|
||||
inline CDialog::CDialog(LPCTSTR lpszResName, CWnd* pParent/* = NULL*/)
|
||||
: m_IsModal(TRUE), m_lpszResName(lpszResName), m_lpTemplate(NULL)
|
||||
{
|
||||
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
||||
::InitCommonControls();
|
||||
}
|
||||
|
||||
inline CDialog::CDialog(UINT nResID, CWnd* pParent/* = NULL*/)
|
||||
: m_IsModal(TRUE), m_lpszResName(MAKEINTRESOURCE (nResID)), m_lpTemplate(NULL)
|
||||
{
|
||||
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
||||
::InitCommonControls();
|
||||
}
|
||||
|
||||
//For indirect dialogs - created from a dialog box template in memory.
|
||||
inline CDialog::CDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent/* = NULL*/)
|
||||
: m_IsModal(TRUE), m_lpszResName(NULL), m_lpTemplate(lpTemplate)
|
||||
{
|
||||
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
||||
::InitCommonControls();
|
||||
}
|
||||
|
||||
inline CDialog::~CDialog()
|
||||
{
|
||||
if (m_hWnd != NULL)
|
||||
{
|
||||
if (IsModal())
|
||||
::EndDialog(m_hWnd, 0);
|
||||
else
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CDialog::AttachItem(int nID, CWnd& Wnd)
|
||||
// Attach a dialog item to a CWnd
|
||||
{
|
||||
Wnd.AttachDlgItem(nID, this);
|
||||
}
|
||||
|
||||
inline HWND CDialog::Create(CWnd* pParent /* = NULL */)
|
||||
{
|
||||
// Allow a dialog to be used as a child window
|
||||
|
||||
assert(GetApp());
|
||||
SetDlgParent(pParent);
|
||||
return DoModeless();
|
||||
}
|
||||
|
||||
inline INT_PTR CDialog::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Override this function in your class derrived from CDialog if you wish to handle messages
|
||||
// A typical function might look like this:
|
||||
|
||||
// switch (uMsg)
|
||||
// {
|
||||
// case MESSAGE1: // Some Windows API message
|
||||
// OnMessage1(); // A user defined function
|
||||
// break; // Also do default processing
|
||||
// case MESSAGE2:
|
||||
// OnMessage2();
|
||||
// return x; // Don't do default processing, but instead return
|
||||
// // a value recommended by the Windows API documentation
|
||||
// }
|
||||
|
||||
// Always pass unhandled messages on to DialogProcDefault
|
||||
return DialogProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
inline INT_PTR CDialog::DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
// All DialogProc functions should pass unhandled messages to this function
|
||||
{
|
||||
LRESULT lr = 0;
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case UWM_CLEANUPTEMPS:
|
||||
{
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
pTLSData->vTmpWnds.clear();
|
||||
}
|
||||
break;
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
// Center the dialog
|
||||
CenterWindow();
|
||||
}
|
||||
return OnInitDialog();
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD (wParam))
|
||||
{
|
||||
case IDOK:
|
||||
OnOK();
|
||||
return TRUE;
|
||||
case IDCANCEL:
|
||||
OnCancel();
|
||||
return TRUE;
|
||||
default:
|
||||
{
|
||||
// Refelect this message if it's from a control
|
||||
CWnd* pWnd = GetApp()->GetCWndFromMap((HWND)lParam);
|
||||
if (pWnd != NULL)
|
||||
lr = pWnd->OnCommand(wParam, lParam);
|
||||
|
||||
// Handle user commands
|
||||
if (!lr)
|
||||
lr = OnCommand(wParam, lParam);
|
||||
|
||||
if (lr) return 0L;
|
||||
}
|
||||
break; // Some commands require default processing
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_NOTIFY:
|
||||
{
|
||||
// Do Notification reflection if it came from a CWnd object
|
||||
HWND hwndFrom = ((LPNMHDR)lParam)->hwndFrom;
|
||||
CWnd* pWndFrom = GetApp()->GetCWndFromMap(hwndFrom);
|
||||
|
||||
if (pWndFrom != NULL)
|
||||
lr = pWndFrom->OnNotifyReflect(wParam, lParam);
|
||||
else
|
||||
{
|
||||
// Some controls (eg ListView) have child windows.
|
||||
// Reflect those notifications too.
|
||||
CWnd* pWndFromParent = GetApp()->GetCWndFromMap(::GetParent(hwndFrom));
|
||||
if (pWndFromParent != NULL)
|
||||
lr = pWndFromParent->OnNotifyReflect(wParam, lParam);
|
||||
}
|
||||
|
||||
// Handle user notifications
|
||||
if (!lr) lr = OnNotify(wParam, lParam);
|
||||
|
||||
// Set the return code for notifications
|
||||
if (IsWindow())
|
||||
SetWindowLongPtr(DWLP_MSGRESULT, (LONG_PTR)lr);
|
||||
|
||||
return (BOOL)lr;
|
||||
}
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (::GetUpdateRect(m_hWnd, NULL, FALSE))
|
||||
{
|
||||
CPaintDC dc(this);
|
||||
OnDraw(&dc);
|
||||
}
|
||||
else
|
||||
// RedrawWindow can require repainting without an update rect
|
||||
{
|
||||
CClientDC dc(this);
|
||||
OnDraw(&dc);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
{
|
||||
CDC dc((HDC)wParam);
|
||||
BOOL bResult = OnEraseBkgnd(&dc);
|
||||
dc.Detach();
|
||||
if (bResult) return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
// A set of messages to be reflected back to the control that generated them
|
||||
case WM_CTLCOLORBTN:
|
||||
case WM_CTLCOLOREDIT:
|
||||
case WM_CTLCOLORDLG:
|
||||
case WM_CTLCOLORLISTBOX:
|
||||
case WM_CTLCOLORSCROLLBAR:
|
||||
case WM_CTLCOLORSTATIC:
|
||||
case WM_DRAWITEM:
|
||||
case WM_MEASUREITEM:
|
||||
case WM_DELETEITEM:
|
||||
case WM_COMPAREITEM:
|
||||
case WM_CHARTOITEM:
|
||||
case WM_VKEYTOITEM:
|
||||
case WM_HSCROLL:
|
||||
case WM_VSCROLL:
|
||||
case WM_PARENTNOTIFY:
|
||||
return MessageReflect(m_hWnd, uMsg, wParam, lParam);
|
||||
|
||||
} // switch(uMsg)
|
||||
return FALSE;
|
||||
|
||||
} // INT_PTR CALLBACK CDialog::DialogProc(...)
|
||||
|
||||
inline INT_PTR CDialog::DoModal()
|
||||
{
|
||||
// Create a modal dialog
|
||||
// A modal dialog box must be closed by the user before the application continues
|
||||
|
||||
assert( GetApp() ); // Test if Win32++ has been started
|
||||
assert(!::IsWindow(m_hWnd)); // Only one window per CWnd instance allowed
|
||||
|
||||
INT_PTR nResult = 0;
|
||||
|
||||
try
|
||||
{
|
||||
m_IsModal=TRUE;
|
||||
|
||||
// Ensure this thread has the TLS index set
|
||||
TLSData* pTLSData = GetApp()->SetTlsIndex();
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
BOOL IsHookedHere = FALSE;
|
||||
if (NULL == pTLSData->hHook )
|
||||
{
|
||||
pTLSData->hHook = ::SetWindowsHookEx(WH_MSGFILTER, (HOOKPROC)StaticMsgHook, NULL, ::GetCurrentThreadId());
|
||||
IsHookedHere = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
HINSTANCE hInstance = GetApp()->GetInstanceHandle();
|
||||
pTLSData->pCWnd = this;
|
||||
|
||||
// Create a modal dialog
|
||||
if (IsIndirect())
|
||||
nResult = ::DialogBoxIndirect(hInstance, m_lpTemplate, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
||||
else
|
||||
{
|
||||
if (::FindResource(GetApp()->GetResourceHandle(), m_lpszResName, RT_DIALOG))
|
||||
hInstance = GetApp()->GetResourceHandle();
|
||||
nResult = ::DialogBox(hInstance, m_lpszResName, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
||||
}
|
||||
|
||||
// Tidy up
|
||||
m_hWnd = NULL;
|
||||
pTLSData->pCWnd = NULL;
|
||||
GetApp()->CleanupTemps();
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
if (IsHookedHere)
|
||||
{
|
||||
::UnhookWindowsHookEx(pTLSData->hHook);
|
||||
pTLSData->hHook = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nResult == -1)
|
||||
throw CWinException(_T("Failed to create modal dialog box"));
|
||||
|
||||
}
|
||||
|
||||
catch (const CWinException &e)
|
||||
{
|
||||
TRACE(_T("\n*** Failed to create dialog ***\n"));
|
||||
e.what(); // Display the last error message.
|
||||
|
||||
// eat the exception (don't rethrow)
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline HWND CDialog::DoModeless()
|
||||
{
|
||||
assert( GetApp() ); // Test if Win32++ has been started
|
||||
assert(!::IsWindow(m_hWnd)); // Only one window per CWnd instance allowed
|
||||
|
||||
try
|
||||
{
|
||||
m_IsModal=FALSE;
|
||||
|
||||
// Ensure this thread has the TLS index set
|
||||
TLSData* pTLSData = GetApp()->SetTlsIndex();
|
||||
|
||||
// Store the CWnd pointer in Thread Local Storage
|
||||
pTLSData->pCWnd = this;
|
||||
|
||||
HINSTANCE hInstance = GetApp()->GetInstanceHandle();
|
||||
|
||||
// Create a modeless dialog
|
||||
if (IsIndirect())
|
||||
m_hWnd = ::CreateDialogIndirect(hInstance, m_lpTemplate, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
||||
else
|
||||
{
|
||||
if (::FindResource(GetApp()->GetResourceHandle(), m_lpszResName, RT_DIALOG))
|
||||
hInstance = GetApp()->GetResourceHandle();
|
||||
|
||||
m_hWnd = ::CreateDialog(hInstance, m_lpszResName, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
||||
}
|
||||
|
||||
// Tidy up
|
||||
pTLSData->pCWnd = NULL;
|
||||
|
||||
// Now handle dialog creation failure
|
||||
if (!m_hWnd)
|
||||
throw CWinException(_T("Failed to create dialog"));
|
||||
}
|
||||
|
||||
catch (const CWinException &e)
|
||||
{
|
||||
TRACE(_T("\n*** Failed to create dialog ***\n"));
|
||||
e.what(); // Display the last error message.
|
||||
|
||||
// eat the exception (don't rethrow)
|
||||
}
|
||||
|
||||
return m_hWnd;
|
||||
}
|
||||
|
||||
inline void CDialog::EndDialog(INT_PTR nResult)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
if (IsModal())
|
||||
::EndDialog(m_hWnd, nResult);
|
||||
else
|
||||
Destroy();
|
||||
|
||||
m_hWnd = NULL;
|
||||
}
|
||||
|
||||
inline void CDialog::OnCancel()
|
||||
{
|
||||
// Override to customize OnCancel behaviour
|
||||
EndDialog(IDCANCEL);
|
||||
}
|
||||
|
||||
inline BOOL CDialog::OnInitDialog()
|
||||
{
|
||||
// Called when the dialog is initialized
|
||||
// Override it in your derived class to automatically perform tasks
|
||||
// The return value is used by WM_INITDIALOG
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
inline void CDialog::OnOK()
|
||||
{
|
||||
// Override to customize OnOK behaviour
|
||||
EndDialog(IDOK);
|
||||
}
|
||||
|
||||
inline BOOL CDialog::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
// allow the dialog to translate keyboard input
|
||||
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
|
||||
{
|
||||
// Process dialog keystrokes for modeless dialogs
|
||||
if (!IsModal())
|
||||
{
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
if (NULL == pTLSData->hHook)
|
||||
{
|
||||
if (IsDialogMessage(pMsg))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A modal message loop is running so we can't do IsDialogMessage.
|
||||
// Avoid having modal dialogs create other windows, because those
|
||||
// windows will then use the modal dialog's special message loop.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline void CDialog::SetDlgParent(CWnd* pParent)
|
||||
// Allows the parent of the dialog to be set before the dialog is created
|
||||
{
|
||||
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
||||
}
|
||||
|
||||
inline INT_PTR CALLBACK CDialog::StaticDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Find the CWnd pointer mapped to this HWND
|
||||
CDialog* w = (CDialog*)GetApp()->GetCWndFromMap(hWnd);
|
||||
if (0 == w)
|
||||
{
|
||||
// The HWND wasn't in the map, so add it now
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
assert(pTLSData);
|
||||
|
||||
// Retrieve pointer to CWnd object from Thread Local Storage TLS
|
||||
w = (CDialog*)pTLSData->pCWnd;
|
||||
assert(w);
|
||||
pTLSData->pCWnd = NULL;
|
||||
|
||||
// Store the Window pointer into the HWND map
|
||||
w->m_hWnd = hWnd;
|
||||
w->AddToMap();
|
||||
}
|
||||
|
||||
return w->DialogProc(uMsg, wParam, lParam);
|
||||
|
||||
} // INT_PTR CALLBACK CDialog::StaticDialogProc(...)
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
inline LRESULT CALLBACK CDialog::StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Used by Modal Dialogs to PreTranslate Messages
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
|
||||
if (nCode == MSGF_DIALOGBOX)
|
||||
{
|
||||
MSG* lpMsg = (MSG*) lParam;
|
||||
|
||||
// only pre-translate keyboard events
|
||||
if ((lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST))
|
||||
{
|
||||
for (HWND hWnd = lpMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
|
||||
{
|
||||
CDialog* pDialog = (CDialog*)GetApp()->GetCWndFromMap(hWnd);
|
||||
if (pDialog && (lstrcmp(pDialog->GetClassName(), _T("#32770")) == 0)) // only for dialogs
|
||||
{
|
||||
pDialog->PreTranslateMessage(lpMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ::CallNextHookEx(pTLSData->hHook, nCode, wParam, lParam);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
|
||||
/////////////////////////////////////
|
||||
// Definitions for the CResizer class
|
||||
//
|
||||
|
||||
void inline CResizer::AddChild(CWnd* pWnd, Alignment corner, DWORD dwStyle)
|
||||
// Adds a child window (usually a dialog control) to the set of windows managed by
|
||||
// the Resizer.
|
||||
//
|
||||
// The alignment corner should be set to the closest corner of the dialog. Allowed
|
||||
// values are topleft, topright, bottomleft, and bottomright.
|
||||
// Set bFixedWidth to TRUE if the width should be fixed instead of variable.
|
||||
// Set bFixedHeight to TRUE if the height should be fixed instead of variable.
|
||||
{
|
||||
ResizeData rd;
|
||||
rd.corner = corner;
|
||||
rd.bFixedWidth = !(dwStyle & RD_STRETCH_WIDTH);
|
||||
rd.bFixedHeight = !(dwStyle & RD_STRETCH_HEIGHT);
|
||||
CRect rcInit = pWnd->GetWindowRect();
|
||||
m_pParent->ScreenToClient(rcInit);
|
||||
rd.rcInit = rcInit;
|
||||
rd.hWnd = pWnd->GetHwnd();
|
||||
|
||||
m_vResizeData.insert(m_vResizeData.begin(), rd);
|
||||
}
|
||||
|
||||
void inline CResizer::AddChild(HWND hWnd, Alignment corner, DWORD dwStyle)
|
||||
// Adds a child window (usually a dialog control) to the set of windows managed by
|
||||
// the Resizer.
|
||||
{
|
||||
AddChild(FromHandle(hWnd), corner, dwStyle);
|
||||
}
|
||||
|
||||
inline void CResizer::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_SIZE:
|
||||
RecalcLayout();
|
||||
break;
|
||||
|
||||
case WM_HSCROLL:
|
||||
if (0 == lParam)
|
||||
OnHScroll(wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_VSCROLL:
|
||||
if (0 == lParam)
|
||||
OnVScroll(wParam, lParam);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void inline CResizer::Initialize(CWnd* pParent, RECT rcMin, RECT rcMax)
|
||||
// Sets up the Resizer by specifying the parent window (usually a dialog),
|
||||
// and the minimum and maximum allowed rectangle sizes.
|
||||
{
|
||||
assert (NULL != pParent);
|
||||
|
||||
m_pParent = pParent;
|
||||
m_rcInit = pParent->GetClientRect();
|
||||
m_rcMin = rcMin;
|
||||
m_rcMax = rcMax;
|
||||
|
||||
// Add scroll bar support to the parent window
|
||||
DWORD dwStyle = (DWORD)m_pParent->GetClassLongPtr(GCL_STYLE);
|
||||
dwStyle |= WS_HSCROLL | WS_VSCROLL;
|
||||
m_pParent->SetClassLongPtr(GCL_STYLE, dwStyle);
|
||||
}
|
||||
|
||||
void inline CResizer::OnHScroll(WPARAM wParam, LPARAM /*lParam*/)
|
||||
{
|
||||
int xNewPos;
|
||||
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case SB_PAGEUP: // User clicked the scroll bar shaft left of the scroll box.
|
||||
xNewPos = m_xScrollPos - 50;
|
||||
break;
|
||||
|
||||
case SB_PAGEDOWN: // User clicked the scroll bar shaft right of the scroll box.
|
||||
xNewPos = m_xScrollPos + 50;
|
||||
break;
|
||||
|
||||
case SB_LINEUP: // User clicked the left arrow.
|
||||
xNewPos = m_xScrollPos - 5;
|
||||
break;
|
||||
|
||||
case SB_LINEDOWN: // User clicked the right arrow.
|
||||
xNewPos = m_xScrollPos + 5;
|
||||
break;
|
||||
|
||||
case SB_THUMBPOSITION: // User dragged the scroll box.
|
||||
xNewPos = HIWORD(wParam);
|
||||
break;
|
||||
|
||||
case SB_THUMBTRACK: // User dragging the scroll box.
|
||||
xNewPos = HIWORD(wParam);
|
||||
break;
|
||||
|
||||
default:
|
||||
xNewPos = m_xScrollPos;
|
||||
}
|
||||
|
||||
// Scroll the window.
|
||||
xNewPos = MAX(0, xNewPos);
|
||||
xNewPos = MIN( xNewPos, GetMinRect().Width() - m_pParent->GetClientRect().Width() );
|
||||
int xDelta = xNewPos - m_xScrollPos;
|
||||
m_xScrollPos = xNewPos;
|
||||
m_pParent->ScrollWindow(-xDelta, 0, NULL, NULL);
|
||||
|
||||
// Reset the scroll bar.
|
||||
SCROLLINFO si = {0};
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_POS;
|
||||
si.nPos = m_xScrollPos;
|
||||
m_pParent->SetScrollInfo(SB_HORZ, si, TRUE);
|
||||
}
|
||||
|
||||
void inline CResizer::OnVScroll(WPARAM wParam, LPARAM /*lParam*/)
|
||||
{
|
||||
int yNewPos;
|
||||
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case SB_PAGEUP: // User clicked the scroll bar shaft above the scroll box.
|
||||
yNewPos = m_yScrollPos - 50;
|
||||
break;
|
||||
|
||||
case SB_PAGEDOWN: // User clicked the scroll bar shaft below the scroll box.
|
||||
yNewPos = m_yScrollPos + 50;
|
||||
break;
|
||||
|
||||
case SB_LINEUP: // User clicked the top arrow.
|
||||
yNewPos = m_yScrollPos - 5;
|
||||
break;
|
||||
|
||||
case SB_LINEDOWN: // User clicked the bottom arrow.
|
||||
yNewPos = m_yScrollPos + 5;
|
||||
break;
|
||||
|
||||
case SB_THUMBPOSITION: // User dragged the scroll box.
|
||||
yNewPos = HIWORD(wParam);
|
||||
break;
|
||||
|
||||
case SB_THUMBTRACK: // User dragging the scroll box.
|
||||
yNewPos = HIWORD(wParam);
|
||||
break;
|
||||
|
||||
default:
|
||||
yNewPos = m_yScrollPos;
|
||||
}
|
||||
|
||||
// Scroll the window.
|
||||
yNewPos = MAX(0, yNewPos);
|
||||
yNewPos = MIN( yNewPos, GetMinRect().Height() - m_pParent->GetClientRect().Height() );
|
||||
int yDelta = yNewPos - m_yScrollPos;
|
||||
m_yScrollPos = yNewPos;
|
||||
m_pParent->ScrollWindow(0, -yDelta, NULL, NULL);
|
||||
|
||||
// Reset the scroll bar.
|
||||
SCROLLINFO si = {0};
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_POS;
|
||||
si.nPos = m_yScrollPos;
|
||||
m_pParent->SetScrollInfo(SB_VERT, si, TRUE);
|
||||
}
|
||||
|
||||
void inline CResizer::RecalcLayout()
|
||||
// Repositions the child windows. Call this function when handling
|
||||
// the WM_SIZE message in the parent window.
|
||||
{
|
||||
assert (m_rcInit.Width() > 0 && m_rcInit.Height() > 0);
|
||||
assert (NULL != m_pParent);
|
||||
|
||||
CRect rcCurrent = m_pParent->GetClientRect();
|
||||
|
||||
// Adjust the scrolling if required
|
||||
m_xScrollPos = MIN(m_xScrollPos, MAX(0, m_rcMin.Width() - rcCurrent.Width() ) );
|
||||
m_yScrollPos = MIN(m_yScrollPos, MAX(0, m_rcMin.Height() - rcCurrent.Height()) );
|
||||
SCROLLINFO si = {0};
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
||||
si.nMax = m_rcMin.Width();
|
||||
si.nPage = rcCurrent.Width();
|
||||
si.nPos = m_xScrollPos;
|
||||
m_pParent->SetScrollInfo(SB_HORZ, si, TRUE);
|
||||
si.nMax = m_rcMin.Height();
|
||||
si.nPage = rcCurrent.Height();
|
||||
si.nPos = m_yScrollPos;
|
||||
m_pParent->SetScrollInfo(SB_VERT, si, TRUE);
|
||||
|
||||
rcCurrent.right = MAX( rcCurrent.Width(), m_rcMin.Width() );
|
||||
rcCurrent.bottom = MAX( rcCurrent.Height(), m_rcMin.Height() );
|
||||
if (!m_rcMax.IsRectEmpty())
|
||||
{
|
||||
rcCurrent.right = MIN( rcCurrent.Width(), m_rcMax.Width() );
|
||||
rcCurrent.bottom = MIN( rcCurrent.Height(), m_rcMax.Height() );
|
||||
}
|
||||
|
||||
// Declare an iterator to step through the vector
|
||||
std::vector<ResizeData>::iterator iter;
|
||||
|
||||
for (iter = m_vResizeData.begin(); iter < m_vResizeData.end(); ++iter)
|
||||
{
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
// Calculate the new size and position of the child window
|
||||
switch( (*iter).corner )
|
||||
{
|
||||
case topleft:
|
||||
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
||||
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
||||
left = (*iter).rcInit.left;
|
||||
top = (*iter).rcInit.top;
|
||||
break;
|
||||
case topright:
|
||||
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
||||
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
||||
left = (*iter).rcInit.right - width - m_rcInit.Width() + rcCurrent.Width();
|
||||
top = (*iter).rcInit.top;
|
||||
break;
|
||||
case bottomleft:
|
||||
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
||||
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
||||
left = (*iter).rcInit.left;
|
||||
top = (*iter).rcInit.bottom - height - m_rcInit.Height() + rcCurrent.Height();
|
||||
break;
|
||||
case bottomright:
|
||||
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
||||
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
||||
left = (*iter).rcInit.right - width - m_rcInit.Width() + rcCurrent.Width();
|
||||
top = (*iter).rcInit.bottom - height - m_rcInit.Height() + rcCurrent.Height();
|
||||
break;
|
||||
}
|
||||
|
||||
// Position the child window.
|
||||
CRect rc(left - m_xScrollPos, top - m_yScrollPos, left + width - m_xScrollPos, top + height - m_yScrollPos);
|
||||
if ( rc != (*iter).rcOld)
|
||||
{
|
||||
CWnd* pWnd = FromHandle((*iter).hWnd);
|
||||
CWnd *pWndPrev = pWnd->GetWindow(GW_HWNDPREV); // Trick to maintain the original tab order.
|
||||
HWND hWnd = pWndPrev ? pWndPrev->GetHwnd():NULL;
|
||||
pWnd->SetWindowPos(hWnd, rc, SWP_NOCOPYBITS);
|
||||
(*iter).rcOld = rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef _WIN32_WCE
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
|
||||
|
||||
#endif // _WIN32XX_DIALOG_H_
|
||||
|
4214
mmc_updater/depends/win32cpp/docking.h
Normal file
4214
mmc_updater/depends/win32cpp/docking.h
Normal file
File diff suppressed because it is too large
Load Diff
392
mmc_updater/depends/win32cpp/file.h
Normal file
392
mmc_updater/depends/win32cpp/file.h
Normal file
@ -0,0 +1,392 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef _WIN32XX_FILE_H_
|
||||
#define _WIN32XX_FILE_H_
|
||||
|
||||
|
||||
#include "wincore.h"
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
class CFile
|
||||
{
|
||||
public:
|
||||
CFile();
|
||||
CFile(HANDLE hFile);
|
||||
CFile(LPCTSTR pszFileName, UINT nOpenFlags);
|
||||
~CFile();
|
||||
operator HANDLE() const;
|
||||
|
||||
BOOL Close();
|
||||
BOOL Flush();
|
||||
HANDLE GetHandle() const;
|
||||
ULONGLONG GetLength() const;
|
||||
const CString& GetFileName() const;
|
||||
const CString& GetFilePath() const;
|
||||
const CString& GetFileTitle() const;
|
||||
ULONGLONG GetPosition() const;
|
||||
BOOL LockRange(ULONGLONG Pos, ULONGLONG Count);
|
||||
BOOL Open(LPCTSTR pszFileName, UINT nOpenFlags);
|
||||
CString OpenFileDialog(LPCTSTR pszFilePathName = NULL,
|
||||
DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR pszFilter = NULL,
|
||||
CWnd* pOwnerWnd = NULL);
|
||||
UINT Read(void* pBuf, UINT nCount);
|
||||
static BOOL Remove(LPCTSTR pszFileName);
|
||||
static BOOL Rename(LPCTSTR pszOldName, LPCTSTR pszNewName);
|
||||
CString SaveFileDialog(LPCTSTR pszFilePathName = NULL,
|
||||
DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR pszFilter = NULL,
|
||||
LPCTSTR pszDefExt = NULL, CWnd* pOwnerWnd = NULL);
|
||||
ULONGLONG Seek(LONGLONG lOff, UINT nFrom);
|
||||
void SeekToBegin();
|
||||
ULONGLONG SeekToEnd();
|
||||
void SetFilePath(LPCTSTR pszNewName);
|
||||
BOOL SetLength(ULONGLONG NewLen);
|
||||
BOOL UnlockRange(ULONGLONG Pos, ULONGLONG Count);
|
||||
BOOL Write(const void* pBuf, UINT nCount);
|
||||
|
||||
private:
|
||||
CFile(const CFile&); // Disable copy construction
|
||||
CFile& operator = (const CFile&); // Disable assignment operator
|
||||
CString m_FileName;
|
||||
CString m_FilePath;
|
||||
CString m_FileTitle;
|
||||
HANDLE m_hFile;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
inline CFile::CFile() : m_hFile(0)
|
||||
{
|
||||
}
|
||||
|
||||
inline CFile::CFile(HANDLE hFile) : m_hFile(hFile)
|
||||
{
|
||||
}
|
||||
|
||||
inline CFile::CFile(LPCTSTR pszFileName, UINT nOpenFlags) : m_hFile(0)
|
||||
{
|
||||
assert(pszFileName);
|
||||
Open(pszFileName, nOpenFlags);
|
||||
assert(m_hFile);
|
||||
}
|
||||
|
||||
inline CFile::~CFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
inline CFile::operator HANDLE() const
|
||||
{
|
||||
return m_hFile;
|
||||
}
|
||||
|
||||
inline BOOL CFile::Close()
|
||||
// Closes the file associated with this object. Closed file can no longer be read or written to.
|
||||
{
|
||||
BOOL bResult = TRUE;
|
||||
if (m_hFile)
|
||||
bResult = CloseHandle(m_hFile);
|
||||
|
||||
m_hFile = 0;
|
||||
return bResult;
|
||||
}
|
||||
|
||||
inline BOOL CFile::Flush()
|
||||
// Causes any remaining data in the file buffer to be written to the file.
|
||||
{
|
||||
assert(m_hFile);
|
||||
return FlushFileBuffers(m_hFile);
|
||||
}
|
||||
|
||||
inline HANDLE CFile::GetHandle() const
|
||||
{
|
||||
return m_hFile;
|
||||
}
|
||||
|
||||
inline ULONGLONG CFile::GetLength( ) const
|
||||
// Returns the length of the file in bytes.
|
||||
{
|
||||
assert(m_hFile);
|
||||
|
||||
LONG High = 0;
|
||||
DWORD LowPos = SetFilePointer(m_hFile, 0, &High, FILE_END);
|
||||
|
||||
ULONGLONG Result = ((ULONGLONG)High << 32) + LowPos;
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline const CString& CFile::GetFileName() const
|
||||
// Returns the filename of the file associated with this object.
|
||||
{
|
||||
return (const CString&)m_FileName;
|
||||
}
|
||||
|
||||
inline const CString& CFile::GetFilePath() const
|
||||
// Returns the full filename including the directory of the file associated with this object.
|
||||
{
|
||||
return (const CString&)m_FilePath;
|
||||
}
|
||||
|
||||
inline const CString& CFile::GetFileTitle() const
|
||||
// Returns the filename of the file associated with this object, excluding the path and the file extension
|
||||
{
|
||||
return (const CString&)m_FileTitle;
|
||||
}
|
||||
|
||||
inline ULONGLONG CFile::GetPosition() const
|
||||
// Returns the current value of the file pointer, which can be used in subsequent calls to Seek.
|
||||
{
|
||||
assert(m_hFile);
|
||||
LONG High = 0;
|
||||
DWORD LowPos = SetFilePointer(m_hFile, 0, &High, FILE_CURRENT);
|
||||
|
||||
ULONGLONG Result = ((ULONGLONG)High << 32) + LowPos;
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline BOOL CFile::LockRange(ULONGLONG Pos, ULONGLONG Count)
|
||||
// Locks a range of bytes in and open file.
|
||||
{
|
||||
assert(m_hFile);
|
||||
|
||||
DWORD dwPosHigh = (DWORD)(Pos >> 32);
|
||||
DWORD dwPosLow = (DWORD)(Pos & 0xFFFFFFFF);
|
||||
DWORD dwCountHigh = (DWORD)(Count >> 32);
|
||||
DWORD dwCountLow = (DWORD)(Count & 0xFFFFFFFF);
|
||||
|
||||
return ::LockFile(m_hFile, dwPosLow, dwPosHigh, dwCountLow, dwCountHigh);
|
||||
}
|
||||
|
||||
inline BOOL CFile::Open(LPCTSTR pszFileName, UINT nOpenFlags)
|
||||
// Prepares a file to be written to or read from.
|
||||
{
|
||||
if (m_hFile) Close();
|
||||
|
||||
m_hFile = ::CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, nOpenFlags, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == m_hFile)
|
||||
{
|
||||
TRACE(_T("Failed\n"));
|
||||
m_hFile = 0;
|
||||
}
|
||||
|
||||
if (m_hFile)
|
||||
{
|
||||
SetFilePath(pszFileName);
|
||||
}
|
||||
|
||||
return (m_hFile != 0);
|
||||
}
|
||||
|
||||
inline CString CFile::OpenFileDialog(LPCTSTR pszFilePathName, DWORD dwFlags, LPCTSTR pszFilter, CWnd* pOwnerWnd)
|
||||
// Displays the file open dialog.
|
||||
// Returns a CString containing either the selected file name or an empty CString.
|
||||
{
|
||||
CString str;
|
||||
if (pszFilePathName)
|
||||
str = pszFilePathName;
|
||||
|
||||
OPENFILENAME ofn = {0};
|
||||
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
|
||||
#if defined OPENFILENAME_SIZE_VERSION_400
|
||||
if (GetWinVersion() < 2500)
|
||||
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
|
||||
#endif
|
||||
|
||||
ofn.hwndOwner = pOwnerWnd? pOwnerWnd->GetHwnd() : NULL;
|
||||
ofn.hInstance = GetApp()->GetInstanceHandle();
|
||||
ofn.lpstrFilter = pszFilter;
|
||||
ofn.lpstrTitle = _T("Open File");
|
||||
ofn.Flags = dwFlags;
|
||||
ofn.nMaxFile = _MAX_PATH;
|
||||
|
||||
ofn.lpstrFile = (LPTSTR)str.GetBuffer(_MAX_PATH);
|
||||
::GetOpenFileName(&ofn);
|
||||
str.ReleaseBuffer();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
inline UINT CFile::Read(void* pBuf, UINT nCount)
|
||||
// Reads from the file, storing the contents in the specified buffer.
|
||||
{
|
||||
assert(m_hFile);
|
||||
DWORD dwRead = 0;
|
||||
|
||||
if (!::ReadFile(m_hFile, pBuf, nCount, &dwRead, NULL))
|
||||
dwRead = 0;
|
||||
|
||||
return dwRead;
|
||||
}
|
||||
|
||||
inline BOOL CFile::Rename(LPCTSTR pszOldName, LPCTSTR pszNewName)
|
||||
// Renames the specified file.
|
||||
{
|
||||
return ::MoveFile(pszOldName, pszNewName);
|
||||
}
|
||||
|
||||
inline BOOL CFile::Remove(LPCTSTR pszFileName)
|
||||
// Deletes the specified file.
|
||||
{
|
||||
return ::DeleteFile(pszFileName);
|
||||
}
|
||||
|
||||
inline CString CFile::SaveFileDialog(LPCTSTR pszFilePathName, DWORD dwFlags, LPCTSTR pszFilter, LPCTSTR pszDefExt, CWnd* pOwnerWnd)
|
||||
// Displays the SaveFileDialog.
|
||||
// Returns a CString containing either the selected file name or an empty CString
|
||||
{
|
||||
CString str;
|
||||
if (pszFilePathName)
|
||||
str = pszFilePathName;
|
||||
|
||||
OPENFILENAME ofn = {0};
|
||||
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
|
||||
#if defined OPENFILENAME_SIZE_VERSION_400
|
||||
if (GetWinVersion() < 2500)
|
||||
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
|
||||
#endif
|
||||
|
||||
ofn.hwndOwner = pOwnerWnd? pOwnerWnd->GetHwnd() : NULL;
|
||||
ofn.hInstance = GetApp()->GetInstanceHandle();
|
||||
ofn.lpstrFilter = pszFilter;
|
||||
ofn.lpstrFile = (LPTSTR)pszFilePathName;
|
||||
ofn.lpstrFileTitle = (LPTSTR)pszFilePathName;
|
||||
ofn.lpstrDefExt = pszDefExt;
|
||||
ofn.nMaxFile = lstrlen(pszFilePathName);
|
||||
ofn.lpstrTitle = _T("Save File");
|
||||
ofn.Flags = dwFlags;
|
||||
ofn.nMaxFile = _MAX_PATH;
|
||||
ofn.lpstrFile = (LPTSTR)str.GetBuffer(_MAX_PATH);
|
||||
::GetSaveFileName(&ofn);
|
||||
str.ReleaseBuffer();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
inline ULONGLONG CFile::Seek(LONGLONG lOff, UINT nFrom)
|
||||
// Positions the current file pointer.
|
||||
// Permitted values for nFrom are: FILE_BEGIN, FILE_CURRENT, or FILE_END.
|
||||
{
|
||||
assert(m_hFile);
|
||||
assert(nFrom == FILE_BEGIN || nFrom == FILE_CURRENT || nFrom == FILE_END);
|
||||
|
||||
LONG High = LONG(lOff >> 32);
|
||||
LONG Low = (LONG)(lOff & 0xFFFFFFFF);
|
||||
|
||||
DWORD LowPos = SetFilePointer(m_hFile, Low, &High, nFrom);
|
||||
|
||||
ULONGLONG Result = ((ULONGLONG)High << 32) + LowPos;
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline void CFile::SeekToBegin()
|
||||
// Sets the current file pointer to the beginning of the file.
|
||||
{
|
||||
assert(m_hFile);
|
||||
Seek(0, FILE_BEGIN);
|
||||
}
|
||||
|
||||
inline ULONGLONG CFile::SeekToEnd()
|
||||
// Sets the current file pointer to the end of the file.
|
||||
{
|
||||
assert(m_hFile);
|
||||
return Seek(0, FILE_END);
|
||||
}
|
||||
|
||||
inline void CFile::SetFilePath(LPCTSTR pszFileName)
|
||||
// Specifies the full file name, including its path
|
||||
{
|
||||
TCHAR* pFileName = NULL;
|
||||
int nBuffSize = ::GetFullPathName(pszFileName, 0, 0, 0);
|
||||
if (nBuffSize > 0)
|
||||
{
|
||||
TCHAR* pBuff = m_FilePath.GetBuffer(nBuffSize);
|
||||
::GetFullPathName(pszFileName, nBuffSize, pBuff, &pFileName);
|
||||
m_FilePath.ReleaseBuffer();
|
||||
m_FileName = pFileName;
|
||||
int nPos = m_FileName.ReverseFind(_T("."));
|
||||
if (nPos >= 0)
|
||||
m_FileTitle = m_FileName.Left(nPos);
|
||||
}
|
||||
}
|
||||
|
||||
inline BOOL CFile::SetLength(ULONGLONG NewLen)
|
||||
// Changes the length of the file to the specified value.
|
||||
{
|
||||
assert(m_hFile);
|
||||
|
||||
Seek(NewLen, FILE_BEGIN);
|
||||
return ::SetEndOfFile(m_hFile);
|
||||
}
|
||||
|
||||
inline BOOL CFile::UnlockRange(ULONGLONG Pos, ULONGLONG Count)
|
||||
// Unlocks a range of bytes in an open file.
|
||||
{
|
||||
assert(m_hFile);
|
||||
|
||||
DWORD dwPosHigh = (DWORD)(Pos >> 32);
|
||||
DWORD dwPosLow = (DWORD)(Pos & 0xFFFFFFFF);
|
||||
DWORD dwCountHigh = (DWORD)(Count >> 32);
|
||||
DWORD dwCountLow = (DWORD)(Count & 0xFFFFFFFF);
|
||||
|
||||
return ::UnlockFile(m_hFile, dwPosLow, dwPosHigh, dwCountLow, dwCountHigh);
|
||||
}
|
||||
|
||||
inline BOOL CFile::Write(const void* pBuf, UINT nCount)
|
||||
// Writes the specified buffer to the file.
|
||||
{
|
||||
assert(m_hFile);
|
||||
DWORD dwWritten = 0;
|
||||
BOOL bResult = ::WriteFile(m_hFile, pBuf, nCount, &dwWritten, NULL);
|
||||
if (dwWritten != nCount)
|
||||
bResult = FALSE;
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif
|
3303
mmc_updater/depends/win32cpp/frame.h
Normal file
3303
mmc_updater/depends/win32cpp/frame.h
Normal file
File diff suppressed because it is too large
Load Diff
3944
mmc_updater/depends/win32cpp/gdi.h
Normal file
3944
mmc_updater/depends/win32cpp/gdi.h
Normal file
File diff suppressed because it is too large
Load Diff
205
mmc_updater/depends/win32cpp/info.txt
Normal file
205
mmc_updater/depends/win32cpp/info.txt
Normal file
@ -0,0 +1,205 @@
|
||||
Generic Information about Win32++ Projects
|
||||
==========================================
|
||||
The various directories may contain the following types of files:
|
||||
|
||||
Extension | Description
|
||||
----------+------------
|
||||
cbp | A project file used by CodeBlocks
|
||||
dsp | A project file used by Visual Studio 6
|
||||
dsw | A project file used by Visual Studio 6
|
||||
sln | A project file used by Visual Studio 2003, VS2005 or VS2008
|
||||
vcproj | A project file used by Visual Studio 2003, VS2005 or VS2008
|
||||
vcxproj | A project file used by Visual Studio 2010
|
||||
filters | A supplementary project file used by Visual Studio 2010
|
||||
bdsproj | A project file used by Borland Developer Studio 2006
|
||||
bpf | A project file used by Borland Developer Studio 2006
|
||||
vcp | A project file used by eMbedded Visual C++
|
||||
vcw | A project file used by eMbedded Visual C++
|
||||
dev | A project file used by Dev-C++
|
||||
cpp | A C++ source file
|
||||
h | A C++ header file
|
||||
rc | A C++ resouce script file
|
||||
jpg | A jpeg resource file
|
||||
ico | An icon resource file
|
||||
bmp | A bitmap resource file
|
||||
cur | A cursor resource file
|
||||
manifest | A manifest resource file
|
||||
txt | A text file
|
||||
xml | An Extensible Markup Language file (defines the ribbon UI)
|
||||
|
||||
Supported Compilers and Integrated Development Environments (IDEs)
|
||||
==================================================================
|
||||
Win32++ supports the following:
|
||||
* Borland Compiler Version 5.5
|
||||
* Borland Developer Studio 2006
|
||||
* Borland Turbo C++ 2006
|
||||
* CodeBlocks
|
||||
* Dev-C++
|
||||
* MinGW GCC Compiler
|
||||
* Visual Studio 6
|
||||
* Visual Studio.net 2003
|
||||
* Visual C++ Toolkit 2003
|
||||
* Visual Studio.net 2005
|
||||
* Visual Studio.net 2005 Express
|
||||
* Visual Studio.net 2008
|
||||
* Visual Studio.net 2008 Express
|
||||
* Visual Studio.net 2010
|
||||
|
||||
CodeBlocks is an IDE. The project files are configured for the following
|
||||
compilers:
|
||||
* Borland Compiler Version 5.5
|
||||
* MinGW GNU compiler
|
||||
* Visual C++ Toolkit 2003
|
||||
|
||||
Dev-C++ is an IDE which supports the MinGW GNU compiler
|
||||
|
||||
Supported Operating Systems
|
||||
===========================
|
||||
The programs compiled with Win32++ can run on the following operating systems:
|
||||
* Win95 (all versions, with or without Internet Explorer 4 installed)
|
||||
* Win98 (both versions)
|
||||
* WinME
|
||||
* Windows NT 4
|
||||
* Windows 2000
|
||||
* Windows XP
|
||||
* Windows XP x64
|
||||
* Windows Vista
|
||||
* Windows Vista x64
|
||||
* Windows 7
|
||||
* Windows 7 x64
|
||||
* Windows Server 2003
|
||||
* Windows Server 2003 x64
|
||||
* Windows Server 2008
|
||||
* Windows Server 2008 x64
|
||||
* Windows CE
|
||||
|
||||
Note: Programs compiled with Visual Studio.net 2008 and Visual Studio.net 2008
|
||||
Express will not run on Win32 operating systems earlier than Windows 2000.
|
||||
|
||||
Win32++ automatically detects if the operating system is capable of using
|
||||
rebars. If rebars are not supported by the OS, Win32++ produces a frame without
|
||||
rebars.
|
||||
|
||||
Win32++ is Unicode compliant and can therefore be used to develop Unicode
|
||||
applications. Users are advised that older operating systems (namely Win95,
|
||||
Win98 and WinME) don't support Unicode applications.
|
||||
|
||||
Win32++ supports 64bit compilers, and can be used to develop 64bit code.
|
||||
|
||||
Directory Structure
|
||||
===================
|
||||
When extracting the files from the zip archive, be sure to preserve the
|
||||
directory structure. The directory structure will typically look like this:
|
||||
|
||||
.\include
|
||||
.\new projects
|
||||
.\output
|
||||
.\samples
|
||||
.\tools
|
||||
.\tutorials
|
||||
.\WCE samples
|
||||
|
||||
The files which form the Win32++ library are contained in the include
|
||||
subdirectory.
|
||||
|
||||
Components of Win32++
|
||||
=====================
|
||||
|
||||
Files | Classes | Operating Systems | Description
|
||||
==================+==================+===================+=====================
|
||||
controls.h | CAnimation | Win32, Win64 | Adds support for the
|
||||
| CComboBox | and WinCE | following controls:
|
||||
| CComboBoxEx | | Animation, ComboBox,
|
||||
| CProgressBar | | ComboBoxEx, Progress
|
||||
| CScrollBar | | bar, Scroll bar,
|
||||
| CSlider | | Slider, Spin button.
|
||||
| CSpinButton | |
|
||||
------------------+------------------+-------------------+---------------------
|
||||
dialog.h | CDialog | Win32, Win64 | Adds dialog support.
|
||||
| CResizer | WinCE for CDialog |
|
||||
------------------+------------------+-------------------+---------------------
|
||||
docking.h | CDocker | Win32, Win64 | Adds support for
|
||||
| CDockContainer | | docking windows and
|
||||
| | | splitter windows.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
frame.h | CMenubar | Win32, Win64 | Adds support for
|
||||
| CFrame | | frames. Frames use a
|
||||
| | | toolbar and menubar
|
||||
| | | inside a rebar, and
|
||||
| | | a statusbar.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
gdi.h | CDC | Win32, Win64 | A helper class for
|
||||
| CBitmap | and WinCE | GDI graphics.
|
||||
| CBrush | |
|
||||
| CFont | |
|
||||
| CPalette | |
|
||||
| CPen | |
|
||||
| CRgn | |
|
||||
------------------+------------------+-------------------+---------------------
|
||||
listView.h | CListView | Win32, Win64 | Adds support for a
|
||||
| | and WinCE | ListView control.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
mdi.h | CMDIFrame | Win32, Win64 | Adds support for MDI
|
||||
| CMDIChild | | frames.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
propertysheet.h | CPropertySheet | Win32, Win64 | Adds property sheet
|
||||
| CPropertyPage | and WinCE | support.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
rebar.h | CRebar | Win32, Win64 | Adds support for a
|
||||
| | and WinCE | Rebar control.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
ribbon.h | CRibbon | Win32, Win64 | Adds support for the
|
||||
| CRibbonFrame | | Windows 7 ribbon.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
shared_ptr.h | Shared_Ptr | Win32, Win64, | Add a smart pointer
|
||||
| | and WinCE | for use in vectors.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
socket.h | CSocket | Win32, Win64 | Adds network
|
||||
| | and WinCE | support.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
splitter.h | CSplitter | Win32, Win64 | Adds splitter support
|
||||
| | | (depreciated)
|
||||
------------------+------------------+-------------------+----------------------
|
||||
statusbar.h | CStatusbar | Win32, Win64 | Adds support for a
|
||||
| | and WinCE | Status bar control.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
stdcontrols.h | CButton | Win32, Win64 | Adds support for
|
||||
| CEdit | and WinCE | Button, Edit,
|
||||
| CListBox | | ListBox and Static
|
||||
| CStatic | | controls.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
tab.h | CTab | Win32, Win64 | Adds support for tab
|
||||
| CMDITab | | controls, and MDI
|
||||
| | | tab windows.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
taskdialog.h | CTaskDialog | Win32, Win64 | Adds support for tab
|
||||
| | | task dialogs.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
thread.h | CThread | Win32, Win64 | Adds support for
|
||||
| | and WinCE | threads.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
toolbar.h | CToolbar | Win32, Win64 | Adds support for a
|
||||
| | and WinCE | Toolbar control.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
treeview.h | CTreeView | Win32, Win64 | Adds support for a
|
||||
| | and WinCE | TreeView control.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
wceframe.h | CWceFrame | WinCE only | Adds support for
|
||||
| CCmdbar | | frames in WinCE.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
webbrowser.h | CAXWindow | Win32, Win64 | Adds support for a
|
||||
| CWebBrowser | and WinCE | ActiveX container and
|
||||
| | | a WebBrowser window.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
wincore.h | CCriticalSection | Win32, Win64, | The core set of
|
||||
| CWinApp | and WinCE | classes required for
|
||||
| CWinException | | all Win32++
|
||||
| CWnd | | applications.
|
||||
------------------+------------------+-------------------+---------------------
|
||||
winutils.h | CPoint | Win32, Win64, | Additional utility
|
||||
| CRect | and WinCE | classes.
|
||||
| CSize | |
|
||||
------------------+------------------+-------------------+---------------------
|
||||
|
||||
Refer to the help documentation that ships with Win32++ for more information on
|
||||
using Win32++.
|
867
mmc_updater/depends/win32cpp/listview.h
Normal file
867
mmc_updater/depends/win32cpp/listview.h
Normal file
@ -0,0 +1,867 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef _WIN32XX_LISTVIEW_H_
|
||||
#define _WIN32XX_LISTVIEW_H_
|
||||
|
||||
#include "wincore.h"
|
||||
#include "commctrl.h"
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
class CListView : public CWnd
|
||||
{
|
||||
public:
|
||||
CListView() {}
|
||||
virtual ~CListView() {}
|
||||
virtual void PreRegisterClass(WNDCLASS &wc);
|
||||
|
||||
// Attributes
|
||||
CSize ApproximateViewRect(CSize sz = CSize(-1, -1), int iCount = -1) const;
|
||||
COLORREF GetBkColor( ) const;
|
||||
BOOL GetBkImage( LVBKIMAGE& lvbkImage ) const;
|
||||
UINT GetCallbackMask( ) const;
|
||||
BOOL GetCheckState( UINT nItem ) const;
|
||||
BOOL GetColumn( int iCol, LVCOLUMN& Column ) const;
|
||||
BOOL GetColumnOrderArray( LPINT piArray, int iCount = -1 );
|
||||
int GetColumnWidth( int iCol ) const;
|
||||
int GetCountPerPage( ) const;
|
||||
HWND GetEditControl( ) const;
|
||||
DWORD GetExtendedStyle( ) const;
|
||||
HWND GetHeader( ) const;
|
||||
HCURSOR GetHotCursor( );
|
||||
int GetHotItem( ) const;
|
||||
DWORD GetHoverTime( ) const;
|
||||
HIMAGELIST GetImageList( int nImageType ) const;
|
||||
BOOL GetItem( LVITEM& lvItem ) const;
|
||||
int GetItemCount( ) const;
|
||||
DWORD_PTR GetItemData( int iItem ) const;
|
||||
BOOL GetItemPosition( int iItem, CPoint& pt ) const;
|
||||
BOOL GetItemRect( int iItem, CRect& rc, UINT nCode ) const;
|
||||
UINT GetItemState( int iItem, UINT nMask ) const;
|
||||
tString GetItemText( int iItem, int iSubItem, UINT nTextMax = 260 ) const;
|
||||
int GetNextItem( int iItem, int iFlags ) const;
|
||||
UINT GetNumberOfWorkAreas( ) const;
|
||||
BOOL GetOrigin( CPoint& pt ) const;
|
||||
UINT GetSelectedCount( ) const;
|
||||
int GetSelectionMark( ) const;
|
||||
int GetStringWidth( LPCTSTR pszString ) const;
|
||||
BOOL GetSubItemRect( int iItem, int iSubItem, int iCode, CRect& rc ) const;
|
||||
COLORREF GetTextBkColor( ) const;
|
||||
COLORREF GetTextColor( ) const;
|
||||
HWND GetToolTips( ) const;
|
||||
int GetTopIndex( ) const;
|
||||
BOOL GetViewRect( CRect& rc ) const;
|
||||
void GetWorkAreas( int iWorkAreas, LPRECT pRectArray ) const;
|
||||
BOOL SetBkColor( COLORREF clrBk ) const;
|
||||
BOOL SetBkImage( LVBKIMAGE& plvbkImage ) const;
|
||||
BOOL SetCallbackMask( UINT nMask ) const;
|
||||
void SetCheckState( int iItem, BOOL fCheck = TRUE ) const;
|
||||
BOOL SetColumn( int iCol, const LVCOLUMN& pColumn ) const;
|
||||
BOOL SetColumnOrderArray( int iCount, LPINT piArray ) const;
|
||||
BOOL SetColumnWidth( int iCol, int cx ) const;
|
||||
DWORD SetExtendedStyle( DWORD dwNewStyle ) const;
|
||||
HCURSOR SetHotCursor( HCURSOR hCursor ) const;
|
||||
int SetHotItem( int nIndex ) const;
|
||||
DWORD SetHoverTime( DWORD dwHoverTime = (DWORD)-1 ) const;
|
||||
CSize SetIconSpacing( int cx, int cy ) const;
|
||||
CSize SetIconSpacing( CSize sz ) const;
|
||||
HIMAGELIST SetImageList( HIMAGELIST himl, int iImageListType ) const;
|
||||
BOOL SetItem( LVITEM& pItem ) const;
|
||||
BOOL SetItem( int iItem, int iSubItem, UINT nMask, LPCTSTR pszText, int iImage,
|
||||
UINT nState, UINT nStateMask, LPARAM lParam, int iIndent ) const;
|
||||
void SetItemCount( int iCount ) const;
|
||||
void SetItemCountEx( int iCount, DWORD dwFlags = LVSICF_NOINVALIDATEALL ) const;
|
||||
BOOL SetItemData( int iItem, DWORD_PTR dwData ) const;
|
||||
BOOL SetItemPosition( int iItem, CPoint& pt ) const;
|
||||
BOOL SetItemState( int iItem, LVITEM& Item ) const;
|
||||
void SetItemState( int iItem, UINT nState, UINT nMask ) const;
|
||||
void SetItemText( int iItem, int iSubItem, LPCTSTR pszText ) const;
|
||||
int SetSelectionMark( int iIndex ) const;
|
||||
BOOL SetTextBkColor( COLORREF clrBkText ) const;
|
||||
BOOL SetTextColor( COLORREF clrText ) const;
|
||||
HWND SetToolTips( HWND hWndToolTip ) const;
|
||||
void SetWorkAreas( int nWorkAreas, CRect& pRectArray ) const;
|
||||
int SubItemHitTest( LVHITTESTINFO& htInfo ) const;
|
||||
|
||||
// Operations
|
||||
BOOL Arrange( UINT nCode ) const;
|
||||
HIMAGELIST CreateDragImage( int iItem, CPoint& pt ) const;
|
||||
BOOL DeleteAllItems( ) const;
|
||||
BOOL DeleteColumn( int iCol ) const;
|
||||
BOOL DeleteItem( int iItem ) const;
|
||||
HWND EditLabel( int iItem ) const;
|
||||
BOOL EnsureVisible( int iItem, BOOL fPartialOK ) const;
|
||||
int FindItem( LVFINDINFO& FindInfo, int iStart = -1 ) const;
|
||||
int HitTest( LVHITTESTINFO& HitTestInfo ) const;
|
||||
int HitTest( CPoint pt, UINT* pFlags = NULL ) const;
|
||||
int InsertColumn( int iCol, const LVCOLUMN& pColumn ) const;
|
||||
int InsertColumn( int iCol, LPCTSTR pszColumnHeading, int iFormat = LVCFMT_LEFT,
|
||||
int iWidth = -1, int iSubItem = -1 ) const;
|
||||
int InsertItem( const LVITEM& pItem ) const;
|
||||
int InsertItem( int iItem, LPCTSTR pszText ) const;
|
||||
int InsertItem( int iItem, LPCTSTR pszText, int iImage ) const;
|
||||
BOOL RedrawItems( int iFirst, int iLast ) const;
|
||||
BOOL Scroll( CSize sz ) const;
|
||||
BOOL SortItems( PFNLVCOMPARE pfnCompare, DWORD_PTR dwData ) const;
|
||||
BOOL Update( int iItem ) const;
|
||||
|
||||
private:
|
||||
CListView(const CListView&); // Disable copy construction
|
||||
CListView& operator = (const CListView&); // Disable assignment operator
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
inline void CListView::PreRegisterClass(WNDCLASS &wc)
|
||||
{
|
||||
// Set the Window Class
|
||||
wc.lpszClassName = WC_LISTVIEW;
|
||||
}
|
||||
|
||||
inline CSize CListView::ApproximateViewRect(CSize sz /*= CSize(-1, -1)*/, int iCount /* = -1*/) const
|
||||
// Calculates the approximate width and height required to display a given number of items.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return CSize( ListView_ApproximateViewRect( m_hWnd, sz.cx, sz.cy, iCount ) );
|
||||
}
|
||||
|
||||
inline COLORREF CListView::GetBkColor( ) const
|
||||
// Retrieves the background color of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetBkColor( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetBkImage( LVBKIMAGE& lvbkImage ) const
|
||||
// Retrieves the background image in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetBkImage( m_hWnd, &lvbkImage );
|
||||
}
|
||||
|
||||
inline UINT CListView::GetCallbackMask( ) const
|
||||
// Retrieves the callback mask for a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetCallbackMask( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetCheckState( UINT nItem ) const
|
||||
// Determines if an item in a list-view control is selected.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetCheckState( m_hWnd, nItem );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetColumn( int iCol, LVCOLUMN& Column ) const
|
||||
// Retrieves the attributes of a list-view control's column.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetColumn( m_hWnd, iCol, &Column );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetColumnOrderArray( LPINT piArray, int iCount /*= -1*/ )
|
||||
// Retrieves the current left-to-right order of columns in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetColumnOrderArray( m_hWnd, iCount, piArray );
|
||||
}
|
||||
|
||||
inline int CListView::GetColumnWidth( int iCol ) const
|
||||
// Retrieves the width of a column in report or list view.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetColumnWidth( m_hWnd, iCol );
|
||||
}
|
||||
|
||||
inline int CListView::GetCountPerPage( ) const
|
||||
// Calculates the number of items that can fit vertically in the visible area of a
|
||||
// list-view control when in list or report view. Only fully visible items are counted.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetCountPerPage( m_hWnd );
|
||||
}
|
||||
|
||||
inline HWND CListView::GetEditControl( ) const
|
||||
// Retrieves the handle to the edit control being used to edit a list-view item's text.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetEditControl( m_hWnd );
|
||||
}
|
||||
|
||||
inline DWORD CListView::GetExtendedStyle( ) const
|
||||
// Retrieves the extended styles that are currently in use for a given list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetExtendedListViewStyle( m_hWnd );
|
||||
}
|
||||
|
||||
inline HWND CListView::GetHeader( ) const
|
||||
// Retrieves the handle to the header control used by a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetHeader( m_hWnd );
|
||||
}
|
||||
|
||||
inline HCURSOR CListView::GetHotCursor( )
|
||||
// Retrieves the HCURSOR used when the pointer is over an item while hot tracking is enabled.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetHotCursor( m_hWnd );
|
||||
}
|
||||
|
||||
inline int CListView::GetHotItem( ) const
|
||||
// Retrieves the index of the hot item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetHotItem( m_hWnd );
|
||||
}
|
||||
|
||||
inline DWORD CListView::GetHoverTime( ) const
|
||||
// Retrieves the amount of time that the mouse cursor must hover over an item before it is selected.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetHoverTime( m_hWnd );
|
||||
}
|
||||
|
||||
inline HIMAGELIST CListView::GetImageList( int nImageType ) const
|
||||
// Retrieves the handle to an image list used for drawing list-view items.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetImageList( m_hWnd, nImageType );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetItem( LVITEM& Item ) const
|
||||
// Retrieves some or all of a list-view item's attributes.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetItem( m_hWnd, &Item );
|
||||
}
|
||||
|
||||
inline int CListView::GetItemCount( ) const
|
||||
// Retrieves the number of items in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetItemCount( m_hWnd );
|
||||
}
|
||||
|
||||
inline DWORD_PTR CListView::GetItemData( int iItem ) const
|
||||
// Retrieves the value(lParam) specific to the item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
LVITEM lvi = {0};
|
||||
lvi.iItem = iItem;
|
||||
lvi.mask = LVIF_PARAM;
|
||||
ListView_GetItem(m_hWnd, &lvi);
|
||||
return lvi.lParam;
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetItemPosition( int iItem, CPoint& pt ) const
|
||||
// Retrieves the position of a list-view item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetItemPosition( m_hWnd, iItem, &pt );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetItemRect( int iItem, CRect& rc, UINT nCode ) const
|
||||
// Retrieves the bounding rectangle for all or part of an item in the current view.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetItemRect( m_hWnd, iItem, &rc, nCode );
|
||||
}
|
||||
|
||||
inline UINT CListView::GetItemState( int iItem, UINT nMask ) const
|
||||
// Retrieves the state of a list-view item.
|
||||
|
||||
// Possible values of nMask:
|
||||
// LVIS_CUT The item is marked for a cut-and-paste operation.
|
||||
// LVIS_DROPHILITED The item is highlighted as a drag-and-drop target.
|
||||
// LVIS_FOCUSED The item has the focus, so it is surrounded by a standard focus rectangle.
|
||||
// LVIS_SELECTED The item is selected.
|
||||
// LVIS_OVERLAYMASK Use this mask to retrieve the item's overlay image index.
|
||||
// LVIS_STATEIMAGEMASK Use this mask to retrieve the item's state image index.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetItemState( m_hWnd, iItem, nMask );
|
||||
}
|
||||
|
||||
inline tString CListView::GetItemText( int iItem, int iSubItem, UINT nTextMax /* = 260 */ ) const
|
||||
// Retrieves the text of a list-view item.
|
||||
// Note: Although the list-view control allows any length string to be stored
|
||||
// as item text, only the first 260 characters are displayed.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
tString t;
|
||||
if (nTextMax > 0)
|
||||
{
|
||||
std::vector<TCHAR> vTChar(nTextMax +1, _T('\0'));
|
||||
TCHAR* pszText = &vTChar.front();
|
||||
LVITEM lvi = {0};
|
||||
lvi.iItem = iItem;
|
||||
lvi.iSubItem = iSubItem;
|
||||
lvi.mask = LVIF_TEXT;
|
||||
lvi.cchTextMax = nTextMax;
|
||||
lvi.pszText = pszText;
|
||||
ListView_GetItem( m_hWnd, &lvi );
|
||||
t = lvi.pszText;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
inline int CListView::GetNextItem( int iItem, int iFlags ) const
|
||||
// Searches for a list-view item that has the specified properties and
|
||||
// bears the specified relationship to a specified item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetNextItem( m_hWnd, iItem, iFlags );
|
||||
}
|
||||
|
||||
inline UINT CListView::GetNumberOfWorkAreas( ) const
|
||||
// Retrieves the working areas from a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
UINT nWorkAreas = 0;
|
||||
ListView_GetWorkAreas( m_hWnd, nWorkAreas, NULL );
|
||||
return nWorkAreas;
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetOrigin( CPoint& pt ) const
|
||||
// Retrieves the current view origin for a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetOrigin( m_hWnd, &pt );
|
||||
}
|
||||
|
||||
inline UINT CListView::GetSelectedCount( ) const
|
||||
// Determines the number of selected items in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (UINT)::SendMessage( m_hWnd, LVM_GETSELECTEDCOUNT, 0L, 0L );
|
||||
}
|
||||
|
||||
inline int CListView::GetSelectionMark( ) const
|
||||
// Retrieves the selection mark from a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)::SendMessage( m_hWnd, LVM_GETSELECTIONMARK, 0L, 0L );
|
||||
}
|
||||
|
||||
inline int CListView::GetStringWidth( LPCTSTR pszString ) const
|
||||
// Determines the width of a specified string using the specified list-view control's current font.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)::SendMessage( m_hWnd, LVM_GETSTRINGWIDTH, 0L, (LPARAM)pszString );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetSubItemRect( int iItem, int iSubItem, int iCode, CRect& rc ) const
|
||||
// Retrieves information about the rectangle that surrounds a subitem in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetSubItemRect( m_hWnd, iItem, iSubItem, iCode, &rc );
|
||||
}
|
||||
|
||||
inline COLORREF CListView::GetTextBkColor( ) const
|
||||
// Retrieves the text background color of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetTextBkColor( m_hWnd );
|
||||
}
|
||||
|
||||
inline COLORREF CListView::GetTextColor( ) const
|
||||
// Retrieves the text color of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetTextColor( m_hWnd );
|
||||
}
|
||||
|
||||
inline HWND CListView::GetToolTips( ) const
|
||||
// Retrieves the ToolTip control that the list-view control uses to display ToolTips.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetToolTips( m_hWnd );
|
||||
}
|
||||
|
||||
inline int CListView::GetTopIndex( ) const
|
||||
// Retrieves the index of the topmost visible item when in list or report view.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetTopIndex( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CListView::GetViewRect( CRect& rc ) const
|
||||
// Retrieves the bounding rectangle of all items in the list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_GetViewRect( m_hWnd, &rc );
|
||||
}
|
||||
|
||||
inline void CListView::GetWorkAreas( int iWorkAreas, LPRECT pRectArray ) const
|
||||
// Retrieves the working areas from a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
ListView_GetWorkAreas( m_hWnd, iWorkAreas, pRectArray );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetBkColor( COLORREF clrBk ) const
|
||||
// Sets the background color of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetBkColor( m_hWnd, clrBk );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetBkImage( LVBKIMAGE& lvbkImage ) const
|
||||
// Sets the background image in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetBkImage( m_hWnd, &lvbkImage );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetCallbackMask( UINT nMask ) const
|
||||
// Changes the callback mask for a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetCallbackMask( m_hWnd, nMask );
|
||||
}
|
||||
|
||||
inline void CListView::SetCheckState( int iItem, BOOL fCheck /*= TRUE*/ ) const
|
||||
// Used to select or deselect an item in a list-view control.
|
||||
// This macro should only be used for list-view controls with the LVS_EX_CHECKBOXES style.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
ListView_SetItemState(m_hWnd, iItem, INDEXTOSTATEIMAGEMASK((fCheck==TRUE)?2:1),LVIS_STATEIMAGEMASK);
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetColumn( int iCol, const LVCOLUMN& Column ) const
|
||||
// Sets the attributes of a list-view column.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetColumn( m_hWnd, iCol, &Column );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetColumnOrderArray( int iCount, LPINT piArray ) const
|
||||
// Sets the left-to-right order of columns in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetColumnOrderArray( m_hWnd, iCount, piArray );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetColumnWidth( int iCol, int cx ) const
|
||||
// Used to change the width of a column in report view or the width of all columns in list-view mode.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetColumnWidth( m_hWnd, iCol, cx );
|
||||
}
|
||||
|
||||
inline DWORD CListView::SetExtendedStyle( DWORD dwNewStyle ) const
|
||||
// Sets extended styles for list-view controls.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetExtendedListViewStyle( m_hWnd, dwNewStyle );
|
||||
}
|
||||
|
||||
inline HCURSOR CListView::SetHotCursor( HCURSOR hCursor ) const
|
||||
// Sets the HCURSOR that the list-view control uses when the pointer is
|
||||
// over an item while hot tracking is enabled.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetHotCursor( m_hWnd, hCursor );
|
||||
}
|
||||
|
||||
inline int CListView::SetHotItem( int nIndex ) const
|
||||
// Sets the hot item in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetHotItem( m_hWnd, nIndex );
|
||||
}
|
||||
|
||||
inline DWORD CListView::SetHoverTime( DWORD dwHoverTime /*= (DWORD)-1*/ ) const
|
||||
// Sets the amount of time that the mouse cursor must hover over an item before it is selected.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetHoverTime( m_hWnd, dwHoverTime );
|
||||
}
|
||||
|
||||
inline CSize CListView::SetIconSpacing( int cx, int cy ) const
|
||||
// Sets the spacing between icons in list-view controls set to the LVS_ICON style.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return CSize( ListView_SetIconSpacing( m_hWnd, cx, cy ) );
|
||||
}
|
||||
|
||||
inline CSize CListView::SetIconSpacing( CSize sz ) const
|
||||
// Sets the spacing between icons in list-view controls set to the LVS_ICON style.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return CSize( ListView_SetIconSpacing( m_hWnd, sz.cx, sz.cy ) );
|
||||
}
|
||||
|
||||
inline HIMAGELIST CListView::SetImageList( HIMAGELIST himl, int iImageListType ) const
|
||||
// Assigns an image list to a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetImageList( m_hWnd, himl, iImageListType );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetItem( LVITEM& Item ) const
|
||||
// Sets some or all of a list-view item's attributes.
|
||||
|
||||
// The declaration for TVITEM:
|
||||
// typedef struct _LVITEM {
|
||||
// UINT mask;
|
||||
// int iItem;
|
||||
// int iSubItem;
|
||||
// UINT state;
|
||||
// UINT stateMask;
|
||||
// LPTSTR pszText;
|
||||
// int cchTextMax;
|
||||
// int iImage;
|
||||
// LPARAM lParam;
|
||||
// } LVITEM, *LVITEM&;
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetItem( m_hWnd, &Item );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetItem( int iItem, int iSubItem, UINT nMask, LPCTSTR pszText, int iImage,
|
||||
UINT nState, UINT nStateMask, LPARAM lParam, int iIndent ) const
|
||||
// Sets some or all of a list-view item's attributes.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
LVITEM lvi = {0};
|
||||
lvi.iItem = iItem;
|
||||
lvi.iSubItem = iSubItem;
|
||||
lvi.mask = nMask;
|
||||
lvi.pszText = (LPTSTR)pszText;
|
||||
lvi.iImage = iImage;
|
||||
lvi.state = nState;
|
||||
lvi.stateMask = nStateMask;
|
||||
lvi.lParam = lParam;
|
||||
lvi.iIndent = iIndent;
|
||||
|
||||
return ListView_SetItem( m_hWnd, &lvi);
|
||||
}
|
||||
|
||||
inline void CListView::SetItemCount( int iCount ) const
|
||||
// Causes the list-view control to allocate memory for the specified number of items.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
ListView_SetItemCount( m_hWnd, iCount );
|
||||
}
|
||||
|
||||
inline void CListView::SetItemCountEx( int iCount, DWORD dwFlags /*= LVSICF_NOINVALIDATEALL*/ ) const
|
||||
// Sets the virtual number of items in a virtual list view.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
ListView_SetItemCountEx( m_hWnd, iCount, dwFlags );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetItemData( int iItem, DWORD_PTR dwData ) const
|
||||
// Sets the value(lParam) specific to the item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
LVITEM lvi = {0};
|
||||
lvi.iItem = iItem;
|
||||
lvi.lParam = dwData;
|
||||
lvi.mask = LVIF_PARAM;
|
||||
return ListView_SetItem(m_hWnd, &lvi);
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetItemPosition( int iItem, CPoint& pt ) const
|
||||
// Moves an item to a specified position in a list-view control (in icon or small icon view).
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetItemPosition( m_hWnd, iItem, pt.x, pt.y );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetItemState( int iItem, LVITEM& Item ) const
|
||||
// Changes the state of an item in a list-view control.
|
||||
|
||||
// Possible values of nMask:
|
||||
// LVIS_CUT The item is marked for a cut-and-paste operation.
|
||||
// LVIS_DROPHILITED The item is highlighted as a drag-and-drop target.
|
||||
// LVIS_FOCUSED The item has the focus, so it is surrounded by a standard focus rectangle.
|
||||
// LVIS_SELECTED The item is selected.
|
||||
// LVIS_OVERLAYMASK Use this mask to retrieve the item's overlay image index.
|
||||
// LVIS_STATEIMAGEMASK Use this mask to retrieve the item's state image index.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, (WPARAM)iItem, (LPARAM)&Item);
|
||||
}
|
||||
|
||||
inline void CListView::SetItemState( int iItem, UINT nState, UINT nMask ) const
|
||||
// Changes the state of an item in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
ListView_SetItemState(m_hWnd, iItem, nState, nMask);
|
||||
}
|
||||
|
||||
inline void CListView::SetItemText( int iItem, int iSubItem, LPCTSTR pszText ) const
|
||||
// Sets the text color of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
ListView_SetItemText(m_hWnd, iItem, iSubItem, (LPTSTR)pszText );
|
||||
}
|
||||
|
||||
inline int CListView::SetSelectionMark( int iIndex ) const
|
||||
// Sets the selection mark in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetSelectionMark( m_hWnd, iIndex );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetTextBkColor( COLORREF clrBkText ) const
|
||||
// Sets the background color of text in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetTextBkColor( m_hWnd, clrBkText );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SetTextColor( COLORREF clrText ) const
|
||||
// Sets the text color of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SetTextColor( m_hWnd, clrText );
|
||||
}
|
||||
|
||||
inline HWND CListView::SetToolTips( HWND hWndToolTip ) const
|
||||
// Sets the ToolTip control that the list-view control will use to display ToolTips.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (HWND)::SendMessage(m_hWnd, LVM_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L);
|
||||
}
|
||||
|
||||
inline void CListView::SetWorkAreas( int nWorkAreas, CRect& pRectArray ) const
|
||||
// Sets the working area within a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
ListView_SetWorkAreas( m_hWnd, nWorkAreas, pRectArray );
|
||||
}
|
||||
|
||||
inline int CListView::SubItemHitTest( LVHITTESTINFO& htInfo ) const
|
||||
// Determines which list-view item or subitem is located at a given position.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SubItemHitTest( m_hWnd, &htInfo );
|
||||
}
|
||||
|
||||
// Operations
|
||||
|
||||
inline BOOL CListView::Arrange( UINT nCode ) const
|
||||
// Arranges items in icon view.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_Arrange( m_hWnd, nCode );
|
||||
}
|
||||
|
||||
inline HIMAGELIST CListView::CreateDragImage( int iItem, CPoint& pt ) const
|
||||
// Creates a drag image list for the specified item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_CreateDragImage( m_hWnd, iItem, &pt );
|
||||
}
|
||||
|
||||
inline BOOL CListView::DeleteAllItems( ) const
|
||||
// ListView_DeleteAllItems
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_DeleteAllItems( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CListView::DeleteColumn( int iCol ) const
|
||||
// Removes a column from a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_DeleteColumn( m_hWnd, iCol );
|
||||
}
|
||||
|
||||
inline BOOL CListView::DeleteItem( int iItem ) const
|
||||
// Removes an item from a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_DeleteItem( m_hWnd, iItem );
|
||||
}
|
||||
|
||||
inline HWND CListView::EditLabel( int iItem ) const
|
||||
// Begins in-place editing of the specified list-view item's text.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_EditLabel( m_hWnd, iItem );
|
||||
}
|
||||
|
||||
inline BOOL CListView::EnsureVisible( int iItem, BOOL fPartialOK ) const
|
||||
// Ensures that a list-view item is either entirely or partially visible,
|
||||
// scrolling the list-view control if necessary.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(LVM_ENSUREVISIBLE, (WPARAM)iItem, (LPARAM)fPartialOK );
|
||||
}
|
||||
|
||||
inline int CListView::FindItem( LVFINDINFO& FindInfo, int iStart /*= -1*/ ) const
|
||||
// Searches for a list-view item with the specified characteristics.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_FindItem( m_hWnd, iStart, &FindInfo );
|
||||
}
|
||||
|
||||
inline int CListView::HitTest( LVHITTESTINFO& HitTestInfo ) const
|
||||
// Determines which list-view item, if any, is at a specified position.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_HitTest( m_hWnd, &HitTestInfo );
|
||||
}
|
||||
|
||||
inline int CListView::HitTest( CPoint pt, UINT* pFlags /*= NULL*/ ) const
|
||||
// Determines which list-view item, if any, is at a specified position.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
LVHITTESTINFO hti = {0};
|
||||
hti.flags = *pFlags;
|
||||
hti.pt = pt;
|
||||
return ListView_HitTest( m_hWnd, &hti );
|
||||
}
|
||||
|
||||
inline int CListView::InsertColumn( int iCol, const LVCOLUMN& Column ) const
|
||||
// Inserts a new column in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_InsertColumn( m_hWnd, iCol, &Column );
|
||||
}
|
||||
|
||||
inline int CListView::InsertColumn( int iCol, LPCTSTR pszColumnHeading, int iFormat /*= LVCFMT_LEFT*/,
|
||||
int iWidth /*= -1*/, int iSubItem /*= -1*/ ) const
|
||||
// Inserts a new column in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
LVCOLUMN lvc = {0};
|
||||
lvc.mask = LVCF_TEXT|LVCF_ORDER|LVCF_FMT;
|
||||
if (-1 != iWidth)
|
||||
{
|
||||
lvc.mask |= LVCF_WIDTH;
|
||||
lvc.cx = iWidth;
|
||||
}
|
||||
if (-1 != iSubItem)
|
||||
{
|
||||
lvc.mask |= LVCF_SUBITEM;
|
||||
lvc.iSubItem = iSubItem;
|
||||
}
|
||||
|
||||
lvc.iOrder = iCol;
|
||||
lvc.pszText = (LPTSTR)pszColumnHeading;
|
||||
lvc.fmt = iFormat;
|
||||
lvc.iSubItem = iSubItem;
|
||||
return ListView_InsertColumn( m_hWnd, iCol, &lvc );
|
||||
}
|
||||
|
||||
inline int CListView::InsertItem( const LVITEM& Item ) const
|
||||
// Inserts a new item in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_InsertItem( m_hWnd, &Item );
|
||||
}
|
||||
|
||||
inline int CListView::InsertItem( int iItem, LPCTSTR pszText ) const
|
||||
// Inserts a new item in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
LVITEM lvi = {0};
|
||||
lvi.iItem = iItem;
|
||||
lvi.pszText = (LPTSTR)pszText;
|
||||
lvi.mask = LVIF_TEXT;
|
||||
return ListView_InsertItem( m_hWnd, &lvi );
|
||||
}
|
||||
|
||||
inline int CListView::InsertItem( int iItem, LPCTSTR pszText, int iImage ) const
|
||||
// Inserts a new item in a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
LVITEM lvi = {0};
|
||||
lvi.iItem = iItem;
|
||||
lvi.pszText = (LPTSTR)pszText;
|
||||
lvi.iImage = iImage;
|
||||
lvi.mask = LVIF_TEXT | LVIF_IMAGE;
|
||||
return ListView_InsertItem( m_hWnd, &lvi );
|
||||
}
|
||||
|
||||
inline BOOL CListView::RedrawItems( int iFirst, int iLast ) const
|
||||
// Forces a list-view control to redraw a range of items.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_RedrawItems( m_hWnd, iFirst, iLast );
|
||||
}
|
||||
|
||||
inline BOOL CListView::Scroll( CSize sz ) const
|
||||
// Scrolls the content of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_Scroll( m_hWnd, sz.cx, sz.cy );
|
||||
}
|
||||
|
||||
inline BOOL CListView::SortItems( PFNLVCOMPARE pfnCompare, DWORD_PTR dwData ) const
|
||||
// Uses an application-defined comparison function to sort the items of a list-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_SortItems( m_hWnd, pfnCompare, dwData );
|
||||
}
|
||||
|
||||
inline BOOL CListView::Update( int iItem ) const
|
||||
// Updates a list-view item. If the list-view control has the LVS_AUTOARRANGE style,
|
||||
// the list-view control is rearranged.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return ListView_Update( m_hWnd, iItem );
|
||||
}
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // #ifndef _WIN32XX_LISTVIEW_H_
|
||||
|
783
mmc_updater/depends/win32cpp/mdi.h
Normal file
783
mmc_updater/depends/win32cpp/mdi.h
Normal file
@ -0,0 +1,783 @@
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// mdi.h
|
||||
// Declaration of the CMDIChild and CMDIFrame classes
|
||||
|
||||
// The classes defined here add MDI frames support to Win32++. MDI
|
||||
// (Multiple Document Interface) frames host one or more child windows. The
|
||||
// child windows hosted by a MDI frame can be different types. For example,
|
||||
// some MDI child windows could be used to edit text, while others could be
|
||||
// used to display a bitmap. Four classes are defined here to support MDI
|
||||
// frames:
|
||||
|
||||
|
||||
// 1) CMDIFrame. This class inherits from CFrame, and adds the functionality
|
||||
// required by MDI frames. It keeps track of the MDI children created and
|
||||
// destroyed, and adjusts the menu when a MDI child is activated. Use the
|
||||
// AddMDIChild function to add MDI child windows to the MDI frame. Inherit
|
||||
// from CMDIFrame to create your own MDI frame.
|
||||
//
|
||||
// 2) CMDIChild: All MDI child windows (ie. CWnd classes) should inherit from
|
||||
// this class. Each MDI child type can have a different frame menu.
|
||||
|
||||
// Use the MDIFrame generic application as the starting point for your own MDI
|
||||
// frame applications.
|
||||
// Refer to the MDIDemo sample for an example on how to use these classes to
|
||||
// create a MDI frame application with different types of MDI child windows.
|
||||
|
||||
|
||||
#ifndef _WIN32XX_MDI_H_
|
||||
#define _WIN32XX_MDI_H_
|
||||
|
||||
#include "frame.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
class CMDIChild;
|
||||
class CMDIFrame;
|
||||
typedef Shared_Ptr<CMDIChild> MDIChildPtr;
|
||||
|
||||
/////////////////////////////////////
|
||||
// Declaration of the CMDIChild class
|
||||
//
|
||||
class CMDIChild : public CWnd
|
||||
{
|
||||
friend class CMDIFrame;
|
||||
public:
|
||||
CMDIChild();
|
||||
virtual ~CMDIChild();
|
||||
|
||||
// These are the functions you might wish to override
|
||||
virtual HWND Create(CWnd* pParent = NULL);
|
||||
virtual void RecalcLayout();
|
||||
|
||||
// These functions aren't virtual, and shouldn't be overridden
|
||||
void SetHandles(HMENU MenuName, HACCEL AccelName);
|
||||
CMDIFrame* GetMDIFrame() const;
|
||||
CWnd* GetView() const {return m_pView;}
|
||||
void SetView(CWnd& pwndView);
|
||||
void MDIActivate() const;
|
||||
void MDIDestroy() const;
|
||||
void MDIMaximize() const;
|
||||
void MDIRestore() const;
|
||||
|
||||
protected:
|
||||
// Its unlikely you would need to override these functions
|
||||
virtual LRESULT FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
virtual void OnCreate();
|
||||
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
CMDIChild(const CMDIChild&); // Disable copy construction
|
||||
CMDIChild& operator = (const CMDIChild&); // Disable assignment operator
|
||||
|
||||
CWnd* m_pView; // pointer to the View CWnd object
|
||||
HMENU m_hChildMenu;
|
||||
HACCEL m_hChildAccel;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
// Declaration of the CMDIFrame class
|
||||
//
|
||||
class CMDIFrame : public CFrame
|
||||
{
|
||||
friend class CMDIChild; // CMDIChild uses m_hOrigMenu
|
||||
typedef Shared_Ptr<CMDIChild> MDIChildPtr;
|
||||
|
||||
public:
|
||||
class CMDIClient : public CWnd // a nested class within CMDIFrame
|
||||
{
|
||||
public:
|
||||
CMDIClient() {}
|
||||
virtual ~CMDIClient() {}
|
||||
virtual HWND Create(CWnd* pParent = NULL);
|
||||
virtual LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
CMDIFrame* GetMDIFrame() const { return (CMDIFrame*)GetParent(); }
|
||||
|
||||
private:
|
||||
CMDIClient(const CMDIClient&); // Disable copy construction
|
||||
CMDIClient& operator = (const CMDIClient&); // Disable assignment operator
|
||||
};
|
||||
|
||||
|
||||
CMDIFrame();
|
||||
virtual ~CMDIFrame() {}
|
||||
|
||||
virtual CMDIChild* AddMDIChild(MDIChildPtr pMDIChild);
|
||||
virtual CMDIClient& GetMDIClient() const { return (CMDIClient&)m_MDIClient; }
|
||||
virtual BOOL IsMDIFrame() const { return TRUE; }
|
||||
virtual void RemoveMDIChild(HWND hWnd);
|
||||
virtual BOOL RemoveAllMDIChildren();
|
||||
virtual void UpdateCheckMarks();
|
||||
|
||||
// These functions aren't virtual, so don't override them
|
||||
std::vector <MDIChildPtr>& GetAllMDIChildren() {return m_vMDIChild;}
|
||||
CMDIChild* GetActiveMDIChild() const;
|
||||
BOOL IsMDIChildMaxed() const;
|
||||
void MDICascade(int nType = 0) const;
|
||||
void MDIIconArrange() const;
|
||||
void MDIMaximize() const;
|
||||
void MDINext() const;
|
||||
void MDIPrev() const;
|
||||
void MDIRestore() const;
|
||||
void MDITile(int nType = 0) const;
|
||||
void SetActiveMDIChild(CMDIChild* pChild);
|
||||
|
||||
protected:
|
||||
// These are the functions you might wish to override
|
||||
virtual void OnClose();
|
||||
virtual void OnViewStatusBar();
|
||||
virtual void OnViewToolBar();
|
||||
virtual void OnWindowPosChanged();
|
||||
virtual void RecalcLayout();
|
||||
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||||
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
CMDIFrame(const CMDIFrame&); // Disable copy construction
|
||||
CMDIFrame& operator = (const CMDIFrame&); // Disable assignment operator
|
||||
void AppendMDIMenu(HMENU hMenuWindow);
|
||||
LRESULT FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
void UpdateFrameMenu(HMENU hMenu);
|
||||
|
||||
CMDIClient m_MDIClient;
|
||||
std::vector <MDIChildPtr> m_vMDIChild;
|
||||
HWND m_hActiveMDIChild;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
/////////////////////////////////////
|
||||
// Definitions for the CMDIFrame class
|
||||
//
|
||||
inline CMDIFrame::CMDIFrame() : m_hActiveMDIChild(NULL)
|
||||
{
|
||||
SetView(GetMDIClient());
|
||||
}
|
||||
|
||||
inline CMDIChild* CMDIFrame::AddMDIChild(MDIChildPtr pMDIChild)
|
||||
{
|
||||
assert(NULL != pMDIChild.get()); // Cannot add Null MDI Child
|
||||
|
||||
m_vMDIChild.push_back(pMDIChild);
|
||||
pMDIChild->Create(GetView());
|
||||
|
||||
return pMDIChild.get();
|
||||
}
|
||||
|
||||
inline void CMDIFrame::AppendMDIMenu(HMENU hMenuWindow)
|
||||
{
|
||||
// Adds the additional menu items the the "Window" submenu when
|
||||
// MDI child windows are created
|
||||
|
||||
if (!IsMenu(hMenuWindow))
|
||||
return;
|
||||
|
||||
// Delete previously appended items
|
||||
int nItems = ::GetMenuItemCount(hMenuWindow);
|
||||
UINT uLastID = ::GetMenuItemID(hMenuWindow, --nItems);
|
||||
if ((uLastID >= IDW_FIRSTCHILD) && (uLastID < IDW_FIRSTCHILD + 10))
|
||||
{
|
||||
while ((uLastID >= IDW_FIRSTCHILD) && (uLastID < IDW_FIRSTCHILD + 10))
|
||||
{
|
||||
::DeleteMenu(hMenuWindow, nItems, MF_BYPOSITION);
|
||||
uLastID = ::GetMenuItemID(hMenuWindow, --nItems);
|
||||
}
|
||||
//delete the separator too
|
||||
::DeleteMenu(hMenuWindow, nItems, MF_BYPOSITION);
|
||||
}
|
||||
|
||||
int nWindow = 0;
|
||||
|
||||
// Allocate an iterator for our MDIChild vector
|
||||
std::vector <MDIChildPtr>::iterator v;
|
||||
|
||||
for (v = GetAllMDIChildren().begin(); v < GetAllMDIChildren().end(); ++v)
|
||||
{
|
||||
if ((*v)->GetWindowLongPtr(GWL_STYLE) & WS_VISIBLE) // IsWindowVisible is unreliable here
|
||||
{
|
||||
// Add Separator
|
||||
if (0 == nWindow)
|
||||
::AppendMenu(hMenuWindow, MF_SEPARATOR, 0, NULL);
|
||||
|
||||
// Add a menu entry for each MDI child (up to 9)
|
||||
if (nWindow < 9)
|
||||
{
|
||||
tString tsMenuItem ( (*v)->GetWindowText() );
|
||||
|
||||
if (tsMenuItem.length() > MAX_MENU_STRING -10)
|
||||
{
|
||||
// Truncate the string if its too long
|
||||
tsMenuItem.erase(tsMenuItem.length() - MAX_MENU_STRING +10);
|
||||
tsMenuItem += _T(" ...");
|
||||
}
|
||||
|
||||
TCHAR szMenuString[MAX_MENU_STRING+1];
|
||||
wsprintf(szMenuString, _T("&%d %s"), nWindow+1, tsMenuItem.c_str());
|
||||
|
||||
::AppendMenu(hMenuWindow, MF_STRING, IDW_FIRSTCHILD + nWindow, szMenuString);
|
||||
|
||||
if (GetActiveMDIChild() == (*v).get())
|
||||
::CheckMenuItem(hMenuWindow, IDW_FIRSTCHILD+nWindow, MF_CHECKED);
|
||||
|
||||
++nWindow;
|
||||
}
|
||||
else if (9 == nWindow)
|
||||
// For the 10th MDI child, add this menu item and return
|
||||
{
|
||||
::AppendMenu(hMenuWindow, MF_STRING, IDW_FIRSTCHILD + nWindow, _T("&Windows..."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline LRESULT CMDIFrame::FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return ::DefFrameProc(m_hWnd, GetMDIClient(), uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
inline CMDIChild* CMDIFrame::GetActiveMDIChild() const
|
||||
{
|
||||
return (CMDIChild*)FromHandle(m_hActiveMDIChild);
|
||||
}
|
||||
|
||||
inline BOOL CMDIFrame::IsMDIChildMaxed() const
|
||||
{
|
||||
BOOL bMaxed = FALSE;
|
||||
GetMDIClient().SendMessage(WM_MDIGETACTIVE, 0L, (LPARAM)&bMaxed);
|
||||
return bMaxed;
|
||||
}
|
||||
|
||||
inline void CMDIFrame::MDICascade(int nType /* = 0*/) const
|
||||
{
|
||||
// Possible values for nType are:
|
||||
// MDITILE_SKIPDISABLED Prevents disabled MDI child windows from being cascaded.
|
||||
|
||||
assert(::IsWindow(m_hWnd));
|
||||
GetView()->SendMessage(WM_MDICASCADE, (WPARAM)nType, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::MDIIconArrange() const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
GetView()->SendMessage(WM_MDIICONARRANGE, 0L, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::MDIMaximize() const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
GetView()->SendMessage(WM_MDIMAXIMIZE, 0L, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::MDINext() const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
HWND hMDIChild = GetActiveMDIChild()->GetHwnd();
|
||||
GetView()->SendMessage(WM_MDINEXT, (WPARAM)hMDIChild, FALSE);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::MDIPrev() const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
HWND hMDIChild = GetActiveMDIChild()->GetHwnd();
|
||||
GetView()->SendMessage(WM_MDINEXT, (WPARAM)hMDIChild, TRUE);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::MDIRestore() const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
GetView()->SendMessage(WM_MDIRESTORE, 0L, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::MDITile(int nType /* = 0*/) const
|
||||
{
|
||||
// Possible values for nType are:
|
||||
// MDITILE_HORIZONTAL Tiles MDI child windows so that one window appears above another.
|
||||
// MDITILE_SKIPDISABLED Prevents disabled MDI child windows from being tiled.
|
||||
// MDITILE_VERTICAL Tiles MDI child windows so that one window appears beside another.
|
||||
|
||||
assert(::IsWindow(m_hWnd));
|
||||
GetView()->SendMessage(WM_MDITILE, (WPARAM)nType, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::OnClose()
|
||||
{
|
||||
if (RemoveAllMDIChildren())
|
||||
{
|
||||
CFrame::OnClose();
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMDIFrame::OnViewStatusBar()
|
||||
{
|
||||
CFrame::OnViewStatusBar();
|
||||
UpdateCheckMarks();
|
||||
GetView()->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::OnViewToolBar()
|
||||
{
|
||||
CFrame::OnViewToolBar();
|
||||
UpdateCheckMarks();
|
||||
GetView()->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::OnWindowPosChanged()
|
||||
{
|
||||
if (IsMenuBarUsed())
|
||||
{
|
||||
// Refresh MenuBar Window
|
||||
HMENU hMenu= GetMenuBar().GetMenu();
|
||||
GetMenuBar().SetMenu(hMenu);
|
||||
UpdateCheckMarks();
|
||||
}
|
||||
}
|
||||
|
||||
inline BOOL CMDIFrame::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST)
|
||||
{
|
||||
if (TranslateMDISysAccel(GetView()->GetHwnd(), pMsg))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return CFrame::PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
inline void CMDIFrame::RecalcLayout()
|
||||
{
|
||||
CFrame::RecalcLayout();
|
||||
|
||||
if (GetView()->IsWindow())
|
||||
MDIIconArrange();
|
||||
}
|
||||
|
||||
inline BOOL CMDIFrame::RemoveAllMDIChildren()
|
||||
{
|
||||
BOOL bResult = TRUE;
|
||||
int Children = (int)m_vMDIChild.size();
|
||||
|
||||
// Remove the children in reverse order
|
||||
for (int i = Children-1; i >= 0; --i)
|
||||
{
|
||||
if (IDNO == m_vMDIChild[i]->SendMessage(WM_CLOSE, 0L, 0L)) // Also removes the MDI child
|
||||
bResult = FALSE;
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
inline void CMDIFrame::RemoveMDIChild(HWND hWnd)
|
||||
{
|
||||
// Allocate an iterator for our HWND map
|
||||
std::vector <MDIChildPtr>::iterator v;
|
||||
|
||||
for (v = m_vMDIChild.begin(); v!= m_vMDIChild.end(); ++v)
|
||||
{
|
||||
if ((*v)->GetHwnd() == hWnd)
|
||||
{
|
||||
m_vMDIChild.erase(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetActiveMDIChild())
|
||||
{
|
||||
if (GetActiveMDIChild()->m_hChildMenu)
|
||||
UpdateFrameMenu(GetActiveMDIChild()->m_hChildMenu);
|
||||
if (GetActiveMDIChild()->m_hChildAccel)
|
||||
GetApp()->SetAccelerators(GetActiveMDIChild()->m_hChildAccel, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsMenuBarUsed())
|
||||
GetMenuBar().SetMenu(GetFrameMenu());
|
||||
else
|
||||
SetMenu(FromHandle(GetFrameMenu()));
|
||||
|
||||
GetApp()->SetAccelerators(GetFrameAccel(), this);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMDIFrame::SetActiveMDIChild(CMDIChild* pChild)
|
||||
{
|
||||
assert ( pChild->IsWindow() );
|
||||
|
||||
GetMDIClient().SendMessage(WM_MDIACTIVATE, (WPARAM)pChild->GetHwnd(), 0L);
|
||||
|
||||
// Verify
|
||||
assert ( m_hActiveMDIChild == pChild->GetHwnd() );
|
||||
}
|
||||
|
||||
inline void CMDIFrame::UpdateCheckMarks()
|
||||
{
|
||||
if ((GetActiveMDIChild()) && GetActiveMDIChild()->m_hChildMenu)
|
||||
{
|
||||
HMENU hMenu = GetActiveMDIChild()->m_hChildMenu;
|
||||
|
||||
UINT uCheck = GetToolBar().IsWindowVisible()? MF_CHECKED : MF_UNCHECKED;
|
||||
::CheckMenuItem(hMenu, IDW_VIEW_TOOLBAR, uCheck);
|
||||
|
||||
uCheck = GetStatusBar().IsWindowVisible()? MF_CHECKED : MF_UNCHECKED;
|
||||
::CheckMenuItem (hMenu, IDW_VIEW_STATUSBAR, uCheck);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMDIFrame::UpdateFrameMenu(HMENU hMenu)
|
||||
{
|
||||
int nMenuItems = GetMenuItemCount(hMenu);
|
||||
if (nMenuItems > 0)
|
||||
{
|
||||
// The Window menu is typically second from the right
|
||||
int nWindowItem = MAX (nMenuItems -2, 0);
|
||||
HMENU hMenuWindow = ::GetSubMenu (hMenu, nWindowItem);
|
||||
|
||||
if (hMenuWindow)
|
||||
{
|
||||
if (IsMenuBarUsed())
|
||||
{
|
||||
AppendMDIMenu(hMenuWindow);
|
||||
GetMenuBar().SetMenu(hMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetView()->SendMessage (WM_MDISETMENU, (WPARAM) hMenu, (LPARAM)hMenuWindow);
|
||||
DrawMenuBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateCheckMarks();
|
||||
}
|
||||
|
||||
inline LRESULT CMDIFrame::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
OnClose();
|
||||
return 0;
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
// MDI Child or MDI frame has been resized
|
||||
OnWindowPosChanged();
|
||||
break; // Continue with default processing
|
||||
|
||||
} // switch uMsg
|
||||
return CFrame::WndProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
inline HWND CMDIFrame::CMDIClient::Create(CWnd* pParent)
|
||||
{
|
||||
assert(pParent != 0);
|
||||
|
||||
CLIENTCREATESTRUCT clientcreate ;
|
||||
clientcreate.hWindowMenu = m_hWnd;
|
||||
clientcreate.idFirstChild = IDW_FIRSTCHILD ;
|
||||
DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;
|
||||
|
||||
// Create the view window
|
||||
CreateEx(WS_EX_CLIENTEDGE, _T("MDICLient"), TEXT(""), dwStyle, 0, 0, 0, 0, pParent, NULL, (PSTR) &clientcreate);
|
||||
|
||||
return m_hWnd;
|
||||
}
|
||||
|
||||
inline LRESULT CMDIFrame::CMDIClient::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_MDIDESTROY:
|
||||
{
|
||||
// Do default processing first
|
||||
CallWindowProc(GetPrevWindowProc(), uMsg, wParam, lParam);
|
||||
|
||||
// Now remove MDI child
|
||||
GetMDIFrame()->RemoveMDIChild((HWND) wParam);
|
||||
}
|
||||
return 0; // Discard message
|
||||
|
||||
case WM_MDISETMENU:
|
||||
{
|
||||
if (GetMDIFrame()->IsMenuBarUsed())
|
||||
{
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MDIACTIVATE:
|
||||
{
|
||||
// Suppress redraw to avoid flicker when activating maximised MDI children
|
||||
SendMessage(WM_SETREDRAW, FALSE, 0L);
|
||||
LRESULT lr = CallWindowProc(GetPrevWindowProc(), WM_MDIACTIVATE, wParam, lParam);
|
||||
SendMessage(WM_SETREDRAW, TRUE, 0L);
|
||||
RedrawWindow(0, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
|
||||
|
||||
return lr;
|
||||
}
|
||||
}
|
||||
return CWnd::WndProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
//Definitions for the CMDIChild class
|
||||
//
|
||||
inline CMDIChild::CMDIChild() : m_pView(NULL), m_hChildMenu(NULL)
|
||||
{
|
||||
// Set the MDI Child's menu and accelerator in the constructor, like this ...
|
||||
// HMENU hChildMenu = LoadMenu(GetApp()->GetResourceHandle(), _T("MdiMenuView"));
|
||||
// HACCEL hChildAccel = LoadAccelerators(GetApp()->GetResourceHandle(), _T("MDIAccelView"));
|
||||
// SetHandles(hChildMenu, hChildAccel);
|
||||
}
|
||||
|
||||
inline CMDIChild::~CMDIChild()
|
||||
{
|
||||
if (IsWindow())
|
||||
GetParent()->SendMessage(WM_MDIDESTROY, (WPARAM)m_hWnd, 0L);
|
||||
|
||||
if (m_hChildMenu)
|
||||
::DestroyMenu(m_hChildMenu);
|
||||
}
|
||||
|
||||
inline HWND CMDIChild::Create(CWnd* pParent /*= NULL*/)
|
||||
// We create the MDI child window and then maximize if required.
|
||||
// This technique avoids unnecessary flicker when creating maximized MDI children.
|
||||
{
|
||||
//Call PreCreate in case its overloaded
|
||||
PreCreate(*m_pcs);
|
||||
|
||||
//Determine if the window should be created maximized
|
||||
BOOL bMax = FALSE;
|
||||
pParent->SendMessage(WM_MDIGETACTIVE, 0L, (LPARAM)&bMax);
|
||||
bMax = bMax | (m_pcs->style & WS_MAXIMIZE);
|
||||
|
||||
// Set the Window Class Name
|
||||
TCHAR szClassName[MAX_STRING_SIZE + 1] = _T("Win32++ MDI Child");
|
||||
if (m_pcs->lpszClass)
|
||||
lstrcpyn(szClassName, m_pcs->lpszClass, MAX_STRING_SIZE);
|
||||
|
||||
// Set the window style
|
||||
DWORD dwStyle;
|
||||
dwStyle = m_pcs->style & ~WS_MAXIMIZE;
|
||||
dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW ;
|
||||
|
||||
// Set window size and position
|
||||
int x = CW_USEDEFAULT;
|
||||
int y = CW_USEDEFAULT;
|
||||
int cx = CW_USEDEFAULT;
|
||||
int cy = CW_USEDEFAULT;
|
||||
if(m_pcs->cx && m_pcs->cy)
|
||||
{
|
||||
x = m_pcs->x;
|
||||
y = m_pcs->y;
|
||||
cx = m_pcs->cx;
|
||||
cy = m_pcs->cy;
|
||||
}
|
||||
|
||||
// Set the extended style
|
||||
DWORD dwExStyle = m_pcs->dwExStyle | WS_EX_MDICHILD;
|
||||
|
||||
// Turn off redraw while creating the window
|
||||
pParent->SendMessage(WM_SETREDRAW, FALSE, 0L);
|
||||
|
||||
// Create the window
|
||||
if (!CreateEx(dwExStyle, szClassName, m_pcs->lpszName, dwStyle, x, y,
|
||||
cx, cy, pParent, FromHandle(m_pcs->hMenu), m_pcs->lpCreateParams))
|
||||
throw CWinException(_T("CMDIChild::Create ... CreateEx failed"));
|
||||
|
||||
if (bMax)
|
||||
ShowWindow(SW_MAXIMIZE);
|
||||
|
||||
// Turn redraw back on
|
||||
pParent->SendMessage(WM_SETREDRAW, TRUE, 0L);
|
||||
pParent->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
|
||||
|
||||
// Ensure bits revealed by round corners (XP themes) are redrawn
|
||||
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED);
|
||||
|
||||
if (m_hChildMenu)
|
||||
GetMDIFrame()->UpdateFrameMenu(m_hChildMenu);
|
||||
if (m_hChildAccel)
|
||||
GetApp()->SetAccelerators(m_hChildAccel, this);
|
||||
|
||||
return m_hWnd;
|
||||
}
|
||||
|
||||
inline CMDIFrame* CMDIChild::GetMDIFrame() const
|
||||
{
|
||||
CMDIFrame* pMDIFrame = (CMDIFrame*)GetParent()->GetParent();
|
||||
assert(dynamic_cast<CMDIFrame*>(pMDIFrame));
|
||||
return pMDIFrame;
|
||||
}
|
||||
|
||||
inline LRESULT CMDIChild::FinalWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return ::DefMDIChildProc(m_hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
inline void CMDIChild::MDIActivate() const
|
||||
{
|
||||
GetParent()->SendMessage(WM_MDIACTIVATE, (WPARAM)m_hWnd, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIChild::MDIDestroy() const
|
||||
{
|
||||
GetParent()->SendMessage(WM_MDIDESTROY, (WPARAM)m_hWnd, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIChild::MDIMaximize() const
|
||||
{
|
||||
GetParent()->SendMessage(WM_MDIMAXIMIZE, (WPARAM)m_hWnd, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIChild::MDIRestore() const
|
||||
{
|
||||
GetParent()->SendMessage(WM_MDIRESTORE, (WPARAM)m_hWnd, 0L);
|
||||
}
|
||||
|
||||
inline void CMDIChild::OnCreate()
|
||||
{
|
||||
// Create the view window
|
||||
assert(GetView()); // Use SetView in CMDIChild's constructor to set the view window
|
||||
GetView()->Create(this);
|
||||
RecalcLayout();
|
||||
}
|
||||
|
||||
inline void CMDIChild::RecalcLayout()
|
||||
{
|
||||
// Resize the View window
|
||||
CRect rc = GetClientRect();
|
||||
m_pView->SetWindowPos( NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_SHOWWINDOW );
|
||||
}
|
||||
|
||||
inline void CMDIChild::SetHandles(HMENU hMenu, HACCEL hAccel)
|
||||
{
|
||||
m_hChildMenu = hMenu;
|
||||
m_hChildAccel = hAccel;
|
||||
|
||||
// Note: It is valid to call SetChildMenu before the window is created
|
||||
if (IsWindow())
|
||||
{
|
||||
CWnd* pWnd = GetMDIFrame()->GetActiveMDIChild();
|
||||
if (pWnd == this)
|
||||
{
|
||||
if (m_hChildMenu)
|
||||
GetMDIFrame()->UpdateFrameMenu(m_hChildMenu);
|
||||
|
||||
if (m_hChildAccel)
|
||||
GetApp()->SetAccelerators(m_hChildAccel, GetMDIFrame());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMDIChild::SetView(CWnd& wndView)
|
||||
// Sets or changes the View window displayed within the frame
|
||||
{
|
||||
if (m_pView != &wndView)
|
||||
{
|
||||
// Destroy the existing view window (if any)
|
||||
if (m_pView) m_pView->Destroy();
|
||||
|
||||
// Assign the view window
|
||||
m_pView = &wndView;
|
||||
|
||||
if (m_hWnd)
|
||||
{
|
||||
// The frame is already created, so create and position the new view too
|
||||
assert(GetView()); // Use SetView in CMDIChild's constructor to set the view window
|
||||
GetView()->Create(this);
|
||||
RecalcLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline LRESULT CMDIChild::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_MDIACTIVATE:
|
||||
{
|
||||
// This child is being activated
|
||||
if (lParam == (LPARAM) m_hWnd)
|
||||
{
|
||||
GetMDIFrame()->m_hActiveMDIChild = m_hWnd;
|
||||
// Set the menu to child default menu
|
||||
if (m_hChildMenu)
|
||||
GetMDIFrame()->UpdateFrameMenu(m_hChildMenu);
|
||||
if (m_hChildAccel)
|
||||
GetApp()->SetAccelerators(m_hChildAccel, this);
|
||||
}
|
||||
|
||||
// No child is being activated
|
||||
if (0 == lParam)
|
||||
{
|
||||
GetMDIFrame()->m_hActiveMDIChild = NULL;
|
||||
// Set the menu to frame's original menu
|
||||
GetMDIFrame()->UpdateFrameMenu(GetMDIFrame()->GetFrameMenu());
|
||||
GetApp()->SetAccelerators(GetMDIFrame()->GetFrameAccel(), this);
|
||||
}
|
||||
}
|
||||
return 0L ;
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
RecalcLayout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return CWnd::WndProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // _WIN32XX_MDI_H_
|
||||
|
600
mmc_updater/depends/win32cpp/menu.h
Normal file
600
mmc_updater/depends/win32cpp/menu.h
Normal file
@ -0,0 +1,600 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// menu.h
|
||||
// Declaration of the CMenu class
|
||||
|
||||
// Notes
|
||||
// 1) Owner-drawn menus send the WM_MEASUREITEM and WM_DRAWITEM messages
|
||||
// to the window that owns the menu. To manage owner drawing for menus,
|
||||
// handle these two messages in the CWnd's WndProc function.
|
||||
//
|
||||
// 2) The CMenu pointer returned by FromHandle might be a temporary pointer. It
|
||||
// should be used immediately, not saved for later use.
|
||||
//
|
||||
// 3) The CMenu pointers returned by FromHandle or GetSubMenu do not need
|
||||
// to be deleted. They are automatically deleted by the Win32++.
|
||||
//
|
||||
// 4) CMenu pointers returned by GetSubMenu are deleted when the parent CMenu is
|
||||
// detached, destroyed or deconstructed.
|
||||
//
|
||||
// 5) The HMENU that is attached to a CMenu object (using the attach function) is
|
||||
// automatically deleted when the CMenu object goes out of scope. Detach the
|
||||
// HMENU to stop it being deleted when CMenu's destructor is called.
|
||||
//
|
||||
// 6) Pass CMenu objects by reference or by pointer when passing them as function
|
||||
// arguments.
|
||||
//
|
||||
// 7) In those functions that use a MENUITEMINFO structure, its cbSize member is
|
||||
// automatically set to the correct value.
|
||||
|
||||
// Program sample
|
||||
// --------------
|
||||
// void CView::CreatePopup()
|
||||
// {
|
||||
// CPoint pt = GetCursorPos();
|
||||
//
|
||||
// // Create the menu
|
||||
// CMenu Popup;
|
||||
// Popup.CreatePopupMenu();
|
||||
//
|
||||
// // Add some menu items
|
||||
// Popup.AppendMenu(MF_STRING, 101, _T("Menu Item &1"));
|
||||
// Popup.AppendMenu(MF_STRING, 102, _T("Menu Item &2"));
|
||||
// Popup.AppendMenu(MF_STRING, 103, _T("Menu Item &3"));
|
||||
// Popup.AppendMenu(MF_SEPARATOR);
|
||||
// Popup.AppendMenu(MF_STRING, 104, _T("Menu Item &4"));
|
||||
//
|
||||
// // Set menu item states
|
||||
// Popup.CheckMenuRadioItem(101, 101, 101, MF_BYCOMMAND);
|
||||
// Popup.CheckMenuItem(102, MF_BYCOMMAND | MF_CHECKED);
|
||||
// Popup.EnableMenuItem(103, MF_BYCOMMAND | MF_GRAYED);
|
||||
// Popup.SetDefaultItem(104);
|
||||
//
|
||||
// // Display the popup menu
|
||||
// Popup.TrackPopupMenu(0, pt.x, pt.y, this);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
#if !defined(_WIN32XX_MENU_H_) && !defined(_WIN32_WCE)
|
||||
#define _WIN32XX_MENU_H_
|
||||
|
||||
|
||||
#include "wincore.h"
|
||||
#include "gdi.h"
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
// Forward declarations
|
||||
class CBitmap;
|
||||
|
||||
class CMenu
|
||||
{
|
||||
friend class CWinApp;
|
||||
|
||||
public:
|
||||
//Construction
|
||||
CMenu() : m_hMenu(0), m_IsTmpMenu(FALSE) {}
|
||||
CMenu(UINT nID) : m_IsTmpMenu(FALSE)
|
||||
{
|
||||
m_hMenu = ::LoadMenu(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(nID));
|
||||
}
|
||||
~CMenu();
|
||||
|
||||
//Initialization
|
||||
void Attach(HMENU hMenu);
|
||||
void CreateMenu();
|
||||
void CreatePopupMenu();
|
||||
void DestroyMenu();
|
||||
HMENU Detach();
|
||||
HMENU GetHandle() const;
|
||||
BOOL LoadMenu(LPCTSTR lpszResourceName);
|
||||
BOOL LoadMenu(UINT uIDResource);
|
||||
BOOL LoadMenuIndirect(const void* lpMenuTemplate);
|
||||
|
||||
//Menu Operations
|
||||
BOOL TrackPopupMenu(UINT uFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = 0);
|
||||
BOOL TrackPopupMenuEx(UINT uFlags, int x, int y, CWnd* pWnd, LPTPMPARAMS lptpm);
|
||||
|
||||
//Menu Item Operations
|
||||
BOOL AppendMenu(UINT uFlags, UINT_PTR uIDNewItem = 0, LPCTSTR lpszNewItem = NULL);
|
||||
BOOL AppendMenu(UINT uFlags, UINT_PTR uIDNewItem, const CBitmap* pBmp);
|
||||
UINT CheckMenuItem(UINT uIDCheckItem, UINT uCheck);
|
||||
BOOL CheckMenuRadioItem(UINT uIDFirst, UINT uIDLast, UINT uIDItem, UINT uFlags);
|
||||
BOOL DeleteMenu(UINT uPosition, UINT uFlags);
|
||||
UINT EnableMenuItem(UINT uIDEnableItem, UINT uEnable);
|
||||
UINT GetDefaultItem(UINT gmdiFlags, BOOL fByPos = FALSE);
|
||||
DWORD GetMenuContextHelpId() const;
|
||||
|
||||
#if(WINVER >= 0x0500) // Minimum OS required is Win2000
|
||||
BOOL GetMenuInfo(LPMENUINFO lpcmi) const;
|
||||
BOOL SetMenuInfo(LPCMENUINFO lpcmi);
|
||||
#endif
|
||||
|
||||
UINT GetMenuItemCount() const;
|
||||
UINT GetMenuItemID(int nPos) const;
|
||||
BOOL GetMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE);
|
||||
UINT GetMenuState(UINT uID, UINT uFlags) const;
|
||||
int GetMenuString(UINT uIDItem, LPTSTR lpString, int nMaxCount, UINT uFlags) const;
|
||||
int GetMenuString(UINT uIDItem, CString& rString, UINT uFlags) const;
|
||||
CMenu* GetSubMenu(int nPos);
|
||||
BOOL InsertMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem = 0, LPCTSTR lpszNewItem = NULL);
|
||||
BOOL InsertMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const CBitmap* pBmp);
|
||||
BOOL InsertMenuItem(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE);
|
||||
BOOL ModifyMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem = 0, LPCTSTR lpszNewItem = NULL);
|
||||
BOOL ModifyMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const CBitmap* pBmp);
|
||||
BOOL RemoveMenu(UINT uPosition, UINT uFlags);
|
||||
BOOL SetDefaultItem(UINT uItem, BOOL fByPos = FALSE);
|
||||
BOOL SetMenuContextHelpId(DWORD dwContextHelpId);
|
||||
BOOL SetMenuItemBitmaps(UINT uPosition, UINT uFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked);
|
||||
BOOL SetMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE);
|
||||
|
||||
//Operators
|
||||
BOOL operator != (const CMenu& menu) const;
|
||||
BOOL operator == (const CMenu& menu) const;
|
||||
operator HMENU () const;
|
||||
|
||||
private:
|
||||
CMenu(const CMenu&); // Disable copy construction
|
||||
CMenu& operator = (const CMenu&); // Disable assignment operator
|
||||
void AddToMap();
|
||||
BOOL RemoveFromMap();
|
||||
std::vector<MenuPtr> m_vSubMenus; // A vector of smart pointers to CMenu
|
||||
HMENU m_hMenu;
|
||||
BOOL m_IsTmpMenu;
|
||||
};
|
||||
|
||||
inline CMenu::~CMenu()
|
||||
{
|
||||
if (m_hMenu)
|
||||
{
|
||||
if (!m_IsTmpMenu)
|
||||
{
|
||||
::DestroyMenu(m_hMenu);
|
||||
}
|
||||
|
||||
RemoveFromMap();
|
||||
}
|
||||
|
||||
m_vSubMenus.clear();
|
||||
}
|
||||
|
||||
inline void CMenu::AddToMap()
|
||||
// Store the HMENU and CMenu pointer in the HMENU map
|
||||
{
|
||||
assert( GetApp() );
|
||||
assert(m_hMenu);
|
||||
|
||||
GetApp()->m_csMapLock.Lock();
|
||||
GetApp()->m_mapHMENU.insert(std::make_pair(m_hMenu, this));
|
||||
GetApp()->m_csMapLock.Release();
|
||||
}
|
||||
|
||||
inline BOOL CMenu::RemoveFromMap()
|
||||
{
|
||||
BOOL Success = FALSE;
|
||||
|
||||
if (GetApp())
|
||||
{
|
||||
// Allocate an iterator for our HDC map
|
||||
std::map<HMENU, CMenu*, CompareHMENU>::iterator m;
|
||||
|
||||
CWinApp* pApp = GetApp();
|
||||
if (pApp)
|
||||
{
|
||||
// Erase the CDC pointer entry from the map
|
||||
pApp->m_csMapLock.Lock();
|
||||
for (m = pApp->m_mapHMENU.begin(); m != pApp->m_mapHMENU.end(); ++m)
|
||||
{
|
||||
if (this == m->second)
|
||||
{
|
||||
pApp->m_mapHMENU.erase(m);
|
||||
Success = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pApp->m_csMapLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
inline BOOL CMenu::AppendMenu(UINT uFlags, UINT_PTR uIDNewItem /*= 0*/, LPCTSTR lpszNewItem /*= NULL*/)
|
||||
// Appends a new item to the end of the specified menu bar, drop-down menu, submenu, or shortcut menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::AppendMenu(m_hMenu, uFlags, uIDNewItem, lpszNewItem);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::AppendMenu(UINT uFlags, UINT_PTR uIDNewItem, const CBitmap* pBmp)
|
||||
// Appends a new item to the end of the specified menu bar, drop-down menu, submenu, or shortcut menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
assert(pBmp);
|
||||
return ::AppendMenu(m_hMenu, uFlags, uIDNewItem, (LPCTSTR)pBmp->GetHandle());
|
||||
}
|
||||
|
||||
inline void CMenu::Attach(HMENU hMenu)
|
||||
// Attaches an existing menu to this CMenu
|
||||
{
|
||||
if (m_hMenu != NULL && m_hMenu != hMenu)
|
||||
{
|
||||
::DestroyMenu(Detach());
|
||||
}
|
||||
|
||||
if (hMenu)
|
||||
{
|
||||
m_hMenu = hMenu;
|
||||
AddToMap();
|
||||
}
|
||||
}
|
||||
|
||||
inline UINT CMenu::CheckMenuItem(UINT uIDCheckItem, UINT uCheck)
|
||||
// Sets the state of the specified menu item's check-mark attribute to either selected or clear.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::CheckMenuItem(m_hMenu, uIDCheckItem, uCheck);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::CheckMenuRadioItem(UINT uIDFirst, UINT uIDLast, UINT uIDItem, UINT uFlags)
|
||||
// Checks a specified menu item and makes it a radio item. At the same time, the function clears
|
||||
// all other menu items in the associated group and clears the radio-item type flag for those items.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::CheckMenuRadioItem(m_hMenu, uIDFirst, uIDLast, uIDItem, uFlags);
|
||||
}
|
||||
|
||||
inline void CMenu::CreateMenu()
|
||||
// Creates an empty menu.
|
||||
{
|
||||
assert(NULL == m_hMenu);
|
||||
m_hMenu = ::CreateMenu();
|
||||
AddToMap();
|
||||
}
|
||||
|
||||
inline void CMenu::CreatePopupMenu()
|
||||
// Creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty.
|
||||
{
|
||||
assert(NULL == m_hMenu);
|
||||
m_hMenu = ::CreatePopupMenu();
|
||||
AddToMap();
|
||||
}
|
||||
|
||||
inline BOOL CMenu::DeleteMenu(UINT uPosition, UINT uFlags)
|
||||
// Deletes an item from the specified menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::DeleteMenu(m_hMenu, uPosition, uFlags);
|
||||
}
|
||||
|
||||
inline void CMenu::DestroyMenu()
|
||||
// Destroys the menu and frees any memory that the menu occupies.
|
||||
{
|
||||
if (::IsMenu(m_hMenu))
|
||||
::DestroyMenu(m_hMenu);
|
||||
|
||||
m_hMenu = 0;
|
||||
RemoveFromMap();
|
||||
m_vSubMenus.clear();
|
||||
}
|
||||
|
||||
inline HMENU CMenu::Detach()
|
||||
// Detaches the HMENU from this CMenu. If the HMENU is not detached it will be
|
||||
// destroyed when this CMenu is deconstructed.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
HMENU hMenu = m_hMenu;
|
||||
m_hMenu = 0;
|
||||
RemoveFromMap();
|
||||
m_vSubMenus.clear();
|
||||
return hMenu;
|
||||
}
|
||||
|
||||
inline HMENU CMenu::GetHandle() const
|
||||
// Returns the HMENU assigned to this CMenu
|
||||
{
|
||||
return m_hMenu;
|
||||
}
|
||||
|
||||
inline UINT CMenu::EnableMenuItem(UINT uIDEnableItem, UINT uEnable)
|
||||
// Enables, disables, or grays the specified menu item.
|
||||
// The uEnable parameter must be a combination of either MF_BYCOMMAND or MF_BYPOSITION
|
||||
// and MF_ENABLED, MF_DISABLED, or MF_GRAYED.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::EnableMenuItem(m_hMenu, uIDEnableItem, uEnable);
|
||||
}
|
||||
|
||||
inline UINT CMenu::GetDefaultItem(UINT gmdiFlags, BOOL fByPos /*= FALSE*/)
|
||||
// Determines the default menu item.
|
||||
// The gmdiFlags parameter specifies how the function searches for menu items.
|
||||
// This parameter can be zero or more of the following values: GMDI_GOINTOPOPUPS; GMDI_USEDISABLED.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::GetMenuDefaultItem(m_hMenu, fByPos, gmdiFlags);
|
||||
}
|
||||
|
||||
inline DWORD CMenu::GetMenuContextHelpId() const
|
||||
// Retrieves the Help context identifier associated with the menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::GetMenuContextHelpId(m_hMenu);
|
||||
}
|
||||
|
||||
#if(WINVER >= 0x0500)
|
||||
// minimum OS required : Win2000
|
||||
|
||||
inline BOOL CMenu::GetMenuInfo(LPMENUINFO lpcmi) const
|
||||
// Retrieves the menu information.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::GetMenuInfo(m_hMenu, lpcmi);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::SetMenuInfo(LPCMENUINFO lpcmi)
|
||||
// Sets the menu information from the specified MENUINFO structure.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::SetMenuInfo(m_hMenu, lpcmi);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline UINT CMenu::GetMenuItemCount() const
|
||||
// Retrieves the number of menu items.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::GetMenuItemCount(m_hMenu);
|
||||
}
|
||||
|
||||
inline UINT CMenu::GetMenuItemID(int nPos) const
|
||||
// Retrieves the menu item identifier of a menu item located at the specified position
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::GetMenuItemID(m_hMenu, nPos);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::GetMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos /*= FALSE*/)
|
||||
// retrieves information about the specified menu item.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
assert(lpMenuItemInfo);
|
||||
lpMenuItemInfo->cbSize = GetSizeofMenuItemInfo();
|
||||
return ::GetMenuItemInfo(m_hMenu, uItem, fByPos, lpMenuItemInfo);
|
||||
}
|
||||
|
||||
inline UINT CMenu::GetMenuState(UINT uID, UINT uFlags) const
|
||||
// Retrieves the menu flags associated with the specified menu item.
|
||||
// Possible values for uFlags are: MF_BYCOMMAND (default) or MF_BYPOSITION.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::GetMenuState(m_hMenu, uID, uFlags);
|
||||
}
|
||||
|
||||
inline int CMenu::GetMenuString(UINT uIDItem, LPTSTR lpString, int nMaxCount, UINT uFlags) const
|
||||
// Copies the text string of the specified menu item into the specified buffer.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
assert(lpString);
|
||||
return ::GetMenuString(m_hMenu, uIDItem, lpString, nMaxCount, uFlags);
|
||||
}
|
||||
|
||||
inline int CMenu::GetMenuString(UINT uIDItem, CString& rString, UINT uFlags) const
|
||||
// Copies the text string of the specified menu item into the specified buffer.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::GetMenuString(m_hMenu, uIDItem, (LPTSTR)rString.c_str(), rString.GetLength(), uFlags);
|
||||
}
|
||||
|
||||
inline CMenu* CMenu::GetSubMenu(int nPos)
|
||||
// Retrieves the CMenu object of a pop-up menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
CMenu* pMenu = new CMenu;
|
||||
pMenu->m_hMenu = ::GetSubMenu(m_hMenu, nPos);
|
||||
pMenu->m_IsTmpMenu = TRUE;
|
||||
m_vSubMenus.push_back(pMenu);
|
||||
return pMenu;
|
||||
}
|
||||
|
||||
inline BOOL CMenu::InsertMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem /*= 0*/, LPCTSTR lpszNewItem /*= NULL*/)
|
||||
// Inserts a new menu item into a menu, moving other items down the menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::InsertMenu(m_hMenu, uPosition, uFlags, uIDNewItem, lpszNewItem);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::InsertMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const CBitmap* pBmp)
|
||||
// Inserts a new menu item into a menu, moving other items down the menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::InsertMenu(m_hMenu, uPosition, uFlags, uIDNewItem, (LPCTSTR)pBmp->GetHandle());
|
||||
}
|
||||
|
||||
inline BOOL CMenu::InsertMenuItem(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos /*= FALSE*/)
|
||||
// Inserts a new menu item at the specified position in a menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
assert(lpMenuItemInfo);
|
||||
lpMenuItemInfo->cbSize = GetSizeofMenuItemInfo();
|
||||
return ::InsertMenuItem(m_hMenu, uItem, fByPos, lpMenuItemInfo);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::LoadMenu(LPCTSTR lpszResourceName)
|
||||
// Loads the menu from the specified windows resource.
|
||||
{
|
||||
assert(NULL == m_hMenu);
|
||||
assert(lpszResourceName);
|
||||
m_hMenu = ::LoadMenu(GetApp()->GetResourceHandle(), lpszResourceName);
|
||||
if (m_hMenu) AddToMap();
|
||||
return NULL != m_hMenu;
|
||||
}
|
||||
|
||||
inline BOOL CMenu::LoadMenu(UINT uIDResource)
|
||||
// Loads the menu from the specified windows resource.
|
||||
{
|
||||
assert(NULL == m_hMenu);
|
||||
m_hMenu = ::LoadMenu(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(uIDResource));
|
||||
if (m_hMenu) AddToMap();
|
||||
return NULL != m_hMenu;
|
||||
}
|
||||
|
||||
inline BOOL CMenu::LoadMenuIndirect(const void* lpMenuTemplate)
|
||||
// Loads the specified menu template and assigns it to this CMenu.
|
||||
{
|
||||
assert(NULL == m_hMenu);
|
||||
assert(lpMenuTemplate);
|
||||
m_hMenu = ::LoadMenuIndirect(lpMenuTemplate);
|
||||
if (m_hMenu) AddToMap();
|
||||
return NULL != m_hMenu;
|
||||
}
|
||||
|
||||
inline BOOL CMenu::ModifyMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem /*= 0*/, LPCTSTR lpszNewItem /*= NULL*/)
|
||||
// Changes an existing menu item. This function is used to specify the content, appearance, and behavior of the menu item.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::ModifyMenu(m_hMenu, uPosition, uFlags, uIDNewItem, lpszNewItem);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::ModifyMenu(UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, const CBitmap* pBmp)
|
||||
// Changes an existing menu item. This function is used to specify the content, appearance, and behavior of the menu item.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
assert(pBmp);
|
||||
return ::ModifyMenu(m_hMenu, uPosition, uFlags, uIDNewItem, (LPCTSTR)pBmp->GetHandle());
|
||||
}
|
||||
|
||||
inline BOOL CMenu::RemoveMenu(UINT uPosition, UINT uFlags)
|
||||
// Deletes a menu item or detaches a submenu from the menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::RemoveMenu(m_hMenu, uPosition, uFlags);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::SetDefaultItem(UINT uItem, BOOL fByPos /*= FALSE*/)
|
||||
// sets the default menu item for the menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::SetMenuDefaultItem(m_hMenu, uItem, fByPos);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::SetMenuContextHelpId(DWORD dwContextHelpId)
|
||||
// Associates a Help context identifier with the menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::SetMenuContextHelpId(m_hMenu, dwContextHelpId);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::SetMenuItemBitmaps(UINT uPosition, UINT uFlags, const CBitmap* pBmpUnchecked, const CBitmap* pBmpChecked)
|
||||
// Associates the specified bitmap with a menu item.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
return ::SetMenuItemBitmaps(m_hMenu, uPosition, uFlags, *pBmpUnchecked, *pBmpChecked);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::SetMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos /*= FALSE*/)
|
||||
// Changes information about a menu item.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
assert(lpMenuItemInfo);
|
||||
lpMenuItemInfo->cbSize = GetSizeofMenuItemInfo();
|
||||
return ::SetMenuItemInfo(m_hMenu, uItem, fByPos, lpMenuItemInfo);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::TrackPopupMenu(UINT uFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect /*= 0*/)
|
||||
// Displays a shortcut menu at the specified location and tracks the selection of items on the menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
HWND hWnd = pWnd? pWnd->GetHwnd() : 0;
|
||||
return ::TrackPopupMenu(m_hMenu, uFlags, x, y, 0, hWnd, lpRect);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::TrackPopupMenuEx(UINT uFlags, int x, int y, CWnd* pWnd, LPTPMPARAMS lptpm)
|
||||
// Displays a shortcut menu at the specified location and tracks the selection of items on the shortcut menu.
|
||||
{
|
||||
assert(IsMenu(m_hMenu));
|
||||
HWND hWnd = pWnd? pWnd->GetHwnd() : 0;
|
||||
return ::TrackPopupMenuEx(m_hMenu, uFlags, x, y, hWnd, lptpm);
|
||||
}
|
||||
|
||||
inline BOOL CMenu::operator != (const CMenu& menu) const
|
||||
// Returns TRUE if the two menu objects are not equal.
|
||||
{
|
||||
return menu.m_hMenu != m_hMenu;
|
||||
}
|
||||
|
||||
inline BOOL CMenu::operator == (const CMenu& menu) const
|
||||
// Returns TRUE of the two menu object are equal
|
||||
{
|
||||
return menu.m_hMenu == m_hMenu;
|
||||
}
|
||||
|
||||
inline CMenu::operator HMENU () const
|
||||
// Retrieves the menu's handle.
|
||||
{
|
||||
return m_hMenu;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// Global functions
|
||||
//
|
||||
|
||||
inline CMenu* FromHandle(HMENU hMenu)
|
||||
// Returns the CMenu object associated with the menu handle (HMENU).
|
||||
{
|
||||
assert( GetApp() );
|
||||
CMenu* pMenu = GetApp()->GetCMenuFromMap(hMenu);
|
||||
if (::IsMenu(hMenu) && pMenu == 0)
|
||||
{
|
||||
GetApp()->AddTmpMenu(hMenu);
|
||||
pMenu = GetApp()->GetCMenuFromMap(hMenu);
|
||||
}
|
||||
return pMenu;
|
||||
}
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // _WIN32XX_MENU_H_
|
||||
|
960
mmc_updater/depends/win32cpp/propertysheet.h
Normal file
960
mmc_updater/depends/win32cpp/propertysheet.h
Normal file
@ -0,0 +1,960 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// propertysheet.h
|
||||
// Declaration of the following classes:
|
||||
// CPropertyPage and CPropertySheet
|
||||
|
||||
// These classes add support for property sheets to Win32++. A property sheet
|
||||
// will have one or more property pages. These pages are much like dialogs
|
||||
// which are presented within a tabbed dialog or within a wizard. The data
|
||||
// on a property page can be validated before the next page is presented.
|
||||
// Property sheets have three modes of use: Modal, Modeless, and Wizard.
|
||||
//
|
||||
// Refer to the PropertySheet demo program for an example of how propert sheets
|
||||
// can be used.
|
||||
|
||||
|
||||
#ifndef _WIN32XX_PROPERTYSHEET_H_
|
||||
#define _WIN32XX_PROPERTYSHEET_H_
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
#define ID_APPLY_NOW 0x3021
|
||||
#define ID_WIZBACK 0x3023
|
||||
#define ID_WIZNEXT 0x3024
|
||||
#define ID_WIZFINISH 0x3025
|
||||
#define ID_HELP 0xE146
|
||||
|
||||
#ifndef PROPSHEETHEADER_V1_SIZE
|
||||
#define PROPSHEETHEADER_V1_SIZE 40
|
||||
#endif
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
class CPropertyPage;
|
||||
typedef Shared_Ptr<CPropertyPage> PropertyPagePtr;
|
||||
|
||||
class CPropertyPage : public CWnd
|
||||
{
|
||||
public:
|
||||
CPropertyPage (UINT nIDTemplate, LPCTSTR szTitle = NULL);
|
||||
virtual ~CPropertyPage() {}
|
||||
|
||||
virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
virtual INT_PTR DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
virtual int OnApply();
|
||||
virtual void OnCancel();
|
||||
virtual void OnHelp();
|
||||
virtual BOOL OnInitDialog();
|
||||
virtual BOOL OnKillActive();
|
||||
virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);
|
||||
virtual int OnOK();
|
||||
virtual BOOL OnQueryCancel();
|
||||
virtual BOOL OnQuerySiblings(WPARAM wParam, LPARAM lParam);
|
||||
virtual int OnSetActive();
|
||||
virtual int OnWizardBack();
|
||||
virtual INT_PTR OnWizardFinish();
|
||||
virtual int OnWizardNext();
|
||||
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||||
|
||||
static UINT CALLBACK StaticPropSheetPageProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp);
|
||||
static INT_PTR CALLBACK StaticDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void CancelToClose() const;
|
||||
PROPSHEETPAGE GetPSP() const {return m_PSP;}
|
||||
BOOL IsButtonEnabled(int iButton) const;
|
||||
LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) const;
|
||||
void SetModified(BOOL bChanged) const;
|
||||
void SetTitle(LPCTSTR szTitle);
|
||||
void SetWizardButtons(DWORD dwFlags) const;
|
||||
|
||||
protected:
|
||||
PROPSHEETPAGE m_PSP;
|
||||
|
||||
private:
|
||||
CPropertyPage(const CPropertyPage&); // Disable copy construction
|
||||
CPropertyPage& operator = (const CPropertyPage&); // Disable assignment operator
|
||||
|
||||
tString m_Title;
|
||||
};
|
||||
|
||||
class CPropertySheet : public CWnd
|
||||
{
|
||||
public:
|
||||
CPropertySheet(UINT nIDCaption, CWnd* pParent = NULL);
|
||||
CPropertySheet(LPCTSTR pszCaption = NULL, CWnd* pParent = NULL);
|
||||
virtual ~CPropertySheet() {}
|
||||
|
||||
// Operations
|
||||
virtual CPropertyPage* AddPage(CPropertyPage* pPage);
|
||||
virtual HWND Create(CWnd* pParent = 0);
|
||||
virtual INT_PTR CreatePropertySheet(LPCPROPSHEETHEADER ppsph);
|
||||
virtual void DestroyButton(int iButton);
|
||||
virtual void Destroy();
|
||||
virtual int DoModal();
|
||||
virtual void RemovePage(CPropertyPage* pPage);
|
||||
|
||||
// State functions
|
||||
BOOL IsModeless() const;
|
||||
BOOL IsWizard() const;
|
||||
|
||||
//Attributes
|
||||
CPropertyPage* GetActivePage() const;
|
||||
int GetPageCount() const;
|
||||
int GetPageIndex(CPropertyPage* pPage) const;
|
||||
HWND GetTabControl() const;
|
||||
virtual BOOL SetActivePage(int nPage);
|
||||
virtual BOOL SetActivePage(CPropertyPage* pPage);
|
||||
virtual void SetIcon(UINT idIcon);
|
||||
virtual void SetTitle(LPCTSTR szTitle);
|
||||
virtual void SetWizardMode(BOOL bWizard);
|
||||
|
||||
protected:
|
||||
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||||
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
CPropertySheet(const CPropertySheet&); // Disable copy construction
|
||||
CPropertySheet& operator = (const CPropertySheet&); // Disable assignment operator
|
||||
void BuildPageArray();
|
||||
static void CALLBACK Callback(HWND hwnd, UINT uMsg, LPARAM lParam);
|
||||
|
||||
tString m_Title;
|
||||
std::vector<PropertyPagePtr> m_vPages; // vector of CPropertyPage
|
||||
std::vector<PROPSHEETPAGE> m_vPSP; // vector of PROPSHEETPAGE
|
||||
BOOL m_bInitialUpdate;
|
||||
PROPSHEETHEADER m_PSH;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Definitions for the CPropertyPage class
|
||||
//
|
||||
inline CPropertyPage::CPropertyPage(UINT nIDTemplate, LPCTSTR szTitle /* = NULL*/)
|
||||
{
|
||||
ZeroMemory(&m_PSP, sizeof(PROPSHEETPAGE));
|
||||
SetTitle(szTitle);
|
||||
|
||||
m_PSP.dwSize = sizeof(PROPSHEETPAGE);
|
||||
m_PSP.dwFlags |= PSP_USECALLBACK;
|
||||
m_PSP.hInstance = GetApp()->GetResourceHandle();
|
||||
m_PSP.pszTemplate = MAKEINTRESOURCE(nIDTemplate);
|
||||
m_PSP.pszTitle = m_Title.c_str();
|
||||
m_PSP.pfnDlgProc = (DLGPROC)CPropertyPage::StaticDialogProc;
|
||||
m_PSP.lParam = (LPARAM)this;
|
||||
m_PSP.pfnCallback = CPropertyPage::StaticPropSheetPageProc;
|
||||
}
|
||||
|
||||
inline void CPropertyPage::CancelToClose() const
|
||||
// Disables the Cancel button and changes the text of the OK button to "Close."
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
SendMessage(PSM_CANCELTOCLOSE, 0L, 0L);
|
||||
}
|
||||
|
||||
|
||||
inline INT_PTR CPropertyPage::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Override this function in your class derrived from CPropertyPage if you wish to handle messages
|
||||
// A typical function might look like this:
|
||||
|
||||
// switch (uMsg)
|
||||
// {
|
||||
// case MESSAGE1: // Some Win32 API message
|
||||
// OnMessage1(); // A user defined function
|
||||
// break; // Also do default processing
|
||||
// case MESSAGE2:
|
||||
// OnMessage2();
|
||||
// return x; // Don't do default processing, but instead return
|
||||
// // a value recommended by the Win32 API documentation
|
||||
// }
|
||||
|
||||
// Always pass unhandled messages on to DialogProcDefault
|
||||
return DialogProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
inline INT_PTR CPropertyPage::DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
// All DialogProc functions should pass unhandled messages to this function
|
||||
{
|
||||
LRESULT lr = 0L;
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case UWM_CLEANUPTEMPS:
|
||||
{
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
pTLSData->vTmpWnds.clear();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_INITDIALOG:
|
||||
return OnInitDialog();
|
||||
|
||||
case PSM_QUERYSIBLINGS:
|
||||
return (BOOL)OnQuerySiblings(wParam, lParam);
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
// Refelect this message if it's from a control
|
||||
CWnd* pWnd = GetApp()->GetCWndFromMap((HWND)lParam);
|
||||
if (pWnd != NULL)
|
||||
lr = pWnd->OnCommand(wParam, lParam);
|
||||
|
||||
// Handle user commands
|
||||
if (!lr)
|
||||
lr = OnCommand(wParam, lParam);
|
||||
|
||||
if (lr) return 0L;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_NOTIFY:
|
||||
{
|
||||
// Do Notification reflection if it came from a CWnd object
|
||||
HWND hwndFrom = ((LPNMHDR)lParam)->hwndFrom;
|
||||
CWnd* pWndFrom = GetApp()->GetCWndFromMap(hwndFrom);
|
||||
|
||||
if (pWndFrom != NULL)
|
||||
lr = pWndFrom->OnNotifyReflect(wParam, lParam);
|
||||
else
|
||||
{
|
||||
// Some controls (eg ListView) have child windows.
|
||||
// Reflect those notifications too.
|
||||
CWnd* pWndFromParent = GetApp()->GetCWndFromMap(::GetParent(hwndFrom));
|
||||
if (pWndFromParent != NULL)
|
||||
lr = pWndFromParent->OnNotifyReflect(wParam, lParam);
|
||||
}
|
||||
|
||||
// Handle user notifications
|
||||
if (!lr) lr = OnNotify(wParam, lParam);
|
||||
|
||||
// Set the return code for notifications
|
||||
if (IsWindow())
|
||||
SetWindowLongPtr(DWLP_MSGRESULT, (LONG_PTR)lr);
|
||||
|
||||
return (BOOL)lr;
|
||||
}
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (::GetUpdateRect(m_hWnd, NULL, FALSE))
|
||||
{
|
||||
CPaintDC dc(this);
|
||||
OnDraw(&dc);
|
||||
}
|
||||
else
|
||||
// RedrawWindow can require repainting without an update rect
|
||||
{
|
||||
CClientDC dc(this);
|
||||
OnDraw(&dc);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
{
|
||||
CDC dc((HDC)wParam);
|
||||
BOOL bResult = OnEraseBkgnd(&dc);
|
||||
dc.Detach();
|
||||
if (bResult) return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
// A set of messages to be reflected back to the control that generated them
|
||||
case WM_CTLCOLORBTN:
|
||||
case WM_CTLCOLOREDIT:
|
||||
case WM_CTLCOLORDLG:
|
||||
case WM_CTLCOLORLISTBOX:
|
||||
case WM_CTLCOLORSCROLLBAR:
|
||||
case WM_CTLCOLORSTATIC:
|
||||
case WM_DRAWITEM:
|
||||
case WM_MEASUREITEM:
|
||||
case WM_DELETEITEM:
|
||||
case WM_COMPAREITEM:
|
||||
case WM_CHARTOITEM:
|
||||
case WM_VKEYTOITEM:
|
||||
case WM_HSCROLL:
|
||||
case WM_VSCROLL:
|
||||
case WM_PARENTNOTIFY:
|
||||
return MessageReflect(m_hWnd, uMsg, wParam, lParam);
|
||||
|
||||
} // switch(uMsg)
|
||||
return FALSE;
|
||||
|
||||
} // INT_PTR CALLBACK CPropertyPage::DialogProc(...)
|
||||
|
||||
inline BOOL CPropertyPage::IsButtonEnabled(int iButton) const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return GetParent()->GetDlgItem(iButton)->IsWindowEnabled();
|
||||
}
|
||||
|
||||
inline int CPropertyPage::OnApply()
|
||||
{
|
||||
// This function is called for each page when the Apply button is pressed
|
||||
// Override this function in your derived class if required.
|
||||
|
||||
// The possible return values are:
|
||||
// PSNRET_NOERROR. The changes made to this page are valid and have been applied
|
||||
// PSNRET_INVALID. The property sheet will not be destroyed, and focus will be returned to this page.
|
||||
// PSNRET_INVALID_NOCHANGEPAGE. The property sheet will not be destroyed, and focus will be returned;
|
||||
|
||||
return PSNRET_NOERROR;
|
||||
}
|
||||
|
||||
inline void CPropertyPage::OnCancel()
|
||||
{
|
||||
// This function is called for each page when the Cancel button is pressed
|
||||
// Override this function in your derived class if required.
|
||||
}
|
||||
|
||||
inline void CPropertyPage::OnHelp()
|
||||
{
|
||||
// This function is called in response to the PSN_HELP notification.
|
||||
SendMessage(m_hWnd, WM_COMMAND, ID_HELP, 0L);
|
||||
}
|
||||
|
||||
inline BOOL CPropertyPage::OnQueryCancel()
|
||||
{
|
||||
// Called when the cancel button is pressed, and before the cancel has taken place
|
||||
// Returns TRUE to prevent the cancel operation, or FALSE to allow it.
|
||||
|
||||
return FALSE; // Allow cancel to proceed
|
||||
}
|
||||
|
||||
inline BOOL CPropertyPage::OnQuerySiblings(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
|
||||
// Responds to a query request from the Property Sheet.
|
||||
// The values for wParam and lParam are the ones set by
|
||||
// the CPropertySheet::QuerySiblings call
|
||||
|
||||
// return FALSE to allow other siblings to be queried, or
|
||||
// return TRUE to stop query at this page.
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline BOOL CPropertyPage::OnInitDialog()
|
||||
{
|
||||
// Called when the property page is created
|
||||
// Override this function in your derived class if required.
|
||||
|
||||
return TRUE; // Pass Keyboard control to handle in WPARAM
|
||||
}
|
||||
|
||||
inline BOOL CPropertyPage::OnKillActive()
|
||||
{
|
||||
// This is called in response to a PSN_KILLACTIVE notification, which
|
||||
// is sent whenever the OK or Apply button is pressed.
|
||||
// It provides an opportunity to validate the page contents before it's closed.
|
||||
// Return TRUE to prevent the page from losing the activation, or FALSE to allow it.
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline int CPropertyPage::OnOK()
|
||||
{
|
||||
// Called for each page when the OK button is pressed
|
||||
// Override this function in your derived class if required.
|
||||
|
||||
// The possible return values are:
|
||||
// PSNRET_NOERROR. The changes made to this page are valid and have been applied
|
||||
// PSNRET_INVALID. The property sheet will not be destroyed, and focus will be returned to this page.
|
||||
// PSNRET_INVALID_NOCHANGEPAGE. The property sheet will not be destroyed, and focus will be returned;
|
||||
|
||||
return PSNRET_NOERROR;
|
||||
}
|
||||
|
||||
inline LRESULT CPropertyPage::OnNotify(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
|
||||
LPPSHNOTIFY pNotify = (LPPSHNOTIFY)lParam;
|
||||
switch(pNotify->hdr.code)
|
||||
{
|
||||
case PSN_SETACTIVE:
|
||||
return OnSetActive();
|
||||
case PSN_KILLACTIVE:
|
||||
return OnKillActive();
|
||||
case PSN_APPLY:
|
||||
if (pNotify->lParam)
|
||||
return OnOK();
|
||||
else
|
||||
return OnApply();
|
||||
case PSN_RESET:
|
||||
OnCancel();
|
||||
return FALSE;
|
||||
case PSN_QUERYCANCEL:
|
||||
return OnQueryCancel();
|
||||
case PSN_WIZNEXT:
|
||||
return OnWizardNext();
|
||||
case PSN_WIZBACK:
|
||||
return OnWizardBack();
|
||||
case PSN_WIZFINISH:
|
||||
return OnWizardFinish();
|
||||
case PSN_HELP:
|
||||
OnHelp();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline int CPropertyPage::OnSetActive()
|
||||
{
|
||||
// Called when a page becomes active
|
||||
// Override this function in your derived class if required.
|
||||
|
||||
// Returns zero to accept the activation, or -1 to activate the next or the previous page (depending
|
||||
// on whether the user clicked the Next or Back button). To set the activation to a particular page,
|
||||
// return the resource identifier of the page.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int CPropertyPage::OnWizardBack()
|
||||
{
|
||||
// This function is called when the Back button is pressed on a wizard page
|
||||
// Override this function in your derived class if required.
|
||||
|
||||
// Returns 0 to allow the wizard to go to the previous page. Returns -1 to prevent the wizard
|
||||
// from changing pages. To display a particular page, return its dialog resource identifier.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline INT_PTR CPropertyPage::OnWizardFinish()
|
||||
{
|
||||
// This function is called when the Finish button is pressed on a wizard page
|
||||
// Override this function in your derived class if required.
|
||||
|
||||
// Return Value:
|
||||
// Return non-zero to prevent the wizard from finishing.
|
||||
// Version 5.80. and later. Return a window handle to prevent the wizard from finishing. The wizard will set the focus to that window. The window must be owned by the wizard page.
|
||||
// Return 0 to allow the wizard to finish.
|
||||
|
||||
return 0; // Allow wizard to finish
|
||||
}
|
||||
|
||||
inline int CPropertyPage::OnWizardNext()
|
||||
{
|
||||
// This function is called when the Next button is pressed on a wizard page
|
||||
// Override this function in your derived class if required.
|
||||
|
||||
// Return 0 to allow the wizard to go to the next page. Return -1 to prevent the wizard from
|
||||
// changing pages. To display a particular page, return its dialog resource identifier.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline BOOL CPropertyPage::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
// allow the tab control to translate keyboard input
|
||||
if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
|
||||
(pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))
|
||||
{
|
||||
CWnd* pWndParent = GetParent();
|
||||
if (pWndParent->SendMessage(PSM_ISDIALOGMESSAGE, 0L, (LPARAM)pMsg))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// allow the dialog to translate keyboard input
|
||||
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
|
||||
{
|
||||
if (IsDialogMessage(pMsg))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return CWnd::PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
inline LRESULT CPropertyPage::QuerySiblings(WPARAM wParam, LPARAM lParam) const
|
||||
{
|
||||
// Sent to a property sheet, which then forwards the message to each of its pages.
|
||||
// Set wParam and lParam to values you want passed to the property pages.
|
||||
// Returns the nonzero value from a page in the property sheet, or zero if no page returns a nonzero value.
|
||||
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return GetParent()->SendMessage(PSM_QUERYSIBLINGS, wParam, lParam);
|
||||
}
|
||||
|
||||
inline void CPropertyPage::SetModified(BOOL bChanged) const
|
||||
{
|
||||
// The property sheet will enable the Apply button if bChanged is TRUE.
|
||||
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
if (bChanged)
|
||||
GetParent()->SendMessage(PSM_CHANGED, (WPARAM)m_hWnd, 0L);
|
||||
else
|
||||
GetParent()->SendMessage(PSM_UNCHANGED, (WPARAM)m_hWnd, 0L);
|
||||
}
|
||||
|
||||
inline void CPropertyPage::SetTitle(LPCTSTR szTitle)
|
||||
{
|
||||
if (szTitle)
|
||||
{
|
||||
m_Title = szTitle;
|
||||
m_PSP.dwFlags |= PSP_USETITLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Title.erase();
|
||||
m_PSP.dwFlags &= ~PSP_USETITLE;
|
||||
}
|
||||
|
||||
m_PSP.pszTitle = m_Title.c_str();
|
||||
}
|
||||
|
||||
inline void CPropertyPage::SetWizardButtons(DWORD dwFlags) const
|
||||
{
|
||||
// dwFlags: A value that specifies which wizard buttons are enabled. You can combine one or more of the following flags.
|
||||
// PSWIZB_BACK Enable the Back button. If this flag is not set, the Back button is displayed as disabled.
|
||||
// PSWIZB_DISABLEDFINISH Display a disabled Finish button.
|
||||
// PSWIZB_FINISH Display an enabled Finish button.
|
||||
// PSWIZB_NEXT Enable the Next button. If this flag is not set, the Next button is displayed as disabled.
|
||||
|
||||
assert (::IsWindow(m_hWnd));
|
||||
PropSheet_SetWizButtons(::GetParent(m_hWnd), dwFlags);
|
||||
}
|
||||
|
||||
inline UINT CALLBACK CPropertyPage::StaticPropSheetPageProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
|
||||
{
|
||||
assert( GetApp() );
|
||||
UNREFERENCED_PARAMETER(hwnd);
|
||||
|
||||
// Note: the hwnd is always NULL
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case PSPCB_CREATE:
|
||||
{
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
assert(pTLSData);
|
||||
|
||||
// Store the CPropertyPage pointer in Thread Local Storage
|
||||
pTLSData->pCWnd = (CWnd*)ppsp->lParam;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
inline INT_PTR CALLBACK CPropertyPage::StaticDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
assert( GetApp() );
|
||||
|
||||
// Find matching CWnd pointer for this HWND
|
||||
CPropertyPage* pPage = (CPropertyPage*)GetApp()->GetCWndFromMap(hwndDlg);
|
||||
if (0 == pPage)
|
||||
{
|
||||
// matching CWnd pointer not found, so add it to HWNDMap now
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
pPage = (CPropertyPage*)pTLSData->pCWnd;
|
||||
|
||||
// Set the hWnd members and call DialogProc for this message
|
||||
pPage->m_hWnd = hwndDlg;
|
||||
pPage->AddToMap();
|
||||
}
|
||||
|
||||
return pPage->DialogProc(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Definitions for the CPropertySheet class
|
||||
//
|
||||
inline CPropertySheet::CPropertySheet(UINT nIDCaption, CWnd* pParent /* = NULL*/)
|
||||
{
|
||||
ZeroMemory(&m_PSH, sizeof (PROPSHEETHEADER));
|
||||
SetTitle(LoadString(nIDCaption));
|
||||
m_bInitialUpdate = FALSE;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
m_PSH.dwSize = sizeof(PROPSHEETHEADER);
|
||||
#else
|
||||
if (GetComCtlVersion() >= 471)
|
||||
m_PSH.dwSize = sizeof(PROPSHEETHEADER);
|
||||
else
|
||||
m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;
|
||||
#endif
|
||||
|
||||
m_PSH.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
|
||||
m_PSH.hwndParent = pParent? pParent->GetHwnd() : 0;
|
||||
m_PSH.hInstance = GetApp()->GetInstanceHandle();
|
||||
m_PSH.pfnCallback = (PFNPROPSHEETCALLBACK)CPropertySheet::Callback;
|
||||
}
|
||||
|
||||
inline CPropertySheet::CPropertySheet(LPCTSTR pszCaption /*= NULL*/, CWnd* pParent /* = NULL*/)
|
||||
{
|
||||
ZeroMemory(&m_PSH, sizeof (PROPSHEETHEADER));
|
||||
SetTitle(pszCaption);
|
||||
m_bInitialUpdate = FALSE;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;
|
||||
#else
|
||||
if (GetComCtlVersion() >= 471)
|
||||
m_PSH.dwSize = sizeof(PROPSHEETHEADER);
|
||||
else
|
||||
m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;
|
||||
#endif
|
||||
|
||||
m_PSH.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
|
||||
m_PSH.hwndParent = pParent? pParent->GetHwnd() : 0;;
|
||||
m_PSH.hInstance = GetApp()->GetInstanceHandle();
|
||||
m_PSH.pfnCallback = (PFNPROPSHEETCALLBACK)CPropertySheet::Callback;
|
||||
}
|
||||
|
||||
inline CPropertyPage* CPropertySheet::AddPage(CPropertyPage* pPage)
|
||||
// Adds a Property Page to the Property Sheet
|
||||
{
|
||||
assert(NULL != pPage);
|
||||
|
||||
m_vPages.push_back(PropertyPagePtr(pPage));
|
||||
|
||||
if (m_hWnd)
|
||||
{
|
||||
// property sheet already exists, so add page to it
|
||||
PROPSHEETPAGE psp = pPage->GetPSP();
|
||||
HPROPSHEETPAGE hpsp = ::CreatePropertySheetPage(&psp);
|
||||
PropSheet_AddPage(m_hWnd, hpsp);
|
||||
}
|
||||
|
||||
m_PSH.nPages = (int)m_vPages.size();
|
||||
|
||||
return pPage;
|
||||
}
|
||||
|
||||
inline void CPropertySheet::BuildPageArray()
|
||||
// Builds the PROPSHEETPAGE array
|
||||
{
|
||||
m_vPSP.clear();
|
||||
std::vector<PropertyPagePtr>::iterator iter;
|
||||
for (iter = m_vPages.begin(); iter < m_vPages.end(); ++iter)
|
||||
m_vPSP.push_back((*iter)->GetPSP());
|
||||
|
||||
PROPSHEETPAGE* pPSPArray = &m_vPSP.front(); // Array of PROPSHEETPAGE
|
||||
m_PSH.ppsp = pPSPArray;
|
||||
}
|
||||
|
||||
inline void CALLBACK CPropertySheet::Callback(HWND hwnd, UINT uMsg, LPARAM lParam)
|
||||
{
|
||||
assert( GetApp() );
|
||||
|
||||
switch(uMsg)
|
||||
{
|
||||
//called before the dialog is created, hwnd = NULL, lParam points to dialog resource
|
||||
case PSCB_PRECREATE:
|
||||
{
|
||||
LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam;
|
||||
|
||||
if(!(lpTemplate->style & WS_SYSMENU))
|
||||
{
|
||||
lpTemplate->style |= WS_SYSMENU;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//called after the dialog is created
|
||||
case PSCB_INITIALIZED:
|
||||
{
|
||||
// Retrieve pointer to CWnd object from Thread Local Storage
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
assert(pTLSData);
|
||||
|
||||
CPropertySheet* w = (CPropertySheet*)pTLSData->pCWnd;
|
||||
assert(w);
|
||||
|
||||
w->Attach(hwnd);
|
||||
w->OnCreate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline HWND CPropertySheet::Create(CWnd* pParent /*= 0*/)
|
||||
// Creates a modeless Property Sheet
|
||||
{
|
||||
assert( GetApp() );
|
||||
|
||||
if (pParent)
|
||||
{
|
||||
m_PSH.hwndParent = pParent->GetHwnd();
|
||||
}
|
||||
|
||||
BuildPageArray();
|
||||
PROPSHEETPAGE* pPSPArray = &m_vPSP.front();
|
||||
m_PSH.ppsp = pPSPArray;
|
||||
|
||||
// Create a modeless Property Sheet
|
||||
m_PSH.dwFlags &= ~PSH_WIZARD;
|
||||
m_PSH.dwFlags |= PSH_MODELESS;
|
||||
HWND hWnd = (HWND)CreatePropertySheet(&m_PSH);
|
||||
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
inline INT_PTR CPropertySheet::CreatePropertySheet(LPCPROPSHEETHEADER ppsph)
|
||||
{
|
||||
assert( GetApp() );
|
||||
|
||||
INT_PTR ipResult = 0;
|
||||
|
||||
// Only one window per CWnd instance allowed
|
||||
assert(!::IsWindow(m_hWnd));
|
||||
|
||||
// Ensure this thread has the TLS index set
|
||||
TLSData* pTLSData = GetApp()->SetTlsIndex();
|
||||
|
||||
// Store the 'this' pointer in Thread Local Storage
|
||||
pTLSData->pCWnd = this;
|
||||
|
||||
// Create the property sheet
|
||||
ipResult = PropertySheet(ppsph);
|
||||
|
||||
return ipResult;
|
||||
}
|
||||
|
||||
inline void CPropertySheet::DestroyButton(int IDButton)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
HWND hwndButton = ::GetDlgItem(m_hWnd, IDButton);
|
||||
if (hwndButton != NULL)
|
||||
{
|
||||
// Hide and disable the button
|
||||
::ShowWindow(hwndButton, SW_HIDE);
|
||||
::EnableWindow(hwndButton, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CPropertySheet::Destroy()
|
||||
{
|
||||
CWnd::Destroy();
|
||||
m_vPages.clear();
|
||||
}
|
||||
|
||||
inline int CPropertySheet::DoModal()
|
||||
{
|
||||
assert( GetApp() );
|
||||
|
||||
BuildPageArray();
|
||||
PROPSHEETPAGE* pPSPArray = &m_vPSP.front();
|
||||
m_PSH.ppsp = pPSPArray;
|
||||
|
||||
// Create the Property Sheet
|
||||
int nResult = (int)CreatePropertySheet(&m_PSH);
|
||||
|
||||
m_vPages.clear();
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline CPropertyPage* CPropertySheet::GetActivePage() const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
CPropertyPage* pPage = NULL;
|
||||
if (m_hWnd != NULL)
|
||||
{
|
||||
HWND hPage = (HWND)SendMessage(PSM_GETCURRENTPAGEHWND, 0L, 0L);
|
||||
pPage = (CPropertyPage*)FromHandle(hPage);
|
||||
}
|
||||
|
||||
return pPage;
|
||||
}
|
||||
|
||||
inline int CPropertySheet::GetPageCount() const
|
||||
// Returns the number of Property Pages in this Property Sheet
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)m_vPages.size();
|
||||
}
|
||||
|
||||
inline int CPropertySheet::GetPageIndex(CPropertyPage* pPage) const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
for (int i = 0; i < GetPageCount(); i++)
|
||||
{
|
||||
if (m_vPages[i].get() == pPage)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline HWND CPropertySheet::GetTabControl() const
|
||||
// Returns the handle to the Property Sheet's tab control
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (HWND)SendMessage(PSM_GETTABCONTROL, 0L, 0L);
|
||||
}
|
||||
|
||||
inline BOOL CPropertySheet::IsModeless() const
|
||||
{
|
||||
return (m_PSH.dwFlags & PSH_MODELESS);
|
||||
}
|
||||
|
||||
inline BOOL CPropertySheet::IsWizard() const
|
||||
{
|
||||
return (m_PSH.dwFlags & PSH_WIZARD);
|
||||
}
|
||||
|
||||
inline void CPropertySheet::RemovePage(CPropertyPage* pPage)
|
||||
// Removes a Property Page from the Property Sheet
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
int nPage = GetPageIndex(pPage);
|
||||
if (m_hWnd != NULL)
|
||||
SendMessage(m_hWnd, PSM_REMOVEPAGE, nPage, 0L);
|
||||
|
||||
m_vPages.erase(m_vPages.begin() + nPage, m_vPages.begin() + nPage+1);
|
||||
m_PSH.nPages = (int)m_vPages.size();
|
||||
}
|
||||
|
||||
inline BOOL CPropertySheet::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
// allow sheet to translate Ctrl+Tab, Shift+Ctrl+Tab, Ctrl+PageUp, and Ctrl+PageDown
|
||||
if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
|
||||
(pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))
|
||||
{
|
||||
if (SendMessage(PSM_ISDIALOGMESSAGE, 0L, (LPARAM)pMsg))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// allow the dialog to translate keyboard input
|
||||
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
|
||||
{
|
||||
return GetActivePage()->PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
return CWnd::PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
inline BOOL CPropertySheet::SetActivePage(int nPage)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(m_hWnd, PSM_SETCURSEL, nPage, 0L);
|
||||
}
|
||||
|
||||
inline BOOL CPropertySheet::SetActivePage(CPropertyPage* pPage)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
int nPage = GetPageIndex(pPage);
|
||||
if ((nPage >= 0))
|
||||
return SetActivePage(nPage);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline void CPropertySheet::SetIcon(UINT idIcon)
|
||||
{
|
||||
m_PSH.pszIcon = MAKEINTRESOURCE(idIcon);
|
||||
m_PSH.dwFlags |= PSH_USEICONID;
|
||||
}
|
||||
|
||||
inline void CPropertySheet::SetTitle(LPCTSTR szTitle)
|
||||
{
|
||||
if (szTitle)
|
||||
m_Title = szTitle;
|
||||
else
|
||||
m_Title.erase();
|
||||
|
||||
m_PSH.pszCaption = m_Title.c_str();
|
||||
}
|
||||
|
||||
inline void CPropertySheet::SetWizardMode(BOOL bWizard)
|
||||
{
|
||||
if (bWizard)
|
||||
m_PSH.dwFlags |= PSH_WIZARD;
|
||||
else
|
||||
m_PSH.dwFlags &= ~PSH_WIZARD;
|
||||
}
|
||||
|
||||
inline LRESULT CPropertySheet::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
LPWINDOWPOS lpWinPos = (LPWINDOWPOS)lParam;
|
||||
if (lpWinPos->flags & SWP_SHOWWINDOW)
|
||||
{
|
||||
if (!m_bInitialUpdate)
|
||||
// The first window positioning with the window visible
|
||||
OnInitialUpdate();
|
||||
m_bInitialUpdate = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
m_bInitialUpdate = FALSE;
|
||||
break;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
if ((SC_CLOSE == wParam) && (m_PSH.dwFlags & PSH_MODELESS))
|
||||
{
|
||||
Destroy();
|
||||
return 0L;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// pass unhandled messages on for default processing
|
||||
return CWnd::WndProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // _WIN32XX_PROPERTYSHEET_H_
|
709
mmc_updater/depends/win32cpp/rebar.h
Normal file
709
mmc_updater/depends/win32cpp/rebar.h
Normal file
@ -0,0 +1,709 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef _WIN32XX_REBAR_H_
|
||||
#define _WIN32XX_REBAR_H_
|
||||
|
||||
#include "wincore.h"
|
||||
#include "gdi.h"
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
struct ReBarTheme
|
||||
{
|
||||
BOOL UseThemes; // TRUE if themes are used
|
||||
COLORREF clrBkgnd1; // Colour 1 for rebar background
|
||||
COLORREF clrBkgnd2; // Colour 2 for rebar background
|
||||
COLORREF clrBand1; // Colour 1 for rebar band background. Use NULL if not required
|
||||
COLORREF clrBand2; // Colour 2 for rebar band background. Use NULL if not required
|
||||
BOOL FlatStyle; // Bands are rendered with flat rather than raised style
|
||||
BOOL BandsLeft; // Position bands left on rearrange
|
||||
BOOL LockMenuBand; // Lock MenuBar's band in dedicated top row, without gripper
|
||||
BOOL RoundBorders; // Use rounded band borders
|
||||
BOOL ShortBands; // Allows bands to be shorter than maximum available width
|
||||
BOOL UseLines; // Displays horizontal lines between bands
|
||||
};
|
||||
|
||||
////////////////////////////////////
|
||||
// Declaration of the CReBar class
|
||||
//
|
||||
class CReBar : public CWnd
|
||||
{
|
||||
public:
|
||||
CReBar();
|
||||
virtual ~CReBar();
|
||||
|
||||
// Operations
|
||||
BOOL DeleteBand(const int nBand) const;
|
||||
int HitTest(RBHITTESTINFO& rbht);
|
||||
HWND HitTest(POINT pt);
|
||||
int IDToIndex(UINT uBandID) const;
|
||||
BOOL InsertBand(const int nBand, REBARBANDINFO& rbbi) const;
|
||||
BOOL IsBandVisible(int nBand) const;
|
||||
void MaximizeBand(UINT uBand, BOOL fIdeal = FALSE);
|
||||
void MinimizeBand(UINT uBand);
|
||||
BOOL MoveBand(UINT uFrom, UINT uTo);
|
||||
void MoveBandsLeft();
|
||||
BOOL ResizeBand(const int nBand, const CSize& sz) const;
|
||||
BOOL ShowGripper(int nBand, BOOL fShow) const;
|
||||
BOOL ShowBand(int nBand, BOOL fShow) const;
|
||||
BOOL SizeToRect(CRect& rect) const;
|
||||
|
||||
// Attributes
|
||||
int GetBand(const HWND hWnd) const;
|
||||
CRect GetBandBorders(int nBand) const;
|
||||
int GetBandCount() const;
|
||||
BOOL GetBandInfo(const int nBand, REBARBANDINFO& rbbi) const;
|
||||
CRect GetBandRect(int i) const;
|
||||
UINT GetBarHeight() const;
|
||||
BOOL GetBarInfo(REBARINFO& rbi) const;
|
||||
HWND GetMenuBar() {return m_hMenuBar;}
|
||||
ReBarTheme& GetReBarTheme() {return m_Theme;}
|
||||
UINT GetRowCount() const;
|
||||
int GetRowHeight(int nRow) const;
|
||||
UINT GetSizeofRBBI() const;
|
||||
HWND GetToolTips() const;
|
||||
BOOL SetBandBitmap(const int nBand, const CBitmap* pBackground) const;
|
||||
BOOL SetBandColor(const int nBand, const COLORREF clrFore, const COLORREF clrBack) const;
|
||||
BOOL SetBandInfo(const int nBand, REBARBANDINFO& rbbi) const;
|
||||
BOOL SetBarInfo(REBARINFO& rbi) const;
|
||||
void SetMenuBar(HWND hMenuBar) {m_hMenuBar = hMenuBar;}
|
||||
void SetReBarTheme(ReBarTheme& Theme);
|
||||
|
||||
protected:
|
||||
//Overridables
|
||||
virtual BOOL OnEraseBkgnd(CDC* pDC);
|
||||
virtual void PreCreate(CREATESTRUCT& cs);
|
||||
virtual void PreRegisterClass(WNDCLASS &wc);
|
||||
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
CReBar(const CReBar&); // Disable copy construction
|
||||
CReBar& operator = (const CReBar&); // Disable assignment operator
|
||||
|
||||
ReBarTheme m_Theme;
|
||||
BOOL m_bIsDragging;
|
||||
HWND m_hMenuBar;
|
||||
LPARAM m_Orig_lParam;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
///////////////////////////////////
|
||||
// Definitions for the CReBar class
|
||||
//
|
||||
inline CReBar::CReBar() : m_bIsDragging(FALSE), m_hMenuBar(0), m_Orig_lParam(0L)
|
||||
{
|
||||
ZeroMemory(&m_Theme, sizeof(ReBarTheme));
|
||||
}
|
||||
|
||||
inline CReBar::~CReBar()
|
||||
{
|
||||
}
|
||||
|
||||
inline BOOL CReBar::DeleteBand(int nBand) const
|
||||
// Deletes a band from a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(RB_DELETEBAND, nBand, 0L);
|
||||
}
|
||||
|
||||
inline int CReBar::GetBand(HWND hWnd) const
|
||||
// Returns the zero based band number for this window handle
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
int nResult = -1;
|
||||
if (NULL == hWnd) return nResult;
|
||||
|
||||
for (int nBand = 0; nBand < GetBandCount(); ++nBand)
|
||||
{
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_CHILD;
|
||||
GetBandInfo(nBand, rbbi);
|
||||
if (rbbi.hwndChild == hWnd)
|
||||
nResult = nBand;
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline CRect CReBar::GetBandBorders(int nBand) const
|
||||
// Retrieves the borders of a band.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
CRect rc;
|
||||
SendMessage(RB_GETBANDBORDERS, nBand, (LPARAM)&rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
inline int CReBar::GetBandCount() const
|
||||
// Retrieves the count of bands currently in the rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)SendMessage(RB_GETBANDCOUNT, 0L, 0L);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::GetBandInfo(int nBand, REBARBANDINFO& rbbi) const
|
||||
// Retrieves information about a specified band in a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
assert(nBand >= 0);
|
||||
|
||||
// REBARBANDINFO describes individual BAND characteristics
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
return (BOOL)SendMessage(RB_GETBANDINFO, nBand, (LPARAM)&rbbi);
|
||||
}
|
||||
|
||||
inline CRect CReBar::GetBandRect(int i) const
|
||||
// Retrieves the bounding rectangle for a given band in a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
CRect rc;
|
||||
SendMessage(RB_GETRECT, i, (LPARAM)&rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
inline UINT CReBar::GetBarHeight() const
|
||||
// Retrieves the height of the rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (UINT)SendMessage(RB_GETBARHEIGHT, 0L, 0L);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::GetBarInfo(REBARINFO& rbi) const
|
||||
// Retrieves information about the rebar control and the image list it uses.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
// REBARINFO describes overall rebar control characteristics
|
||||
rbi.cbSize = GetSizeofRBBI();
|
||||
return (BOOL)SendMessage(RB_GETBARINFO, 0L, (LPARAM)&rbi);
|
||||
}
|
||||
|
||||
inline UINT CReBar::GetRowCount() const
|
||||
// Retrieves the number of rows of bands in a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (UINT)SendMessage(RB_GETROWCOUNT, 0L, 0L);
|
||||
}
|
||||
|
||||
inline int CReBar::GetRowHeight(int nRow) const
|
||||
// Retrieves the height of a specified row in a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)SendMessage(RB_GETROWHEIGHT, nRow, 0L);
|
||||
}
|
||||
|
||||
inline UINT CReBar::GetSizeofRBBI() const
|
||||
// The size of the REBARBANDINFO struct changes according to _WIN32_WINNT
|
||||
// sizeof(REBARBANDINFO) can report an incorrect size for older Window versions,
|
||||
// or newer Window version without XP themes enabled.
|
||||
// Use this function to get a safe size for REBARBANDINFO.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
UINT uSizeof = sizeof(REBARBANDINFO);
|
||||
|
||||
#if defined REBARBANDINFO_V6_SIZE // only defined for VS2008 or higher
|
||||
#if !defined (_WIN32_WINNT) || _WIN32_WINNT >= 0x0600
|
||||
if ((GetWinVersion() < 2600) || (GetComCtlVersion() < 610)) // Vista and Vista themes?
|
||||
uSizeof = REBARBANDINFO_V6_SIZE;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return uSizeof;
|
||||
}
|
||||
|
||||
inline HWND CReBar::GetToolTips() const
|
||||
// Retrieves the handle to any ToolTip control associated with the rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (HWND)SendMessage(RB_GETTOOLTIPS, 0L, 0L);
|
||||
}
|
||||
|
||||
inline int CReBar::HitTest(RBHITTESTINFO& rbht)
|
||||
// Determines which portion of a rebar band is at a given point on the screen,
|
||||
// if a rebar band exists at that point.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)SendMessage(RB_HITTEST, 0L, (LPARAM)&rbht);
|
||||
}
|
||||
|
||||
inline HWND CReBar::HitTest(POINT pt)
|
||||
// Return the child HWND at the given point
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
// Convert the point to client co-ordinates
|
||||
ScreenToClient(pt);
|
||||
|
||||
// Get the rebar band with the point
|
||||
RBHITTESTINFO rbhti = {0};
|
||||
rbhti.pt = pt;
|
||||
int iBand = HitTest(rbhti);
|
||||
|
||||
if (iBand >= 0)
|
||||
{
|
||||
// Get the rebar band's hWnd
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_CHILD;
|
||||
GetBandInfo(iBand, rbbi);
|
||||
|
||||
return rbbi.hwndChild;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline int CReBar::IDToIndex(UINT uBandID) const
|
||||
// Converts a band identifier to a band index in a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)SendMessage(RB_IDTOINDEX, (WPARAM)uBandID, 0L);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::InsertBand(int nBand, REBARBANDINFO& rbbi) const
|
||||
// Inserts a new band in a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
return (BOOL)SendMessage(RB_INSERTBAND, nBand, (LPARAM)&rbbi);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::IsBandVisible(int nBand) const
|
||||
// Returns true if the band is visible
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_STYLE;
|
||||
GetBandInfo(nBand, rbbi);
|
||||
|
||||
return !(rbbi.fStyle & RBBS_HIDDEN);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::OnEraseBkgnd(CDC* pDC)
|
||||
{
|
||||
BOOL Erase = TRUE;
|
||||
if (!m_Theme.UseThemes)
|
||||
Erase = FALSE;
|
||||
|
||||
if (!m_Theme.clrBkgnd1 && !m_Theme.clrBkgnd2 && !m_Theme.clrBand1 && !m_Theme.clrBand2)
|
||||
Erase = FALSE;
|
||||
|
||||
if (Erase)
|
||||
{
|
||||
CRect rcReBar = GetClientRect();
|
||||
int BarWidth = rcReBar.Width();
|
||||
int BarHeight = rcReBar.Height();
|
||||
|
||||
// Create and set up our memory DC
|
||||
CMemDC MemDC(pDC);
|
||||
MemDC.CreateCompatibleBitmap(pDC, BarWidth, BarHeight);
|
||||
|
||||
// Draw to ReBar background to the memory DC
|
||||
rcReBar.right = 600;
|
||||
MemDC.GradientFill(m_Theme.clrBkgnd1, m_Theme.clrBkgnd2, rcReBar, TRUE);
|
||||
if (BarWidth >= 600)
|
||||
{
|
||||
rcReBar.left = 600;
|
||||
rcReBar.right = BarWidth;
|
||||
MemDC.SolidFill(m_Theme.clrBkgnd2, rcReBar);
|
||||
}
|
||||
|
||||
if (m_Theme.clrBand1 || m_Theme.clrBand2)
|
||||
{
|
||||
// Draw the individual band backgrounds
|
||||
for (int nBand = 0 ; nBand < GetBandCount(); ++nBand)
|
||||
{
|
||||
if (IsBandVisible(nBand))
|
||||
{
|
||||
if (nBand != GetBand(m_hMenuBar))
|
||||
{
|
||||
// Determine the size of this band
|
||||
CRect rcBand = GetBandRect(nBand);
|
||||
|
||||
// Determine the size of the child window
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_CHILD ;
|
||||
GetBandInfo(nBand, rbbi);
|
||||
CRect rcChild;
|
||||
::GetWindowRect(rbbi.hwndChild, &rcChild);
|
||||
int ChildWidth = rcChild.right - rcChild.left;
|
||||
|
||||
// Determine our drawing rectangle
|
||||
CRect rcDraw = rcBand;
|
||||
rcDraw.bottom = rcDraw.top + (rcBand.bottom - rcBand.top)/2;
|
||||
int xPad = IsXPThemed()? 2: 0;
|
||||
rcDraw.left -= xPad;
|
||||
|
||||
// Fill the Source CDC with the band's background
|
||||
CMemDC SourceDC(pDC);
|
||||
SourceDC.CreateCompatibleBitmap(pDC, BarWidth, BarHeight);
|
||||
CRect rcBorder = GetBandBorders(nBand);
|
||||
rcDraw.right = rcBand.left + ChildWidth + rcBorder.left;
|
||||
SourceDC.SolidFill(m_Theme.clrBand1, rcDraw);
|
||||
rcDraw.top = rcDraw.bottom;
|
||||
rcDraw.bottom = rcBand.bottom;
|
||||
SourceDC.GradientFill(m_Theme.clrBand1, m_Theme.clrBand2, rcDraw, FALSE);
|
||||
|
||||
// Set Curve amount for rounded edges
|
||||
int Curve = m_Theme.RoundBorders? 12 : 0;
|
||||
|
||||
// Create our mask for rounded edges using RoundRect
|
||||
CMemDC MaskDC(pDC);
|
||||
MaskDC.CreateCompatibleBitmap(pDC, BarWidth, BarHeight);
|
||||
|
||||
rcDraw.top = rcBand.top;
|
||||
if (!m_Theme.FlatStyle)
|
||||
::InflateRect(&rcDraw, 1, 1);
|
||||
|
||||
int left = rcDraw.left;
|
||||
int right = rcDraw.right;
|
||||
int top = rcDraw.top;
|
||||
int bottom = rcDraw.bottom;
|
||||
int cx = rcDraw.right - rcBand.left + xPad;
|
||||
int cy = rcDraw.bottom - rcBand.top;
|
||||
|
||||
if (m_Theme.FlatStyle)
|
||||
{
|
||||
MaskDC.SolidFill(RGB(0,0,0), rcDraw);
|
||||
MaskDC.BitBlt(left, top, cx, cy, &MaskDC, left, top, PATINVERT);
|
||||
MaskDC.RoundRect(left, top, right, bottom, Curve, Curve);
|
||||
}
|
||||
else
|
||||
{
|
||||
MaskDC.SolidFill(RGB(0,0,0), rcDraw);
|
||||
MaskDC.RoundRect(left, top, right, bottom, Curve, Curve);
|
||||
MaskDC.BitBlt(left, top, cx, cy, &MaskDC, left, top, PATINVERT);
|
||||
}
|
||||
|
||||
// Copy Source DC to Memory DC using the RoundRect mask
|
||||
MemDC.BitBlt(left, top, cx, cy, &SourceDC, left, top, SRCINVERT);
|
||||
MemDC.BitBlt(left, top, cx, cy, &MaskDC, left, top, SRCAND);
|
||||
MemDC.BitBlt(left, top, cx, cy, &SourceDC, left, top, SRCINVERT);
|
||||
|
||||
// Extra drawing to prevent jagged edge while moving bands
|
||||
if (m_bIsDragging)
|
||||
{
|
||||
CClientDC ReBarDC(this);
|
||||
ReBarDC.BitBlt(rcDraw.right - ChildWidth, rcDraw.top, ChildWidth, cy, &MemDC, rcDraw.right - ChildWidth, rcDraw.top, SRCCOPY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Theme.UseLines)
|
||||
{
|
||||
// Draw lines between bands
|
||||
for (int j = 0; j < GetBandCount()-1; ++j)
|
||||
{
|
||||
rcReBar = GetBandRect(j);
|
||||
rcReBar.left = MAX(0, rcReBar.left - 4);
|
||||
rcReBar.bottom +=2;
|
||||
MemDC.DrawEdge(rcReBar, EDGE_ETCHED, BF_BOTTOM | BF_ADJUST);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the Memory DC to the window's DC
|
||||
pDC->BitBlt(0, 0, BarWidth, BarHeight, &MemDC, 0, 0, SRCCOPY);
|
||||
}
|
||||
|
||||
return Erase;
|
||||
}
|
||||
|
||||
inline void CReBar::PreCreate(CREATESTRUCT &cs)
|
||||
// Sets the CREATESTRUCT paramaters prior to window creation
|
||||
{
|
||||
cs.style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
|
||||
CCS_NODIVIDER | RBS_VARHEIGHT | RBS_BANDBORDERS ;
|
||||
|
||||
cs.cy = 100;
|
||||
}
|
||||
|
||||
inline void CReBar::PreRegisterClass(WNDCLASS &wc)
|
||||
{
|
||||
// Set the Window Class
|
||||
wc.lpszClassName = REBARCLASSNAME;
|
||||
}
|
||||
|
||||
inline void CReBar::MaximizeBand(UINT uBand, BOOL fIdeal /*= FALSE*/)
|
||||
// Resizes a band in a rebar control to either its ideal or largest size.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
SendMessage(RB_MAXIMIZEBAND, (WPARAM)uBand, (LPARAM)fIdeal);
|
||||
}
|
||||
|
||||
inline void CReBar::MinimizeBand(UINT uBand)
|
||||
// Resizes a band in a rebar control to its smallest size.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
SendMessage(RB_MINIMIZEBAND, (WPARAM)uBand, 0L);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::MoveBand(UINT uFrom, UINT uTo)
|
||||
// Moves a band from one index to another.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(RB_MOVEBAND, (WPARAM)uFrom, (LPARAM)uTo);
|
||||
}
|
||||
|
||||
inline void CReBar::MoveBandsLeft()
|
||||
// Repositions the bands so they are left justified
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
int OldrcTop = -1;
|
||||
for (int nBand = GetBandCount() -1; nBand >= 0; --nBand)
|
||||
{
|
||||
CRect rc = GetBandRect(nBand);
|
||||
if (rc.top != OldrcTop)
|
||||
{
|
||||
// Maximize the last band on each row
|
||||
if (IsBandVisible(nBand))
|
||||
{
|
||||
::SendMessage(GetHwnd(), RB_MAXIMIZEBAND, nBand, 0L);
|
||||
OldrcTop = rc.top;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline BOOL CReBar::ResizeBand(int nBand, const CSize& sz) const
|
||||
// Sets a band's size
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_SIZE;
|
||||
|
||||
GetBandInfo(nBand, rbbi);
|
||||
rbbi.cx = sz.cx + 2;
|
||||
rbbi.cxMinChild = sz.cx + 2;
|
||||
rbbi.cyMinChild = sz.cy;
|
||||
rbbi.cyMaxChild = sz.cy;
|
||||
|
||||
return SetBandInfo(nBand, rbbi );
|
||||
}
|
||||
|
||||
inline BOOL CReBar::SetBandBitmap(int nBand, const CBitmap* pBackground) const
|
||||
// Sets the band's bitmaps
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
assert(pBackground);
|
||||
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_STYLE;
|
||||
GetBandInfo(nBand, rbbi);
|
||||
rbbi.fMask |= RBBIM_BACKGROUND;
|
||||
rbbi.hbmBack = *pBackground;
|
||||
|
||||
return (BOOL)SendMessage(RB_SETBANDINFO, nBand, (LPARAM)&rbbi);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::SetBandColor(int nBand, COLORREF clrFore, COLORREF clrBack) const
|
||||
// Sets the band's color
|
||||
// Note: No effect with XP themes enabled
|
||||
// No effect if a bitmap has been set
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_COLORS;
|
||||
rbbi.clrFore = clrFore;
|
||||
rbbi.clrBack = clrBack;
|
||||
|
||||
return (BOOL)SendMessage(RB_SETBANDINFO, nBand, (LPARAM)&rbbi);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::SetBandInfo(int nBand, REBARBANDINFO& rbbi) const
|
||||
// Sets the characteristics of a rebar control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
assert(nBand >= 0);
|
||||
|
||||
// REBARBANDINFO describes individual BAND characteristics0
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
return (BOOL)SendMessage(RB_SETBANDINFO, nBand, (LPARAM)&rbbi);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::SetBarInfo(REBARINFO& rbi) const
|
||||
// REBARINFO associates an image list with the rebar
|
||||
// A band will also need to set RBBIM_IMAGE
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
rbi.cbSize = GetSizeofRBBI();
|
||||
return (BOOL)SendMessage(RB_SETBARINFO, 0L, (LPARAM)&rbi);
|
||||
}
|
||||
|
||||
inline void CReBar::SetReBarTheme(ReBarTheme& Theme)
|
||||
{
|
||||
m_Theme.UseThemes = Theme.UseThemes;
|
||||
m_Theme.clrBkgnd1 = Theme.clrBkgnd1;
|
||||
m_Theme.clrBkgnd2 = Theme.clrBkgnd2;
|
||||
m_Theme.clrBand1 = Theme.clrBand1;
|
||||
m_Theme.clrBand2 = Theme.clrBand2;
|
||||
m_Theme.BandsLeft = Theme.BandsLeft;
|
||||
m_Theme.LockMenuBand = Theme.LockMenuBand;
|
||||
m_Theme.ShortBands = Theme.ShortBands;
|
||||
m_Theme.UseLines = Theme.UseLines;
|
||||
m_Theme.FlatStyle = Theme.FlatStyle;
|
||||
m_Theme.RoundBorders = Theme.RoundBorders;
|
||||
|
||||
if (IsWindow())
|
||||
{
|
||||
if (m_Theme.LockMenuBand)
|
||||
ShowGripper(GetBand(m_hMenuBar), FALSE);
|
||||
else
|
||||
ShowGripper(GetBand(m_hMenuBar), TRUE);
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
inline BOOL CReBar::ShowBand(int nBand, BOOL fShow) const
|
||||
// Show or hide a band
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(RB_SHOWBAND, (WPARAM)nBand, (LPARAM)fShow);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::ShowGripper(int nBand, BOOL fShow) const
|
||||
// Show or hide the band's gripper
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
REBARBANDINFO rbbi = {0};
|
||||
rbbi.cbSize = GetSizeofRBBI();
|
||||
rbbi.fMask = RBBIM_STYLE;
|
||||
GetBandInfo(nBand, rbbi);
|
||||
if (fShow)
|
||||
{
|
||||
rbbi.fStyle |= RBBS_GRIPPERALWAYS;
|
||||
rbbi.fStyle &= ~RBBS_NOGRIPPER;
|
||||
}
|
||||
else
|
||||
{
|
||||
rbbi.fStyle &= ~RBBS_GRIPPERALWAYS;
|
||||
rbbi.fStyle |= RBBS_NOGRIPPER;
|
||||
}
|
||||
|
||||
return SetBandInfo(nBand, rbbi);
|
||||
}
|
||||
|
||||
inline BOOL CReBar::SizeToRect(CRect& rect) const
|
||||
// Attempts to find the best layout of the bands for the given rectangle.
|
||||
// The rebar bands will be arranged and wrapped as necessary to fit the rectangle.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(RB_SIZETORECT, 0, (LPARAM) (LPRECT)rect);
|
||||
}
|
||||
|
||||
inline LRESULT CReBar::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_MOUSEMOVE:
|
||||
if (m_Theme.UseThemes && m_Theme.LockMenuBand)
|
||||
{
|
||||
// We want to lock the first row in place, but allow other bands to move!
|
||||
// Use move messages to limit the resizing of bands
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
|
||||
if (y <= GetRowHeight(0))
|
||||
return 0L; // throw this message away
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
m_Orig_lParam = lParam; // Store the x,y position
|
||||
m_bIsDragging = TRUE;
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
if (m_Theme.UseThemes && m_Theme.LockMenuBand)
|
||||
{
|
||||
// Use move messages to limit the resizing of bands
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
|
||||
if (y <= GetRowHeight(0))
|
||||
{
|
||||
// Use x,y from WM_LBUTTONDOWN for WM_LBUTTONUP position
|
||||
lParam = m_Orig_lParam;
|
||||
}
|
||||
}
|
||||
m_bIsDragging = FALSE;
|
||||
break;
|
||||
case UWM_GETREBARTHEME:
|
||||
{
|
||||
ReBarTheme& rm = GetReBarTheme();
|
||||
return (LRESULT)&rm;
|
||||
}
|
||||
case UWM_TOOLBAR_RESIZE:
|
||||
{
|
||||
HWND hToolBar = (HWND)wParam;
|
||||
LPSIZE pToolBarSize = (LPSIZE)lParam;
|
||||
ResizeBand(GetBand(hToolBar), *pToolBarSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// pass unhandled messages on for default processing
|
||||
return CWnd::WndProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // #ifndef _WIN32XX_REBAR_H_
|
116
mmc_updater/depends/win32cpp/release notes.txt
Normal file
116
mmc_updater/depends/win32cpp/release notes.txt
Normal file
@ -0,0 +1,116 @@
|
||||
About Win32++
|
||||
-------------
|
||||
Win32++ is simple and easy to understand framework for developing Win32
|
||||
applications using C++. It brings an object oriented approach to programming
|
||||
directly with the Win32 API. Each window created is a C++ class object capable
|
||||
of having its own window procedure for routing messages.
|
||||
|
||||
Win32++ supports the following compilers and development environments:
|
||||
* Borland C++ Compiler 5.5
|
||||
* Borland Developer Studio 2006
|
||||
* Dev-C++
|
||||
* Microsoft Visual C++ Toolkit 2003
|
||||
* Microsoft Visual C++ 2005 Express Edition
|
||||
* Microsoft Visual C++ 2008 Express Edition
|
||||
* Microsoft Visual C++ 2010 Express Edition
|
||||
* Microsoft Visual Studio 6.0
|
||||
* Microsoft Visual Studio.net 2003
|
||||
* Microsoft Visual Studio.net 2005
|
||||
* Microsoft Visual Studio.net 2008
|
||||
* Microsoft Visual Studio.net 2010
|
||||
* MinGW compiler
|
||||
|
||||
Win32++ supports the following operating systems
|
||||
* Windows 95
|
||||
* Windows 98
|
||||
* Windows ME
|
||||
* Windows NT 4
|
||||
* Windows 2000
|
||||
* Windows XP (32bit and 64bit)
|
||||
* Windows 2003 Server (32bit and 64bit)
|
||||
* Windows Vista (32bit and 64bit)
|
||||
* Windows 2008 Server (32bit and 64bit)
|
||||
* Windows 7 (32 bit and 64 bit)
|
||||
* Windows CE from WCE400 (Windows mobile 2003) to WCE600 (Windows mobile 6)
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
Win32++ code has the following features
|
||||
* Object Orientated
|
||||
* Subclassing support
|
||||
* Notification reflection and message reflection
|
||||
* Unicode compliant, with multilingual support
|
||||
* Multi-threaded support.
|
||||
* Tracing
|
||||
* 64 bit support
|
||||
* Windows 7 ribbon support
|
||||
* Themes support
|
||||
* Network support (including IP version 6)
|
||||
* Docking windows
|
||||
* Tabbed MDIs
|
||||
|
||||
Frames produced by Win32++ include the following:
|
||||
* Rebar
|
||||
* Menubar
|
||||
* Toolbar
|
||||
* Status bar
|
||||
* Tool tips
|
||||
|
||||
About the file downloads
|
||||
------------------------
|
||||
The file download from Sourceforge includes the following:
|
||||
* The Win32++ library itself
|
||||
* Help for the library
|
||||
* A set of tutorials
|
||||
* A collection of sample applications
|
||||
|
||||
The sample applications include:
|
||||
* Browser - An Internet browser application with an event sink.
|
||||
* Dialog - An example of a simple dialog application.
|
||||
* DialogDemo - An interative dialog application demonstrating slider controls and progress bars.
|
||||
* DialogResizing - An example of a resizable dialog.
|
||||
* DialogTab - A dialog application with a tab control.
|
||||
* DirectX - A simple DirectX application.
|
||||
* DLL - Shows how to run Win32++ from within a DLL
|
||||
* Dock - An example of a simple docking application.
|
||||
* DockContainer - An example of a docking application which incorporates containers.
|
||||
* DockTabbedMDI - An example of a docking application with containers and a tabbed MDI.
|
||||
* Explorer - A Windows Explorer-like application.
|
||||
* FastGDI - An application which demonstrates direct manipulation of a bitmap's colour.
|
||||
* FormDemo - An example of a modeless dialog within a frame.
|
||||
* Frame - A simple frame application.
|
||||
* GDIPlus - Demonstrates how to use GDI+ with Win32++.
|
||||
* MDIFrame - A simple MDI frame application.
|
||||
* MDIFrameDemo - Demonstrates some additional features of MDI frames.
|
||||
* MDIFrameSplitter - Demonstrates how to implement splitter windows in MDI Child windows.
|
||||
* Networking - Demonstrates the use of networking.
|
||||
* Notepad - A simple text editor with printing.
|
||||
* Performance - Measures Win32++'s message handling speed.
|
||||
* Picture - A simple picture rendering application.
|
||||
* PropertySheets - A demonstration of property sheets.
|
||||
* RibbonFrame - Demonstrates how to use the Windows 7 ribbon with a frame.
|
||||
* RibbonSimple - Demonstrates how to use the Windwos 7 ribbon with a simple window.
|
||||
* Scribble - A simple drawing application.
|
||||
* Simple - Creates a simple window.
|
||||
* Splitter - Demonstrates how to use dockers to create splitter windows.
|
||||
* TabDemo - Demonstrates the use of a CTab control in a frame.
|
||||
* TaskDialog - Demonstrates the use of task dialogs (available on Vista and above).
|
||||
* Themes - Demonstrates how to customise the colours for rebar and toolbar controls.
|
||||
* Threads - Demonstrates multi-threaded Windows.
|
||||
* Tray - Demonstrates how to "minimise" an application to the system tray.
|
||||
* WinCE samples - A small collection of samples for Windows CE
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
Each file download includes the project files for Dev-C++, CodeBlocks and the
|
||||
various compilers from Microsoft. CodeBlocks is an IDE (Integrated Development
|
||||
Environment) that supports GNU GCC, Borland Developer Studio 2006 and Microsoft
|
||||
C++ Toolkit 2003.
|
||||
|
||||
You can start with one of the sample programs, and add your code. Alternatively
|
||||
you can start with the projects and sample code provided in the "new projects"
|
||||
folder.
|
||||
|
||||
For additional information on getting started, refer to the help included
|
||||
in the documentation.
|
527
mmc_updater/depends/win32cpp/ribbon.h
Normal file
527
mmc_updater/depends/win32cpp/ribbon.h
Normal file
@ -0,0 +1,527 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// ribbon.h
|
||||
// Declaration of the following classes:
|
||||
// CRibbon and CRibbonFrame
|
||||
//
|
||||
|
||||
#ifndef _WIN32XX_RIBBON_H_
|
||||
#define _WIN32XX_RIBBON_H_
|
||||
|
||||
|
||||
// Notes: 1) The Windows 7 SDK must be installed and its directories added to the IDE
|
||||
// 2) The ribbon only works on OS Windows 7 and above
|
||||
|
||||
//#include <strsafe.h>
|
||||
#include <UIRibbon.h> // Contained within the Windows 7 SDK
|
||||
#include <UIRibbonPropertyHelpers.h>
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
// Defines the callback entry-point methods for the Ribbon framework.
|
||||
class CRibbon : public IUICommandHandler, public IUIApplication
|
||||
{
|
||||
public:
|
||||
CRibbon() : m_cRef(1), m_pRibbonFramework(NULL) {}
|
||||
~CRibbon();
|
||||
|
||||
// IUnknown methods.
|
||||
STDMETHOD_(ULONG, AddRef());
|
||||
STDMETHOD_(ULONG, Release());
|
||||
STDMETHOD(QueryInterface(REFIID iid, void** ppv));
|
||||
|
||||
// IUIApplication methods
|
||||
STDMETHOD(OnCreateUICommand)(UINT nCmdID, __in UI_COMMANDTYPE typeID,
|
||||
__deref_out IUICommandHandler** ppCommandHandler);
|
||||
|
||||
STDMETHOD(OnDestroyUICommand)(UINT32 commandId, __in UI_COMMANDTYPE typeID,
|
||||
__in_opt IUICommandHandler* commandHandler);
|
||||
|
||||
STDMETHOD(OnViewChanged)(UINT viewId, __in UI_VIEWTYPE typeId, __in IUnknown* pView,
|
||||
UI_VIEWVERB verb, INT uReasonCode);
|
||||
|
||||
// IUICommandHandle methods
|
||||
STDMETHODIMP Execute(UINT nCmdID, UI_EXECUTIONVERB verb, __in_opt const PROPERTYKEY* key, __in_opt const PROPVARIANT* ppropvarValue,
|
||||
__in_opt IUISimplePropertySet* pCommandExecutionProperties);
|
||||
|
||||
STDMETHODIMP UpdateProperty(UINT nCmdID, __in REFPROPERTYKEY key, __in_opt const PROPVARIANT* ppropvarCurrentValue,
|
||||
__out PROPVARIANT* ppropvarNewValue);
|
||||
|
||||
bool virtual CreateRibbon(CWnd* pWnd);
|
||||
void virtual DestroyRibbon();
|
||||
IUIFramework* GetRibbonFramework() { return m_pRibbonFramework; }
|
||||
|
||||
private:
|
||||
IUIFramework* m_pRibbonFramework;
|
||||
LONG m_cRef; // Reference count.
|
||||
|
||||
};
|
||||
|
||||
|
||||
class CRibbonFrame : public CFrame, public CRibbon
|
||||
{
|
||||
public:
|
||||
// A nested class for the MRU item properties
|
||||
class CRecentFiles : public IUISimplePropertySet
|
||||
{
|
||||
public:
|
||||
CRecentFiles(PWSTR wszFullPath);
|
||||
~CRecentFiles() {}
|
||||
|
||||
// IUnknown methods.
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
|
||||
|
||||
// IUISimplePropertySet methods
|
||||
STDMETHODIMP GetValue(__in REFPROPERTYKEY key, __out PROPVARIANT *value);
|
||||
|
||||
private:
|
||||
LONG m_cRef; // Reference count.
|
||||
WCHAR m_wszDisplayName[MAX_PATH];
|
||||
WCHAR m_wszFullPath[MAX_PATH];
|
||||
};
|
||||
|
||||
typedef Shared_Ptr<CRecentFiles> RecentFilesPtr;
|
||||
|
||||
CRibbonFrame() : m_uRibbonHeight(0) {}
|
||||
virtual ~CRibbonFrame() {}
|
||||
virtual CRect GetViewRect() const;
|
||||
virtual void OnCreate();
|
||||
virtual void OnDestroy();
|
||||
virtual STDMETHODIMP OnViewChanged(UINT32 viewId, UI_VIEWTYPE typeId, IUnknown* pView, UI_VIEWVERB verb, INT32 uReasonCode);
|
||||
virtual HRESULT PopulateRibbonRecentItems(__deref_out PROPVARIANT* pvarValue);
|
||||
virtual void UpdateMRUMenu();
|
||||
|
||||
UINT GetRibbonHeight() const { return m_uRibbonHeight; }
|
||||
|
||||
private:
|
||||
std::vector<RecentFilesPtr> m_vRecentFiles;
|
||||
void SetRibbonHeight(UINT uRibbonHeight) { m_uRibbonHeight = uRibbonHeight; }
|
||||
UINT m_uRibbonHeight;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
//////////////////////////////////////////////
|
||||
// Definitions for the CRibbon class
|
||||
//
|
||||
|
||||
inline CRibbon::~CRibbon()
|
||||
{
|
||||
// Reference count must be 1 or we have a leak!
|
||||
assert(m_cRef == 1);
|
||||
}
|
||||
|
||||
// IUnknown method implementations.
|
||||
inline STDMETHODIMP_(ULONG) CRibbon::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
inline STDMETHODIMP_(ULONG) CRibbon::Release()
|
||||
{
|
||||
LONG cRef = InterlockedDecrement(&m_cRef);
|
||||
return cRef;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CRibbon::Execute(UINT nCmdID, UI_EXECUTIONVERB verb, __in_opt const PROPERTYKEY* key, __in_opt const PROPVARIANT* ppropvarValue,
|
||||
__in_opt IUISimplePropertySet* pCommandExecutionProperties)
|
||||
{
|
||||
UNREFERENCED_PARAMETER (nCmdID);
|
||||
UNREFERENCED_PARAMETER (verb);
|
||||
UNREFERENCED_PARAMETER (key);
|
||||
UNREFERENCED_PARAMETER (ppropvarValue);
|
||||
UNREFERENCED_PARAMETER (pCommandExecutionProperties);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CRibbon::QueryInterface(REFIID iid, void** ppv)
|
||||
{
|
||||
if (iid == __uuidof(IUnknown))
|
||||
{
|
||||
*ppv = static_cast<IUnknown*>(static_cast<IUIApplication*>(this));
|
||||
}
|
||||
else if (iid == __uuidof(IUICommandHandler))
|
||||
{
|
||||
*ppv = static_cast<IUICommandHandler*>(this);
|
||||
}
|
||||
else if (iid == __uuidof(IUIApplication))
|
||||
{
|
||||
*ppv = static_cast<IUIApplication*>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Called by the Ribbon framework for each command specified in markup, to bind the Command to an IUICommandHandler.
|
||||
inline STDMETHODIMP CRibbon::OnCreateUICommand(UINT nCmdID, __in UI_COMMANDTYPE typeID,
|
||||
__deref_out IUICommandHandler** ppCommandHandler)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(typeID);
|
||||
UNREFERENCED_PARAMETER(nCmdID);
|
||||
|
||||
// By default we use the single command handler provided as part of CRibbon.
|
||||
// Override this function to account for multiple command handlers.
|
||||
|
||||
return QueryInterface(IID_PPV_ARGS(ppCommandHandler));
|
||||
}
|
||||
|
||||
// Called when the state of the Ribbon changes, for example, created, destroyed, or resized.
|
||||
inline STDMETHODIMP CRibbon::OnViewChanged(UINT viewId, __in UI_VIEWTYPE typeId, __in IUnknown* pView,
|
||||
UI_VIEWVERB verb, INT uReasonCode)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(viewId);
|
||||
UNREFERENCED_PARAMETER(typeId);
|
||||
UNREFERENCED_PARAMETER(pView);
|
||||
UNREFERENCED_PARAMETER(verb);
|
||||
UNREFERENCED_PARAMETER(uReasonCode);
|
||||
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// Called by the Ribbon framework for each command at the time of ribbon destruction.
|
||||
inline STDMETHODIMP CRibbon::OnDestroyUICommand(UINT32 nCmdID, __in UI_COMMANDTYPE typeID,
|
||||
__in_opt IUICommandHandler* commandHandler)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(commandHandler);
|
||||
UNREFERENCED_PARAMETER(typeID);
|
||||
UNREFERENCED_PARAMETER(nCmdID);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// Called by the Ribbon framework when a command property (PKEY) needs to be updated.
|
||||
inline STDMETHODIMP CRibbon::UpdateProperty(UINT nCmdID, __in REFPROPERTYKEY key, __in_opt const PROPVARIANT* ppropvarCurrentValue,
|
||||
__out PROPVARIANT* ppropvarNewValue)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(nCmdID);
|
||||
UNREFERENCED_PARAMETER(key);
|
||||
UNREFERENCED_PARAMETER(ppropvarCurrentValue);
|
||||
UNREFERENCED_PARAMETER(ppropvarNewValue);
|
||||
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline bool CRibbon::CreateRibbon(CWnd* pWnd)
|
||||
{
|
||||
::CoInitialize(NULL);
|
||||
|
||||
// Instantiate the Ribbon framework object.
|
||||
::CoCreateInstance(CLSID_UIRibbonFramework, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pRibbonFramework));
|
||||
|
||||
// Connect the host application to the Ribbon framework.
|
||||
HRESULT hr = m_pRibbonFramework->Initialize(pWnd->GetHwnd(), this);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the binary markup. APPLICATION_RIBBON is the default name generated by uicc.
|
||||
hr = m_pRibbonFramework->LoadUI(GetModuleHandle(NULL), L"APPLICATION_RIBBON");
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void CRibbon::DestroyRibbon()
|
||||
{
|
||||
if (m_pRibbonFramework)
|
||||
{
|
||||
m_pRibbonFramework->Destroy();
|
||||
m_pRibbonFramework->Release();
|
||||
m_pRibbonFramework = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Definitions for the CRibbonFrame class
|
||||
//
|
||||
|
||||
inline CRect CRibbonFrame::GetViewRect() const
|
||||
{
|
||||
// Get the frame's client area
|
||||
CRect rcFrame = GetClientRect();
|
||||
|
||||
// Get the statusbar's window area
|
||||
CRect rcStatus;
|
||||
if (GetStatusBar().IsWindowVisible() || !IsWindowVisible())
|
||||
rcStatus = GetStatusBar().GetWindowRect();
|
||||
|
||||
// Get the top rebar or toolbar's window area
|
||||
CRect rcTop;
|
||||
if (IsReBarSupported() && m_bUseReBar)
|
||||
rcTop = GetReBar().GetWindowRect();
|
||||
else
|
||||
if (m_bUseToolBar && GetToolBar().IsWindowVisible())
|
||||
rcTop = GetToolBar().GetWindowRect();
|
||||
|
||||
// Return client size less the rebar and status windows
|
||||
int top = rcFrame.top + rcTop.Height() + m_uRibbonHeight;
|
||||
int left = rcFrame.left;
|
||||
int right = rcFrame.right;
|
||||
int bottom = rcFrame.Height() - (rcStatus.Height());
|
||||
if ((bottom <= top) ||( right <= left))
|
||||
top = left = right = bottom = 0;
|
||||
|
||||
CRect rcView(left, top, right, bottom);
|
||||
return rcView;
|
||||
}
|
||||
|
||||
inline void CRibbonFrame::OnCreate()
|
||||
{
|
||||
// OnCreate is called automatically during window creation when a
|
||||
// WM_CREATE message received.
|
||||
|
||||
// Tasks such as setting the icon, creating child windows, or anything
|
||||
// associated with creating windows are normally performed here.
|
||||
|
||||
if (GetWinVersion() >= 2601) // WinVersion >= Windows 7
|
||||
{
|
||||
m_bUseReBar = FALSE; // Don't use rebars
|
||||
m_bUseToolBar = FALSE; // Don't use a toolbar
|
||||
|
||||
CFrame::OnCreate();
|
||||
|
||||
if (CreateRibbon(this))
|
||||
TRACE(_T("Ribbon Created Succesfully\n"));
|
||||
else
|
||||
throw CWinException(_T("Failed to create ribbon"));
|
||||
}
|
||||
else
|
||||
{
|
||||
CFrame::OnCreate();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CRibbonFrame::OnDestroy()
|
||||
{
|
||||
DestroyRibbon();
|
||||
CFrame::OnDestroy();
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CRibbonFrame::OnViewChanged(UINT32 viewId, UI_VIEWTYPE typeId, IUnknown* pView, UI_VIEWVERB verb, INT32 uReasonCode)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(viewId);
|
||||
UNREFERENCED_PARAMETER(uReasonCode);
|
||||
|
||||
HRESULT hr = E_NOTIMPL;
|
||||
|
||||
// Checks to see if the view that was changed was a Ribbon view.
|
||||
if (UI_VIEWTYPE_RIBBON == typeId)
|
||||
{
|
||||
switch (verb)
|
||||
{
|
||||
// The view was newly created.
|
||||
case UI_VIEWVERB_CREATE:
|
||||
hr = S_OK;
|
||||
break;
|
||||
|
||||
// The view has been resized. For the Ribbon view, the application should
|
||||
// call GetHeight to determine the height of the ribbon.
|
||||
case UI_VIEWVERB_SIZE:
|
||||
{
|
||||
IUIRibbon* pRibbon = NULL;
|
||||
UINT uRibbonHeight;
|
||||
|
||||
hr = pView->QueryInterface(IID_PPV_ARGS(&pRibbon));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Call to the framework to determine the desired height of the Ribbon.
|
||||
hr = pRibbon->GetHeight(&uRibbonHeight);
|
||||
SetRibbonHeight(uRibbonHeight);
|
||||
pRibbon->Release();
|
||||
|
||||
RecalcLayout();
|
||||
// Use the ribbon height to position controls in the client area of the window.
|
||||
}
|
||||
}
|
||||
break;
|
||||
// The view was destroyed.
|
||||
case UI_VIEWVERB_DESTROY:
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT CRibbonFrame::PopulateRibbonRecentItems(__deref_out PROPVARIANT* pvarValue)
|
||||
{
|
||||
LONG iCurrentFile = 0;
|
||||
std::vector<tString> FileNames = GetMRUEntries();
|
||||
std::vector<tString>::iterator iter;
|
||||
int iFileCount = FileNames.size();
|
||||
HRESULT hr = E_FAIL;
|
||||
SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, iFileCount);
|
||||
m_vRecentFiles.clear();
|
||||
|
||||
if (psa != NULL)
|
||||
{
|
||||
for (iter = FileNames.begin(); iter < FileNames.end(); ++iter)
|
||||
{
|
||||
tString strCurrentFile = (*iter);
|
||||
WCHAR wszCurrentFile[MAX_PATH] = {0L};
|
||||
lstrcpynW(wszCurrentFile, T2W(strCurrentFile.c_str()), MAX_PATH);
|
||||
|
||||
CRecentFiles* pRecentFiles = new CRecentFiles(wszCurrentFile);
|
||||
m_vRecentFiles.push_back(RecentFilesPtr(pRecentFiles));
|
||||
hr = SafeArrayPutElement(psa, &iCurrentFile, static_cast<void*>(pRecentFiles));
|
||||
++iCurrentFile;
|
||||
}
|
||||
|
||||
SAFEARRAYBOUND sab = {iCurrentFile,0};
|
||||
SafeArrayRedim(psa, &sab);
|
||||
hr = UIInitPropertyFromIUnknownArray(UI_PKEY_RecentItems, psa, pvarValue);
|
||||
|
||||
SafeArrayDestroy(psa); // Calls release for each element in the array
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline void CRibbonFrame::UpdateMRUMenu()
|
||||
{
|
||||
// Suppress UpdateMRUMenu when ribbon is used
|
||||
if (0 != GetRibbonFramework()) return;
|
||||
|
||||
CFrame::UpdateMRUMenu();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// Declaration of the nested CRecentFiles class
|
||||
//
|
||||
inline CRibbonFrame::CRecentFiles::CRecentFiles(PWSTR wszFullPath) : m_cRef(1)
|
||||
{
|
||||
SHFILEINFOW sfi;
|
||||
DWORD_PTR dwPtr = NULL;
|
||||
m_wszFullPath[0] = L'\0';
|
||||
m_wszDisplayName[0] = L'\0';
|
||||
|
||||
if (NULL != lstrcpynW(m_wszFullPath, wszFullPath, MAX_PATH))
|
||||
{
|
||||
dwPtr = ::SHGetFileInfoW(wszFullPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME | SHGFI_USEFILEATTRIBUTES);
|
||||
|
||||
if (dwPtr != NULL)
|
||||
{
|
||||
lstrcpynW(m_wszDisplayName, sfi.szDisplayName, MAX_PATH);
|
||||
}
|
||||
else // Provide a reasonable fallback.
|
||||
{
|
||||
lstrcpynW(m_wszDisplayName, m_wszFullPath, MAX_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline STDMETHODIMP_(ULONG) CRibbonFrame::CRecentFiles::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
inline STDMETHODIMP_(ULONG) CRibbonFrame::CRecentFiles::Release()
|
||||
{
|
||||
return InterlockedDecrement(&m_cRef);
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CRibbonFrame::CRecentFiles::QueryInterface(REFIID iid, void** ppv)
|
||||
{
|
||||
if (!ppv)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (iid == __uuidof(IUnknown))
|
||||
{
|
||||
*ppv = static_cast<IUnknown*>(this);
|
||||
}
|
||||
else if (iid == __uuidof(IUISimplePropertySet))
|
||||
{
|
||||
*ppv = static_cast<IUISimplePropertySet*>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// IUISimplePropertySet methods.
|
||||
inline STDMETHODIMP CRibbonFrame::CRecentFiles::GetValue(__in REFPROPERTYKEY key, __out PROPVARIANT *ppropvar)
|
||||
{
|
||||
HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
|
||||
if (key == UI_PKEY_Label)
|
||||
{
|
||||
hr = UIInitPropertyFromString(key, m_wszDisplayName, ppropvar);
|
||||
}
|
||||
else if (key == UI_PKEY_LabelDescription)
|
||||
{
|
||||
hr = UIInitPropertyFromString(key, m_wszDisplayName, ppropvar);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // _WIN32XX_RIBBON_H_
|
||||
|
199
mmc_updater/depends/win32cpp/shared_ptr.h
Normal file
199
mmc_updater/depends/win32cpp/shared_ptr.h
Normal file
@ -0,0 +1,199 @@
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// This software was developed from code available in the public domain
|
||||
// and has no copyright.
|
||||
|
||||
|
||||
// About Shared_Ptr:
|
||||
// Shared_Ptr wraps a reference-counted smart pointer around a dynamically
|
||||
// allocated object. Unlike auto_ptr, the Shared_Ptr can be used as a smart
|
||||
// pointer for objects stored in containers like std::vector. Do not use
|
||||
// Shared_Ptr (or shared_ptr or auto_ptr) for dynamically allocated arrays.
|
||||
// See below for advice on how to wrap dynamically allocated arrays in a
|
||||
// vector.
|
||||
//
|
||||
// The next standard of C++ will also contain a shared_ptr. Some modern
|
||||
// compilers already have a shared_ptr available as std::tr1::shared_ptr. If
|
||||
// your compiler already provides a shared_ptr, or if you have Boost, you
|
||||
// should use that smart pointer instead. This class has been provided for
|
||||
// those users who don't have easy access to an "official" shared_ptr.
|
||||
// Note that this class is "Shared_Ptr", a slightly different name to the
|
||||
// future "shared_ptr" to avoid naming conflicts.
|
||||
|
||||
// Advantages of Shared_Ptr (or shared_ptr where available):
|
||||
// - Shared_Ptr can be safely copied. This makes then suitable for containers.
|
||||
// - Shared_Ptr automatically calls delete for the wrapped pointer when
|
||||
// its last copy goes out of scope.
|
||||
// - Shared_Ptr simplifies exception safety.
|
||||
//
|
||||
// Without smart pointers, it can be quite challenging to ensure that every
|
||||
// dynamically allocated pointer (i.e. use of new) is deleted in the event of
|
||||
// all possible exceptions. In addition to the exceptions we throw ourselves,
|
||||
// "new" itself will throw an exception it it fails, as does the STL (Standard
|
||||
// Template Library which includes vector and string). Without smart pointers
|
||||
// we often need to resort to additional try/catch blocks simply to avoid
|
||||
// memory leaks when exceptions occur.
|
||||
|
||||
// Examples:
|
||||
// Shared_Ptr<CWnd> w1(new CWnd);
|
||||
// or
|
||||
// Shared_Ptr<CWnd> w1 = new CWnd;
|
||||
// or
|
||||
// typedef Shared_Ptr<CWnd> CWndPtr;
|
||||
// CWndPtr w1 = new CWnd;
|
||||
// or
|
||||
// typedef Shared_Ptr<CWnd> CWndPtr;
|
||||
// CWndPtr w1(new CWnd);
|
||||
//
|
||||
// And with a vector
|
||||
// typedef Shared_Ptr<CWnd> CWndPtr;
|
||||
// std::vector<CWndPtr> MyVector;
|
||||
// MyVector.push_back(new CWnd);
|
||||
// or
|
||||
// typedef Shared_Ptr<CWnd> CWndPtr;
|
||||
// CWnd* pWnd = new CWnd;
|
||||
// std::vector<CWndPtr> MyVector;
|
||||
// MyVector.push_back(pWnd);
|
||||
//
|
||||
|
||||
// How to handle dynamically allocated arrays:
|
||||
// While we could create a smart pointer for arrays, we don't need to because
|
||||
// std::vector already handles this for us. Consider the following example:
|
||||
// int nLength = ::GetWindowTextLength(m_hWnd);
|
||||
// pTChar = new TCHAR[nLength+1];
|
||||
// memset(pTChar, 0, (nLength+1)*sizeof(TCHAR));
|
||||
// ::GetWindowText(m_hWnd, m_pTChar, nLength+1);
|
||||
// ....
|
||||
// delete[] pTChar;
|
||||
//
|
||||
// This can be improved by using a vector instead of an array
|
||||
// int nLength = ::GetWindowTextLength(m_hWnd);
|
||||
// std::vector<TCHAR> vTChar( nLength+1, _T('\0') );
|
||||
// TCHAR* pTCharArray = &vTChar.front();
|
||||
// ::GetWindowText(m_hWnd, pTCharArray, nLength+1);
|
||||
//
|
||||
// This works because the memory in a vector is always contiguous. Note that
|
||||
// this is NOT always true of std::string.
|
||||
|
||||
|
||||
// Summing up:
|
||||
// In my opinion, "naked" pointers for dynamically created objects should be
|
||||
// avoided in modern C++ code. That's to say that calls to "new" should be
|
||||
// wrapped in some sort of smart pointer wherever possible. This eliminates
|
||||
// the possibility of memory leaks (particularly in the event of exceptions).
|
||||
// It also elminiates the need for delete in user's code.
|
||||
|
||||
#ifndef _WIN32XX_SHARED_PTR_
|
||||
#define _WIN32XX_SHARED_PTR_
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
template <class T1>
|
||||
class Shared_Ptr
|
||||
{
|
||||
public:
|
||||
Shared_Ptr() : m_ptr(NULL), m_count(NULL) { }
|
||||
Shared_Ptr(T1 * p) : m_ptr(p), m_count(NULL)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_ptr) m_count = new long(0);
|
||||
inc_ref();
|
||||
}
|
||||
// catch the unlikely event of 'new long(0)' throwing an exception
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
delete m_ptr;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
Shared_Ptr(const Shared_Ptr& rhs) : m_ptr(rhs.m_ptr), m_count(rhs.m_count) { inc_ref(); }
|
||||
~Shared_Ptr()
|
||||
{
|
||||
if(m_count && 0 == dec_ref())
|
||||
{
|
||||
// Note: This code doesn't handle a pointer to an array.
|
||||
// We would need delete[] m_ptr to handle that.
|
||||
delete m_ptr;
|
||||
delete m_count;
|
||||
}
|
||||
}
|
||||
|
||||
T1* get() const { return m_ptr; }
|
||||
long use_count() const { return m_count? *m_count : 0; }
|
||||
bool unique() const { return (m_count && (*m_count == 1)); }
|
||||
|
||||
void swap(Shared_Ptr& rhs)
|
||||
{
|
||||
std::swap(m_ptr, rhs.m_ptr);
|
||||
std::swap(m_count, rhs.m_count);
|
||||
}
|
||||
|
||||
Shared_Ptr& operator=(const Shared_Ptr& rhs)
|
||||
{
|
||||
Shared_Ptr tmp(rhs);
|
||||
this->swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T1* operator->() const
|
||||
{
|
||||
assert(m_ptr);
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
T1& operator*() const
|
||||
{
|
||||
assert (m_ptr);
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
bool operator== (const Shared_Ptr& rhs) const
|
||||
{
|
||||
return ( *m_ptr == *rhs.m_ptr);
|
||||
}
|
||||
|
||||
bool operator!= (const Shared_Ptr& rhs) const
|
||||
{
|
||||
return ( *m_ptr != *rhs.m_ptr);
|
||||
}
|
||||
|
||||
bool operator< (const Shared_Ptr& rhs) const
|
||||
{
|
||||
return ( *m_ptr < *rhs.m_ptr );
|
||||
}
|
||||
|
||||
bool operator> (const Shared_Ptr& rhs) const
|
||||
{
|
||||
return ( *m_ptr > *rhs.m_ptr );
|
||||
}
|
||||
|
||||
private:
|
||||
void inc_ref()
|
||||
{
|
||||
if(m_count)
|
||||
InterlockedIncrement(m_count);
|
||||
}
|
||||
|
||||
int dec_ref()
|
||||
{
|
||||
assert (m_count);
|
||||
return InterlockedDecrement(m_count);
|
||||
}
|
||||
|
||||
T1* m_ptr;
|
||||
long* m_count;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _WIN32XX_SHARED_PTR_
|
778
mmc_updater/depends/win32cpp/socket.h
Normal file
778
mmc_updater/depends/win32cpp/socket.h
Normal file
@ -0,0 +1,778 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// socket.h
|
||||
// Declaration of the CSocket class
|
||||
//
|
||||
// The CSocket class represents a network socket. It encapsualtes many of
|
||||
// the Windows Socket SPI fuctions, providing an object-oriented approach
|
||||
// to network programming. After StartEvents is called, CSocket monitors
|
||||
// the socket and responds automatically to network events. This event
|
||||
// monitoring, for example, automatically calls OnReceive when there is
|
||||
// data on the socket to be read, and OnAccept when a server should accept
|
||||
// a connection from a client.
|
||||
|
||||
// Users of this class should be aware that functions like OnReceive,
|
||||
// OnAccept, etc. are called on a different thread from the one CSocket is
|
||||
// instanciated on. The thread for these functions needs to respond quickly
|
||||
// to other network events, so it shouldn't be delayed. It also doesn't run
|
||||
// a message loop, so it can't be used to create windows. For these reasons
|
||||
// it might be best to use PostMessage in response to these functions in a
|
||||
// windows environment.
|
||||
|
||||
// Refer to the network samples for an example of how to use this class to
|
||||
// create a TCP client & server, and a UDP client and server.
|
||||
|
||||
// To compile programs with CSocket, link with ws3_32.lib for Win32,
|
||||
// and ws2.lib for Windows CE. Windows 95 systems will need to install the
|
||||
// "Windows Sockets 2.0 for Windows 95". It's available from:
|
||||
// http://support.microsoft.com/kb/182108/EN-US/
|
||||
|
||||
// For a TCP server, inherit a class from CSocket and override OnAccept, OnDisconnect
|
||||
// and OnRecieve. Create one instance of this class and use it as a listening socket.
|
||||
// The purpose of the listening socket is to detect connections from clients and accept them.
|
||||
// For the listening socket, we do the following:
|
||||
// 1) Create the socket.
|
||||
// 2) Bind an IP address to the socket.
|
||||
// 3) Listen on the socket for incoming connection requests.
|
||||
// 4) Use StartNotifyRevents to receive notification of network events.
|
||||
// 5) Override OnAccept to accept requests on a newly created data CSocket object.
|
||||
// 6) Create a new data socket for each client connection accepted.
|
||||
// 7) The server socket uses the 'accept' function to accept an incoming connection
|
||||
// from this new data socket.
|
||||
|
||||
// The purpose of the data socket is to send data to, and recieve data from the client.
|
||||
// There will be one data socket for each client accepted by the server.
|
||||
// To use it we do the following:
|
||||
// * To recieve data from the client, override OnReceive and use Receive.
|
||||
// * To send data to use Send.
|
||||
// * OnDisconnect can be used to detect when the client is disconnected.
|
||||
|
||||
// For a TCP client, inherit from CSocket and override OnReceive and OnDisconnect.
|
||||
// Create an instance of this inherited class, and perform the following steps:
|
||||
// 1) Create the socket.
|
||||
// 2) Connect to the server.
|
||||
// 3) Use StartNotifyRevents to receive notification of network events.
|
||||
// We are now ready to send and recieve data from the server.
|
||||
// * Use Send to send data to the server.
|
||||
// * Override OnReceive and use Recieve to receive data from the server
|
||||
// * OnDisconnect can be used to detect when the client is disconnected from the server.
|
||||
|
||||
// Notes regarding IPv6 support
|
||||
// * IPv6 is supported on Windows Vista and above. Windows XP with SP2 provides
|
||||
// "experimental" support, which can be enabled by entering "ipv6 install"
|
||||
// at a command prompt.
|
||||
// * IPv6 is not supported by all compilters and devlopment environments. In
|
||||
// particular, it is not supported by Dev-C++ or Borland 5.5. A modern
|
||||
// Platform SDK needs to be added to Visual Studio 6 for it to support IPv6.
|
||||
// * IsIPV6Supported returns false if either the operating system or the
|
||||
// development environment fails to support IPv6.
|
||||
//
|
||||
|
||||
#ifndef _WIN32XX_SOCKET_H_
|
||||
#define _WIN32XX_SOCKET_H_
|
||||
|
||||
|
||||
#include "wincore.h"
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <process.h>
|
||||
|
||||
|
||||
#define THREAD_TIMEOUT 100
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
typedef int WINAPI GETADDRINFO(LPCSTR, LPCSTR, const struct addrinfo*, struct addrinfo**);
|
||||
typedef void WINAPI FREEADDRINFO(struct addrinfo*);
|
||||
|
||||
class CSocket
|
||||
{
|
||||
public:
|
||||
CSocket();
|
||||
virtual ~CSocket();
|
||||
|
||||
// Operations
|
||||
virtual void Accept(CSocket& rClientSock, struct sockaddr* addr, int* addrlen);
|
||||
virtual int Bind(LPCTSTR addr, LPCTSTR port);
|
||||
virtual int Bind(const struct sockaddr* name, int namelen);
|
||||
virtual int Connect(LPCTSTR addr, LPCTSTR port);
|
||||
virtual int Connect(const struct sockaddr* name, int namelen);
|
||||
virtual BOOL Create( int family, int type, int protocol = IPPROTO_IP);
|
||||
virtual void Disconnect();
|
||||
virtual void FreeAddrInfo( struct addrinfo* ai );
|
||||
virtual int GetAddrInfo( LPCTSTR nodename, LPCTSTR servname, const struct addrinfo* hints, struct addrinfo** res);
|
||||
virtual LPCTSTR GetLastError();
|
||||
virtual int ioCtlSocket(long cmd, u_long* argp);
|
||||
virtual BOOL IsIPV6Supported();
|
||||
virtual int Listen(int backlog = SOMAXCONN);
|
||||
virtual int Receive(TCHAR* buf, int len, int flags);
|
||||
virtual int ReceiveFrom(TCHAR* buf, int len, int flags, struct sockaddr* from, int* fromlen);
|
||||
virtual int Send(LPCTSTR buf, int len, int flags);
|
||||
virtual int SendTo(LPCTSTR send, int len, int flags, LPCTSTR addr, LPCTSTR port);
|
||||
virtual int SendTo(LPCTSTR buf, int len, int flags, const struct sockaddr* to, int tolen);
|
||||
|
||||
virtual void StartEvents();
|
||||
virtual void StopEvents();
|
||||
|
||||
// Attributes
|
||||
virtual int GetPeerName(struct sockaddr* name, int* namelen);
|
||||
virtual int GetSockName(struct sockaddr* name, int* namelen);
|
||||
SOCKET& GetSocket() { return m_Socket; }
|
||||
virtual int GetSockOpt(int level, int optname, char* optval, int* optlen);
|
||||
virtual int SetSockOpt(int level, int optname, const char* optval, int optlen);
|
||||
|
||||
// Override these functions to monitor events
|
||||
virtual void OnAccept() {}
|
||||
virtual void OnAddresListChange() {}
|
||||
virtual void OnDisconnect() {}
|
||||
virtual void OnConnect() {}
|
||||
virtual void OnOutOfBand() {}
|
||||
virtual void OnQualityOfService() {}
|
||||
virtual void OnReceive() {}
|
||||
virtual void OnRoutingChange() {}
|
||||
virtual void OnSend() {}
|
||||
|
||||
|
||||
|
||||
// Allow CSocket to be used as a SOCKET
|
||||
operator SOCKET() const {return m_Socket;}
|
||||
|
||||
private:
|
||||
CSocket(const CSocket&); // Disable copy construction
|
||||
CSocket& operator = (const CSocket&); // Disable assignment operator
|
||||
static UINT WINAPI EventThread(LPVOID thread_data);
|
||||
|
||||
tString m_tsErrorMessage;
|
||||
SOCKET m_Socket;
|
||||
HMODULE m_hWS2_32;
|
||||
HANDLE m_hEventThread; // Handle to the thread
|
||||
HANDLE m_StopRequest; // An event to signal the event thread should stop
|
||||
HANDLE m_Stopped; // An event to signal the event thread is stopped
|
||||
|
||||
GETADDRINFO* m_pfnGetAddrInfo; // pointer for the GetAddrInfo function
|
||||
FREEADDRINFO* m_pfnFreeAddrInfo; // pointer for the FreeAddrInfo function
|
||||
};
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
inline CSocket::CSocket() : m_Socket(INVALID_SOCKET), m_hEventThread(0)
|
||||
{
|
||||
// Initialise the Windows Socket services
|
||||
WSADATA wsaData;
|
||||
|
||||
if (0 != ::WSAStartup(MAKEWORD(2,2), &wsaData))
|
||||
throw CWinException(_T("WSAStartup failed"));
|
||||
|
||||
m_hWS2_32 = ::LoadLibrary(_T("WS2_32.dll"));
|
||||
if (0 == m_hWS2_32)
|
||||
throw CWinException(_T("Failed to load WS2_2.dll"));
|
||||
|
||||
m_pfnGetAddrInfo = (GETADDRINFO*) GetProcAddress(m_hWS2_32, "getaddrinfo");
|
||||
m_pfnFreeAddrInfo = (FREEADDRINFO*) GetProcAddress(m_hWS2_32, "freeaddrinfo");
|
||||
|
||||
m_StopRequest = ::CreateEvent(0, TRUE, FALSE, 0);
|
||||
m_Stopped = ::CreateEvent(0, TRUE, FALSE, 0);
|
||||
}
|
||||
|
||||
inline CSocket::~CSocket()
|
||||
{
|
||||
Disconnect();
|
||||
|
||||
// Close handles
|
||||
::CloseHandle(m_StopRequest);
|
||||
::CloseHandle(m_Stopped);
|
||||
|
||||
// Terminate the Windows Socket services
|
||||
::WSACleanup();
|
||||
|
||||
::FreeLibrary(m_hWS2_32);
|
||||
}
|
||||
|
||||
inline void CSocket::Accept(CSocket& rClientSock, struct sockaddr* addr, int* addrlen)
|
||||
{
|
||||
// The accept function permits an incoming connection attempt on the socket.
|
||||
|
||||
rClientSock.m_Socket = ::accept(m_Socket, addr, addrlen);
|
||||
if (INVALID_SOCKET == rClientSock.GetSocket())
|
||||
TRACE(_T("Accept failed\n"));
|
||||
}
|
||||
|
||||
inline int CSocket::Bind(LPCTSTR addr, LPCTSTR port)
|
||||
// The bind function associates a local address with the socket.
|
||||
{
|
||||
int RetVal = 0;
|
||||
|
||||
if (IsIPV6Supported())
|
||||
{
|
||||
|
||||
#ifdef GetAddrInfo // Skip the following code block for older development environments
|
||||
|
||||
ADDRINFO Hints= {0};
|
||||
Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
|
||||
ADDRINFO *AddrInfo;
|
||||
|
||||
RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);
|
||||
if (RetVal != 0)
|
||||
{
|
||||
TRACE( _T("GetAddrInfo failed\n"));
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
// Bind the IP address to the listening socket
|
||||
RetVal = ::bind( m_Socket, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );
|
||||
if ( RetVal == SOCKET_ERROR )
|
||||
{
|
||||
TRACE(_T("Bind failed\n"));
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
// Free the address information allocated by GetAddrInfo
|
||||
FreeAddrInfo(AddrInfo);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sockaddr_in clientService;
|
||||
clientService.sin_family = AF_INET;
|
||||
clientService.sin_addr.s_addr = inet_addr( T2A(addr) );
|
||||
int nPort = -1;
|
||||
nPort = atoi( T2A(port) );
|
||||
if (-1 == nPort)
|
||||
{
|
||||
TRACE(_T("Invalid port number\n"));
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
clientService.sin_port = htons( (u_short)nPort );
|
||||
|
||||
RetVal = ::bind( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );
|
||||
if ( 0 != RetVal )
|
||||
TRACE(_T("Bind failed\n"));
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
inline int CSocket::Bind(const struct sockaddr* name, int namelen)
|
||||
{
|
||||
// The bind function associates a local address with the socket.
|
||||
|
||||
int Result = ::bind (m_Socket, name, namelen);
|
||||
if ( 0 != Result )
|
||||
TRACE(_T("Bind failed\n"));
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::Connect(LPCTSTR addr, LPCTSTR port)
|
||||
// The Connect function establishes a connection to the socket.
|
||||
{
|
||||
int RetVal = 0;
|
||||
|
||||
if (IsIPV6Supported())
|
||||
{
|
||||
|
||||
#ifdef GetAddrInfo // Skip the following code block for older development environments
|
||||
|
||||
ADDRINFO Hints= {0};
|
||||
Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
|
||||
ADDRINFO *AddrInfo;
|
||||
|
||||
RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);
|
||||
if (RetVal != 0)
|
||||
{
|
||||
TRACE( _T("getaddrinfo failed\n"));
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
// Bind the IP address to the listening socket
|
||||
RetVal = Connect( AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );
|
||||
if ( RetVal == SOCKET_ERROR )
|
||||
{
|
||||
TRACE(_T("Connect failed\n"));
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
// Free the address information allocatied by GetAddrInfo
|
||||
FreeAddrInfo(AddrInfo);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sockaddr_in clientService;
|
||||
clientService.sin_family = AF_INET;
|
||||
clientService.sin_addr.s_addr = inet_addr( T2A(addr) );
|
||||
int nPort = -1;
|
||||
nPort = atoi( T2A(port) );
|
||||
if (-1 == nPort)
|
||||
{
|
||||
TRACE(_T("Invalid port number\n"));
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
clientService.sin_port = htons( (u_short)nPort );
|
||||
|
||||
RetVal = ::connect( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );
|
||||
if ( 0 != RetVal )
|
||||
TRACE(_T("Connect failed\n"));
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
inline int CSocket::Connect(const struct sockaddr* name, int namelen)
|
||||
{
|
||||
// The Connect function establishes a connection to the socket.
|
||||
|
||||
int Result = ::connect( m_Socket, name, namelen );
|
||||
if ( 0 != Result )
|
||||
TRACE(_T("Connect failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline BOOL CSocket::Create( int family, int type, int protocol /*= IPPROTO_IP*/)
|
||||
{
|
||||
// Creates the socket
|
||||
|
||||
// Valid values:
|
||||
// family: AF_INET or AF_INET6
|
||||
// type: SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM, SOCK_RAW
|
||||
// protocol: IPPROTO_IP, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6
|
||||
|
||||
m_Socket = socket(family, type, protocol);
|
||||
if(m_Socket == INVALID_SOCKET)
|
||||
{
|
||||
TRACE(_T("Failed to create socket\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
inline void CSocket::Disconnect()
|
||||
{
|
||||
::shutdown(m_Socket, SD_BOTH);
|
||||
StopEvents();
|
||||
::closesocket(m_Socket);
|
||||
m_Socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
inline UINT WINAPI CSocket::EventThread(LPVOID thread_data)
|
||||
{
|
||||
// These are the possible network event notifications:
|
||||
// FD_READ Notification of readiness for reading.
|
||||
// FD_WRITE Motification of readiness for writing.
|
||||
// FD_OOB Notification of the arrival of Out Of Band data.
|
||||
// FD_ACCEPT Notification of incoming connections.
|
||||
// FD_CONNECT Notification of completed connection or multipoint join operation.
|
||||
// FD_CLOSE Notification of socket closure.
|
||||
// FD_QOS Notification of socket Quality Of Service changes
|
||||
// FD_ROUTING_INTERFACE_CHANGE Notification of routing interface changes for the specified destination.
|
||||
// FD_ADDRESS_LIST_CHANGE Notification of local address list changes for the address family of the socket.
|
||||
|
||||
WSANETWORKEVENTS NetworkEvents;
|
||||
CSocket* pSocket = (CSocket*)thread_data;
|
||||
SOCKET sClient = pSocket->m_Socket;
|
||||
|
||||
WSAEVENT AllEvents[2];
|
||||
AllEvents[0] = ::WSACreateEvent();
|
||||
AllEvents[1] = (WSAEVENT)pSocket->m_StopRequest;
|
||||
long Events = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE |
|
||||
FD_QOS | FD_ROUTING_INTERFACE_CHANGE | FD_ADDRESS_LIST_CHANGE;
|
||||
|
||||
// Associate the network event object (hNetworkEvents) with the
|
||||
// specified network events (Events) on socket sClient.
|
||||
if( SOCKET_ERROR == WSAEventSelect(sClient, AllEvents[0], Events))
|
||||
{
|
||||
TRACE(_T("Error in Event Select\n"));
|
||||
::SetEvent(pSocket->m_Stopped);
|
||||
::WSACloseEvent(AllEvents[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// loop until the stop event is set
|
||||
for (;;) // infinite loop
|
||||
{
|
||||
// Wait 100 ms for a network event
|
||||
DWORD dwResult = ::WSAWaitForMultipleEvents(2, AllEvents, FALSE, THREAD_TIMEOUT, FALSE);
|
||||
|
||||
// Check event for stop thread
|
||||
if(::WaitForSingleObject(pSocket->m_StopRequest, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
::WSACloseEvent(AllEvents[0]);
|
||||
::SetEvent(pSocket->m_Stopped);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (WSA_WAIT_FAILED == dwResult)
|
||||
{
|
||||
TRACE(_T("WSAWaitForMultipleEvents failed\n"));
|
||||
::WSACloseEvent(AllEvents[0]);
|
||||
::SetEvent(pSocket->m_Stopped);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Proceed if a network event occurred
|
||||
if (WSA_WAIT_TIMEOUT != dwResult)
|
||||
{
|
||||
|
||||
if ( SOCKET_ERROR == ::WSAEnumNetworkEvents(sClient, AllEvents[0], &NetworkEvents) )
|
||||
{
|
||||
TRACE(_T("WSAEnumNetworkEvents failed\n"));
|
||||
::WSACloseEvent(AllEvents[0]);
|
||||
::SetEvent(pSocket->m_Stopped);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
|
||||
pSocket->OnAccept();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_READ)
|
||||
pSocket->OnReceive();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_WRITE)
|
||||
pSocket->OnSend();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_OOB)
|
||||
pSocket->OnOutOfBand();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_QOS)
|
||||
pSocket->OnQualityOfService();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_CONNECT)
|
||||
pSocket->OnConnect();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_ROUTING_INTERFACE_CHANGE)
|
||||
pSocket->OnRoutingChange();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_ADDRESS_LIST_CHANGE)
|
||||
pSocket->OnAddresListChange();
|
||||
|
||||
if (NetworkEvents.lNetworkEvents & FD_CLOSE)
|
||||
{
|
||||
::shutdown(sClient, SD_BOTH);
|
||||
::closesocket(sClient);
|
||||
pSocket->OnDisconnect();
|
||||
::WSACloseEvent(AllEvents[0]);
|
||||
::SetEvent(pSocket->m_Stopped);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int CSocket::GetAddrInfo( LPCTSTR nodename, LPCTSTR servname, const struct addrinfo* hints, struct addrinfo** res)
|
||||
{
|
||||
|
||||
#ifdef GetAddrInfo
|
||||
|
||||
std::string sNodeName = T2A(nodename);
|
||||
std::string sServName = T2A(servname);
|
||||
return (*m_pfnGetAddrInfo)(sNodeName.c_str(), sServName.c_str(), hints, res);
|
||||
|
||||
#else
|
||||
|
||||
UNREFERENCED_PARAMETER(nodename);
|
||||
UNREFERENCED_PARAMETER(servname);
|
||||
UNREFERENCED_PARAMETER(hints);
|
||||
UNREFERENCED_PARAMETER(res);
|
||||
|
||||
throw CWinException(_T("getaddrinfo is not supported"));
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
inline LPCTSTR CSocket::GetLastError()
|
||||
{
|
||||
// Retrieves the most recent network error.
|
||||
|
||||
int ErrorCode = WSAGetLastError();
|
||||
LPTSTR Message = NULL;
|
||||
m_tsErrorMessage = _T("");
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&Message, 1024, NULL);
|
||||
|
||||
if (Message)
|
||||
{
|
||||
m_tsErrorMessage = Message;
|
||||
::LocalFree(Message);
|
||||
}
|
||||
|
||||
return m_tsErrorMessage.c_str();
|
||||
}
|
||||
|
||||
inline int CSocket::GetPeerName(struct sockaddr* name, int* namelen)
|
||||
{
|
||||
int Result = ::getpeername(m_Socket, name, namelen);
|
||||
if (0 != Result)
|
||||
TRACE(_T("GetPeerName failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::GetSockName(struct sockaddr* name, int* namelen)
|
||||
{
|
||||
int Result = ::getsockname(m_Socket, name, namelen);
|
||||
if (0 != Result)
|
||||
TRACE(_T("GetSockName Failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::GetSockOpt(int level, int optname, char* optval, int* optlen)
|
||||
{
|
||||
int Result = ::getsockopt(m_Socket, level, optname, optval, optlen);
|
||||
if (0 != Result)
|
||||
TRACE(_T("GetSockOpt Failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline void CSocket::FreeAddrInfo( struct addrinfo* ai )
|
||||
{
|
||||
|
||||
#ifdef GetAddrInfo
|
||||
|
||||
(*m_pfnFreeAddrInfo)(ai);
|
||||
|
||||
#else
|
||||
|
||||
UNREFERENCED_PARAMETER(ai);
|
||||
|
||||
throw CWinException(_T("getaddrinfo is not supported"));
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
inline int CSocket::ioCtlSocket(long cmd, u_long* argp)
|
||||
{
|
||||
int Result = ::ioctlsocket(m_Socket, cmd, argp);
|
||||
if (0 != Result)
|
||||
TRACE(_T("ioCtlSocket Failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline BOOL CSocket::IsIPV6Supported()
|
||||
{
|
||||
BOOL IsIPV6Supported = FALSE;
|
||||
|
||||
#ifdef GetAddrInfo
|
||||
|
||||
if (m_pfnGetAddrInfo != 0 && m_pfnFreeAddrInfo != 0)
|
||||
IsIPV6Supported = TRUE;
|
||||
|
||||
#endif
|
||||
|
||||
return IsIPV6Supported;
|
||||
}
|
||||
|
||||
inline int CSocket::Listen(int backlog /*= SOMAXCONN*/)
|
||||
{
|
||||
int Result = ::listen(m_Socket, backlog);
|
||||
if (0 != Result)
|
||||
TRACE(_T("Listen Failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::Receive(TCHAR* buf, int len, int flags)
|
||||
{
|
||||
std::vector<char> vChar(len+1, '\0');
|
||||
char* pCharArray = &vChar.front();
|
||||
int Result = ::recv(m_Socket, pCharArray, len, flags);
|
||||
if (SOCKET_ERROR == Result)
|
||||
TRACE(_T("Receive failed\n"));
|
||||
|
||||
lstrcpyn(buf, A2T(pCharArray), len);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::ReceiveFrom(TCHAR* buf, int len, int flags, struct sockaddr* from, int* fromlen)
|
||||
//The ReceiveFrom function receives a datagram and stores the source address.
|
||||
{
|
||||
std::vector<char> vChar(len+1, '\0');
|
||||
char* pCharArray = &vChar.front();
|
||||
int Result = ::recvfrom(m_Socket, pCharArray, len, flags, from, fromlen);
|
||||
if (SOCKET_ERROR == Result)
|
||||
TRACE(_T("ReceiveFrom failed\n"));
|
||||
|
||||
lstrcpyn(buf, A2T(pCharArray), len);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::Send(LPCTSTR buf, int len, int flags)
|
||||
{
|
||||
int Result = ::send(m_Socket, T2A(buf), len, flags);
|
||||
if (SOCKET_ERROR == Result)
|
||||
TRACE(_T("Send failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::SendTo(LPCTSTR send, int len, int flags, LPCTSTR addr, LPCTSTR port)
|
||||
// The sendto function sends data to a specific destination.
|
||||
{
|
||||
int RetVal = 0;
|
||||
|
||||
if (IsIPV6Supported())
|
||||
{
|
||||
|
||||
#ifdef GetAddrInfo // Skip the following code block for older development environments
|
||||
|
||||
ADDRINFO Hints= {0};
|
||||
Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
|
||||
ADDRINFO *AddrInfo;
|
||||
|
||||
RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);
|
||||
if (RetVal != 0)
|
||||
{
|
||||
TRACE( _T("GetAddrInfo failed\n"));
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
RetVal = ::sendto(m_Socket, T2A(send), len, flags, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );
|
||||
if ( RetVal == SOCKET_ERROR )
|
||||
{
|
||||
TRACE(_T("SendTo failed\n"));
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
// Free the address information allocatied by GetAddrInfo
|
||||
FreeAddrInfo(AddrInfo);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sockaddr_in clientService;
|
||||
clientService.sin_family = AF_INET;
|
||||
clientService.sin_addr.s_addr = inet_addr( T2A(addr) );
|
||||
int nPort = -1;
|
||||
nPort = atoi( T2A(port));
|
||||
if (-1 == nPort)
|
||||
{
|
||||
TRACE(_T("Invalid port number\n"));
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
clientService.sin_port = htons( (u_short)nPort );
|
||||
|
||||
RetVal = ::sendto( m_Socket, T2A(send), len, flags, (SOCKADDR*) &clientService, sizeof(clientService) );
|
||||
if ( SOCKET_ERROR != RetVal )
|
||||
TRACE(_T("SendTo failed\n"));
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
inline int CSocket::SendTo(LPCTSTR buf, int len, int flags, const struct sockaddr* to, int tolen)
|
||||
// The sendto function sends data to a specific destination.
|
||||
{
|
||||
int Result = ::sendto(m_Socket, T2A(buf), len, flags, to, tolen);
|
||||
if (SOCKET_ERROR == Result)
|
||||
TRACE(_T("SendTo failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline int CSocket::SetSockOpt(int level, int optname, const char* optval, int optlen)
|
||||
{
|
||||
int Result = ::setsockopt(m_Socket, level, optname, optval, optlen);
|
||||
if (0 != Result)
|
||||
TRACE(_T("SetSockOpt failed\n"));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline void CSocket::StartEvents()
|
||||
{
|
||||
// This function starts the thread which monitors the socket for events.
|
||||
StopEvents(); // Ensure the thread isn't already running
|
||||
UINT ThreadID; // a return variable required for Win95, Win98, WinME
|
||||
m_hEventThread = (HANDLE)::_beginthreadex(NULL, 0, CSocket::EventThread, (LPVOID) this, 0, &ThreadID);
|
||||
}
|
||||
|
||||
inline void CSocket::StopEvents()
|
||||
{
|
||||
// Terminates the event thread gracefully (if possible)
|
||||
if (m_hEventThread)
|
||||
{
|
||||
::SetThreadPriority(m_hEventThread, THREAD_PRIORITY_HIGHEST);
|
||||
::SetEvent(m_StopRequest);
|
||||
|
||||
for (;;) // infinite loop
|
||||
{
|
||||
// wait for the Thread stopping event to be set
|
||||
if ( WAIT_TIMEOUT == ::WaitForSingleObject(m_Stopped, THREAD_TIMEOUT * 10) )
|
||||
{
|
||||
// Note: An excessive delay in processing any of the notification functions
|
||||
// can cause us to get here. (Yes one second is an excessive delay. Its a bug!)
|
||||
TRACE(_T("*** Error: Event Thread won't die ***\n") );
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
::CloseHandle(m_hEventThread);
|
||||
m_hEventThread = 0;
|
||||
}
|
||||
|
||||
::ResetEvent(m_StopRequest);
|
||||
::ResetEvent(m_Stopped);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // #ifndef _WIN32XX_SOCKET_H_
|
||||
|
226
mmc_updater/depends/win32cpp/statusbar.h
Normal file
226
mmc_updater/depends/win32cpp/statusbar.h
Normal file
@ -0,0 +1,226 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef _WIN32XX_STATUSBAR_H_
|
||||
#define _WIN32XX_STATUSBAR_H_
|
||||
|
||||
#include "wincore.h"
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
//////////////////////////////////////
|
||||
// Declaration of the CStatusBar class
|
||||
//
|
||||
class CStatusBar : public CWnd
|
||||
{
|
||||
public:
|
||||
CStatusBar();
|
||||
virtual ~CStatusBar() {}
|
||||
|
||||
// Overridables
|
||||
virtual void PreCreate(CREATESTRUCT& cs);
|
||||
virtual void PreRegisterClass(WNDCLASS &wc);
|
||||
|
||||
// Attributes
|
||||
int GetParts();
|
||||
HICON GetPartIcon(int iPart);
|
||||
CRect GetPartRect(int iPart);
|
||||
tString GetPartText(int iPart) const;
|
||||
BOOL IsSimple();
|
||||
BOOL SetPartIcon(int iPart, HICON hIcon);
|
||||
BOOL SetPartText(int iPart, LPCTSTR szText, UINT Style = 0) const;
|
||||
BOOL SetPartWidth(int iPart, int iWidth) const;
|
||||
|
||||
// Operations
|
||||
CStatusBar(const CStatusBar&); // Disable copy construction
|
||||
CStatusBar& operator = (const CStatusBar&); // Disable assignment operator
|
||||
|
||||
BOOL CreateParts(int iParts, const int iPaneWidths[]) const;
|
||||
void SetSimple(BOOL fSimple = TRUE);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
//////////////////////////////////////
|
||||
// Definitions for the CStatusBar class
|
||||
//
|
||||
inline CStatusBar::CStatusBar()
|
||||
{
|
||||
}
|
||||
|
||||
inline BOOL CStatusBar::CreateParts(int iParts, const int iPaneWidths[]) const
|
||||
// Sets the number of parts in a status window and the coordinate of the right edge of each part.
|
||||
// If an element of iPaneWidths is -1, the right edge of the corresponding part extends
|
||||
// to the border of the window
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
assert(iParts <= 256);
|
||||
|
||||
return (BOOL)SendMessage(SB_SETPARTS, iParts, (LPARAM)iPaneWidths);
|
||||
}
|
||||
|
||||
inline int CStatusBar::GetParts()
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (int)SendMessage(SB_GETPARTS, 0L, 0L);
|
||||
}
|
||||
|
||||
inline HICON CStatusBar::GetPartIcon(int iPart)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (HICON)SendMessage(SB_GETICON, (WPARAM)iPart, 0L);
|
||||
}
|
||||
|
||||
inline CRect CStatusBar::GetPartRect(int iPart)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
CRect rc;
|
||||
SendMessage(SB_GETRECT, (WPARAM)iPart, (LPARAM)&rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
inline tString CStatusBar::GetPartText(int iPart) const
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
tString PaneText;
|
||||
|
||||
// Get size of Text array
|
||||
int iChars = LOWORD (SendMessage(SB_GETTEXTLENGTH, iPart, 0L));
|
||||
|
||||
std::vector<TCHAR> Text( iChars +1, _T('\0') );
|
||||
TCHAR* pTextArray = &Text[0];
|
||||
|
||||
SendMessage(SB_GETTEXT, iPart, (LPARAM)pTextArray);
|
||||
PaneText = pTextArray;
|
||||
return PaneText;
|
||||
}
|
||||
|
||||
inline BOOL CStatusBar::IsSimple()
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(SB_ISSIMPLE, 0L, 0L);
|
||||
}
|
||||
|
||||
inline void CStatusBar::PreCreate(CREATESTRUCT &cs)
|
||||
{
|
||||
cs.style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | CCS_BOTTOM | SBARS_SIZEGRIP;
|
||||
}
|
||||
|
||||
inline void CStatusBar::PreRegisterClass(WNDCLASS &wc)
|
||||
{
|
||||
// Set the Window Class
|
||||
wc.lpszClassName = STATUSCLASSNAME;
|
||||
}
|
||||
|
||||
inline BOOL CStatusBar::SetPartText(int iPart, LPCTSTR szText, UINT Style) const
|
||||
// Available Styles: Combinations of ...
|
||||
//0 The text is drawn with a border to appear lower than the plane of the window.
|
||||
//SBT_NOBORDERS The text is drawn without borders.
|
||||
//SBT_OWNERDRAW The text is drawn by the parent window.
|
||||
//SBT_POPOUT The text is drawn with a border to appear higher than the plane of the window.
|
||||
//SBT_RTLREADING The text will be displayed in the opposite direction to the text in the parent window.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
BOOL bResult = FALSE;
|
||||
if (SendMessage(SB_GETPARTS, 0L, 0L) >= iPart)
|
||||
bResult = (BOOL)SendMessage(SB_SETTEXT, iPart | Style, (LPARAM)szText);
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
inline BOOL CStatusBar::SetPartIcon(int iPart, HICON hIcon)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return (BOOL)SendMessage(SB_SETICON, (WPARAM)iPart, (LPARAM) hIcon);
|
||||
}
|
||||
|
||||
inline BOOL CStatusBar::SetPartWidth(int iPart, int iWidth) const
|
||||
{
|
||||
// This changes the width of an existing pane, or creates a new pane
|
||||
// with the specified width.
|
||||
// A width of -1 for the last part sets the width to the border of the window.
|
||||
|
||||
assert(::IsWindow(m_hWnd));
|
||||
assert(iPart >= 0 && iPart <= 255);
|
||||
|
||||
// Fill the PartWidths vector with the current width of the statusbar parts
|
||||
int PartsCount = (int)SendMessage(SB_GETPARTS, 0L, 0L);
|
||||
std::vector<int> PartWidths(PartsCount, 0);
|
||||
int* pPartWidthArray = &PartWidths[0];
|
||||
SendMessage(SB_GETPARTS, PartsCount, (LPARAM)pPartWidthArray);
|
||||
|
||||
// Fill the NewPartWidths vector with the new width of the statusbar parts
|
||||
int NewPartsCount = MAX(iPart+1, PartsCount);
|
||||
std::vector<int> NewPartWidths(NewPartsCount, 0);;
|
||||
NewPartWidths = PartWidths;
|
||||
int* pNewPartWidthArray = &NewPartWidths[0];
|
||||
|
||||
if (0 == iPart)
|
||||
pNewPartWidthArray[iPart] = iWidth;
|
||||
else
|
||||
{
|
||||
if (iWidth >= 0)
|
||||
pNewPartWidthArray[iPart] = pNewPartWidthArray[iPart -1] + iWidth;
|
||||
else
|
||||
pNewPartWidthArray[iPart] = -1;
|
||||
}
|
||||
|
||||
// Set the statusbar parts with our new parts count and part widths
|
||||
BOOL bResult = (BOOL)SendMessage(SB_SETPARTS, NewPartsCount, (LPARAM)pNewPartWidthArray);
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
inline void CStatusBar::SetSimple(BOOL fSimple /* = TRUE*/)
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
SendMessage(SB_SIMPLE, (WPARAM)fSimple, 0L);
|
||||
}
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // #ifndef _WIN32XX_STATUSBAR_H_
|
1000
mmc_updater/depends/win32cpp/stdcontrols.h
Normal file
1000
mmc_updater/depends/win32cpp/stdcontrols.h
Normal file
File diff suppressed because it is too large
Load Diff
1658
mmc_updater/depends/win32cpp/tab.h
Normal file
1658
mmc_updater/depends/win32cpp/tab.h
Normal file
File diff suppressed because it is too large
Load Diff
811
mmc_updater/depends/win32cpp/taskdialog.h
Normal file
811
mmc_updater/depends/win32cpp/taskdialog.h
Normal file
@ -0,0 +1,811 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// taskdialog.h
|
||||
// Declaration of the CTaskDialog class
|
||||
|
||||
// A task dialog is a dialog box that can be used to display information
|
||||
// and receive simple input from the user. Like a message box, it is
|
||||
// formatted by the operating system according to parameters you set.
|
||||
// However, a task dialog has many more features than a message box.
|
||||
|
||||
// NOTES:
|
||||
// Task Dialogs are only supported on Windows Vista and above.
|
||||
// Task Dialogs require XP themes enabled (use version 6 of Common Controls)
|
||||
// Task Dialogs are always modal.
|
||||
|
||||
|
||||
#ifndef _WIN32XX_TASKDIALOG_H_
|
||||
#define _WIN32XX_TASKDIALOG_H_
|
||||
|
||||
#include "wincore.h"
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
class CTaskDialog : public CWnd
|
||||
{
|
||||
public:
|
||||
CTaskDialog();
|
||||
virtual ~CTaskDialog() {}
|
||||
|
||||
void AddCommandControl(int nButtonID, LPCTSTR pszCaption);
|
||||
void AddRadioButton(int nRadioButtonID, LPCTSTR pszCaption);
|
||||
void AddRadioButtonGroup(int nIDRadioButtonsFirst, int nIDRadioButtonsLast);
|
||||
void ClickButton(int nButtonID) const;
|
||||
void ClickRadioButton(int nRadioButtonID) const;
|
||||
LRESULT DoModal(CWnd* pParent = NULL);
|
||||
void ElevateButton(int nButtonID, BOOL bElevated);
|
||||
void EnableButton(int nButtonID, BOOL bEnabled);
|
||||
void EnableRadioButton(int nButtonID, BOOL bEnabled);
|
||||
TASKDIALOGCONFIG GetConfig() const;
|
||||
TASKDIALOG_FLAGS GetOptions() const;
|
||||
int GetSelectedButtonID() const;
|
||||
int GetSelectedRadioButtonID() const;
|
||||
BOOL GetVerificationCheckboxState() const;
|
||||
static BOOL IsSupported();
|
||||
void NavigateTo(CTaskDialog& TaskDialog) const;
|
||||
void RemoveAllButtons();
|
||||
void RemoveAllRadioButtons();
|
||||
void Reset();
|
||||
void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons);
|
||||
void SetContent(LPCTSTR pszContent);
|
||||
void SetDefaultButton(int nButtonID);
|
||||
void SetDefaultRadioButton(int nRadioButtonID);
|
||||
void SetDialogWidth(UINT nWidth = 0);
|
||||
void SetExpansionArea(LPCTSTR pszExpandedInfo, LPCTSTR pszExpandedLabel = _T(""), LPCTSTR pszCollapsedLabel = _T(""));
|
||||
void SetFooterIcon(HICON hFooterIcon);
|
||||
void SetFooterIcon(LPCTSTR lpszFooterIcon);
|
||||
void SetFooterText(LPCTSTR pszFooter);
|
||||
void SetMainIcon(HICON hMainIcon);
|
||||
void SetMainIcon(LPCTSTR lpszMainIcon);
|
||||
void SetMainInstruction(LPCTSTR pszMainInstruction);
|
||||
void SetOptions(TASKDIALOG_FLAGS dwFlags);
|
||||
void SetProgressBarMarquee(BOOL bEnabled = TRUE, int nMarqueeSpeed = 0);
|
||||
void SetProgressBarPosition(int nProgressPos);
|
||||
void SetProgressBarRange(int nMinRange, int nMaxRange);
|
||||
void SetProgressBarState(int nNewState = PBST_NORMAL);
|
||||
void SetVerificationCheckbox(BOOL bChecked);
|
||||
void SetVerificationCheckboxText(LPCTSTR pszVerificationText);
|
||||
void SetWindowTitle(LPCTSTR pszWindowTitle);
|
||||
static HRESULT CALLBACK StaticTaskDialogProc(HWND hWnd, UINT uNotification, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData);
|
||||
void StoreText(std::vector<WCHAR>& vWChar, LPCTSTR pFromTChar);
|
||||
void UpdateElementText(TASKDIALOG_ELEMENTS eElement, LPCTSTR pszNewText);
|
||||
|
||||
|
||||
protected:
|
||||
// Override these functions as required
|
||||
virtual BOOL OnTDButtonClicked(int nButtonID);
|
||||
virtual void OnTDConstructed();
|
||||
virtual void OnTDCreated();
|
||||
virtual void OnTDDestroyed();
|
||||
virtual void OnTDExpandButtonClicked(BOOL bExpanded);
|
||||
virtual void OnTDHelp();
|
||||
virtual void OnTDHyperlinkClicked(LPCTSTR pszHref);
|
||||
virtual void OnTDNavigatePage();
|
||||
virtual BOOL OnTDRadioButtonClicked(int nRadioButtonID);
|
||||
virtual BOOL OnTDTimer(DWORD dwTickCount);
|
||||
virtual void OnTDVerificationCheckboxClicked(BOOL bChecked);
|
||||
virtual LRESULT TaskDialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
virtual LRESULT TaskDialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
CTaskDialog(const CTaskDialog&); // Disable copy construction
|
||||
CTaskDialog& operator = (const CTaskDialog&); // Disable assignment operator
|
||||
|
||||
std::vector<TASKDIALOG_BUTTON> m_vButtons;
|
||||
std::vector<TASKDIALOG_BUTTON> m_vRadioButtons;
|
||||
|
||||
std::vector< std::vector<WCHAR> > m_vButtonsText; // A vector of WCHAR vectors
|
||||
std::vector< std::vector<WCHAR> > m_vRadioButtonsText; // A vector of WCHAR vectors
|
||||
|
||||
std::vector<WCHAR> m_vWindowTitle;
|
||||
std::vector<WCHAR> m_vMainInstruction;
|
||||
std::vector<WCHAR> m_vContent;
|
||||
std::vector<WCHAR> m_vVerificationText;
|
||||
std::vector<WCHAR> m_vExpandedInformation;
|
||||
std::vector<WCHAR> m_vExpandedControlText;
|
||||
std::vector<WCHAR> m_vCollapsedControlText;
|
||||
std::vector<WCHAR> m_vFooter;
|
||||
|
||||
TASKDIALOGCONFIG m_tc;
|
||||
int m_SelectedButtonID;
|
||||
int m_SelectedRadioButtonID;
|
||||
BOOL m_VerificationCheckboxState;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
inline CTaskDialog::CTaskDialog() : m_SelectedButtonID(0), m_SelectedRadioButtonID(0), m_VerificationCheckboxState(FALSE)
|
||||
{
|
||||
ZeroMemory(&m_tc, sizeof(m_tc));
|
||||
m_tc.cbSize = sizeof(m_tc);
|
||||
m_tc.pfCallback = CTaskDialog::StaticTaskDialogProc;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::AddCommandControl(int nButtonID, LPCTSTR pszCaption)
|
||||
// Adds a command control or push button to the Task Dialog.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
|
||||
std::vector<WCHAR> vButtonText;
|
||||
StoreText(vButtonText, pszCaption);
|
||||
m_vButtonsText.push_back(vButtonText); // m_vButtonsText is a vector of vector<WCHAR>'s
|
||||
|
||||
TASKDIALOG_BUTTON tdb;
|
||||
tdb.nButtonID = nButtonID;
|
||||
tdb.pszButtonText = &m_vButtonsText.back().front();
|
||||
|
||||
m_vButtons.push_back(tdb);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::AddRadioButton(int nRadioButtonID, LPCTSTR pszCaption)
|
||||
// Adds a radio button to the Task Dialog.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
|
||||
std::vector<WCHAR> vRadioButtonText;
|
||||
StoreText(vRadioButtonText, pszCaption);
|
||||
m_vRadioButtonsText.push_back(vRadioButtonText); // m_vRadioButtonsText is a vector of vector<WCHAR>'s
|
||||
|
||||
TASKDIALOG_BUTTON tdb;
|
||||
tdb.nButtonID = nRadioButtonID;
|
||||
tdb.pszButtonText = &m_vRadioButtonsText.back().front();
|
||||
|
||||
m_vRadioButtons.push_back(tdb);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::AddRadioButtonGroup(int nIDRadioButtonsFirst, int nIDRadioButtonsLast)
|
||||
// Adds a range of radio buttons to the Task Dialog.
|
||||
// Assumes the resource ID of the button and it's string match
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
assert(nIDRadioButtonsFirst > 0);
|
||||
assert(nIDRadioButtonsLast > nIDRadioButtonsFirst);
|
||||
|
||||
TASKDIALOG_BUTTON tdb;
|
||||
for (int nID = nIDRadioButtonsFirst; nID <= nIDRadioButtonsLast; ++nID)
|
||||
{
|
||||
tdb.nButtonID = nID;
|
||||
tdb.pszButtonText = MAKEINTRESOURCEW(nID);
|
||||
m_vRadioButtons.push_back(tdb);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CTaskDialog::ClickButton(int nButtonID) const
|
||||
// Simulates the action of a button click in the Task Dialog.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_CLICK_BUTTON, (WPARAM)nButtonID, 0);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::ClickRadioButton(int nRadioButtonID) const
|
||||
// Simulates the action of a radio button click in the TaskDialog.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_CLICK_RADIO_BUTTON, (WPARAM)nRadioButtonID, 0);
|
||||
}
|
||||
|
||||
inline LRESULT CTaskDialog::DoModal(CWnd* pParent /* = NULL */)
|
||||
// Creates and displays the Task Dialog.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
|
||||
m_tc.cbSize = sizeof(m_tc);
|
||||
m_tc.pButtons = m_vButtons.empty()? NULL : &m_vButtons.front();
|
||||
m_tc.cButtons = m_vButtons.size();
|
||||
m_tc.pRadioButtons = m_vRadioButtons.empty()? NULL : &m_vRadioButtons.front();
|
||||
m_tc.cRadioButtons = m_vRadioButtons.size();
|
||||
m_tc.hwndParent = pParent? pParent->GetHwnd() : NULL;
|
||||
|
||||
// Ensure this thread has the TLS index set
|
||||
TLSData* pTLSData = GetApp()->SetTlsIndex();
|
||||
|
||||
// Store the CWnd pointer in thread local storage
|
||||
pTLSData->pCWnd = this;
|
||||
|
||||
// Declare a pointer to the TaskDialogIndirect function
|
||||
HMODULE hComCtl = ::LoadLibrary(_T("COMCTL32.DLL"));
|
||||
assert(hComCtl);
|
||||
typedef HRESULT WINAPI TASKDIALOGINDIRECT(const TASKDIALOGCONFIG*, int*, int*, BOOL*);
|
||||
TASKDIALOGINDIRECT* pTaskDialogIndirect = (TASKDIALOGINDIRECT*)::GetProcAddress(hComCtl, "TaskDialogIndirect");
|
||||
|
||||
// Call TaskDialogIndirect through our function pointer
|
||||
LRESULT lr = (*pTaskDialogIndirect)(&m_tc, &m_SelectedButtonID, &m_SelectedRadioButtonID, &m_VerificationCheckboxState);
|
||||
|
||||
FreeLibrary(hComCtl);
|
||||
return lr;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::ElevateButton(int nButtonID, BOOL bElevated)
|
||||
// Adds a shield icon to indicate that the button's action requires elevated privilages.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, (WPARAM)nButtonID, (LPARAM)bElevated);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::EnableButton(int nButtonID, BOOL bEnabled)
|
||||
// Enables or disables a push button in the TaskDialog.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_ENABLE_BUTTON, (WPARAM)nButtonID, (LPARAM)bEnabled);
|
||||
}
|
||||
inline void CTaskDialog::EnableRadioButton(int nRadioButtonID, BOOL bEnabled)
|
||||
// Enables or disables a radio button in the TaskDialog.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_ENABLE_RADIO_BUTTON, (WPARAM)nRadioButtonID, (LPARAM)bEnabled);
|
||||
}
|
||||
|
||||
inline TASKDIALOGCONFIG CTaskDialog::GetConfig() const
|
||||
// Returns the TASKDIALOGCONFIG structure for the Task Dialog.
|
||||
{
|
||||
return m_tc;
|
||||
}
|
||||
|
||||
inline TASKDIALOG_FLAGS CTaskDialog::GetOptions() const
|
||||
// Returns the Task Dialog's options. These are a combination of:
|
||||
// TDF_ENABLE_HYPERLINKS
|
||||
// TDF_USE_HICON_MAIN
|
||||
// TDF_USE_HICON_FOOTER
|
||||
// TDF_ALLOW_DIALOG_CANCELLATION
|
||||
// TDF_USE_COMMAND_LINKS
|
||||
// TDF_USE_COMMAND_LINKS_NO_ICON
|
||||
// TDF_EXPAND_FOOTER_AREA
|
||||
// TDF_EXPANDED_BY_DEFAULT
|
||||
// TDF_VERIFICATION_FLAG_CHECKED
|
||||
// TDF_SHOW_PROGRESS_BAR
|
||||
// TDF_SHOW_MARQUEE_PROGRESS_BAR
|
||||
// TDF_CALLBACK_TIMER
|
||||
// TDF_POSITION_RELATIVE_TO_WINDOW
|
||||
// TDF_RTL_LAYOUT
|
||||
// TDF_NO_DEFAULT_RADIO_BUTTON
|
||||
// TDF_CAN_BE_MINIMIZED
|
||||
{
|
||||
return m_tc.dwFlags;
|
||||
}
|
||||
|
||||
inline int CTaskDialog::GetSelectedButtonID() const
|
||||
// Returns the ID of the selected button.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
return m_SelectedButtonID;
|
||||
}
|
||||
|
||||
inline int CTaskDialog::GetSelectedRadioButtonID() const
|
||||
// Returns the ID of the selected radio button.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
return m_SelectedRadioButtonID;
|
||||
}
|
||||
|
||||
inline BOOL CTaskDialog::GetVerificationCheckboxState() const
|
||||
// Returns the state of the verification check box.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
return m_VerificationCheckboxState;
|
||||
}
|
||||
|
||||
inline BOOL CTaskDialog::IsSupported()
|
||||
// Returns true if TaskDialogs are supported on this system.
|
||||
{
|
||||
HMODULE hModule = ::LoadLibrary(_T("COMCTL32.DLL"));
|
||||
assert(hModule);
|
||||
|
||||
BOOL bResult = (BOOL)::GetProcAddress(hModule, "TaskDialogIndirect");
|
||||
|
||||
::FreeLibrary(hModule);
|
||||
return bResult;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::NavigateTo(CTaskDialog& TaskDialog) const
|
||||
// Replaces the information displayed by the task dialog.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
TASKDIALOGCONFIG tc = TaskDialog.GetConfig();
|
||||
SendMessage(TDM_NAVIGATE_PAGE, 0, (LPARAM)&tc);
|
||||
}
|
||||
|
||||
inline BOOL CTaskDialog::OnTDButtonClicked(int nButtonID)
|
||||
// Called when the user selects a button or command link.
|
||||
{
|
||||
UNREFERENCED_PARAMETER(nButtonID);
|
||||
|
||||
// return TRUE to prevent the task dialog from closing
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::OnTDConstructed()
|
||||
// Called when the task dialog is constructed, before it is displayed.
|
||||
{}
|
||||
|
||||
inline void CTaskDialog::OnTDCreated()
|
||||
// Called when the task dialog is displayed.
|
||||
{}
|
||||
|
||||
inline void CTaskDialog::OnTDDestroyed()
|
||||
// Called when the task dialog is destroyed.
|
||||
{
|
||||
}
|
||||
|
||||
inline void CTaskDialog::OnTDExpandButtonClicked(BOOL bExpanded)
|
||||
// Called when the expand button is clicked.
|
||||
{
|
||||
UNREFERENCED_PARAMETER(bExpanded);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::OnTDHelp()
|
||||
// Called when the user presses F1 on the keyboard.
|
||||
{}
|
||||
|
||||
inline void CTaskDialog::OnTDHyperlinkClicked(LPCTSTR pszHref)
|
||||
// Called when the user clicks on a hyperlink.
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pszHref);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::OnTDNavigatePage()
|
||||
// Called when a navigation has occurred.
|
||||
{}
|
||||
|
||||
inline BOOL CTaskDialog::OnTDRadioButtonClicked(int nRadioButtonID)
|
||||
// Called when the user selects a radio button.
|
||||
{
|
||||
UNREFERENCED_PARAMETER(nRadioButtonID);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
inline BOOL CTaskDialog::OnTDTimer(DWORD dwTickCount)
|
||||
// Called every 200 milliseconds (aproximately) when the TDF_CALLBACK_TIMER flag is set.
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dwTickCount);
|
||||
|
||||
// return TRUE to reset the tick count
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::OnTDVerificationCheckboxClicked(BOOL bChecked)
|
||||
// Called when the user clicks the Task Dialog verification check box.
|
||||
{
|
||||
UNREFERENCED_PARAMETER(bChecked);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::RemoveAllButtons()
|
||||
// Removes all push buttons from the task dialog.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
m_vButtons.clear();
|
||||
m_vButtonsText.clear();
|
||||
}
|
||||
|
||||
inline void CTaskDialog::RemoveAllRadioButtons()
|
||||
// Removes all radio buttons from the task dialog.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
m_vRadioButtons.clear();
|
||||
m_vRadioButtonsText.clear();
|
||||
}
|
||||
|
||||
inline void CTaskDialog::Reset()
|
||||
// Returns the dialog to its default state.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
|
||||
RemoveAllButtons();
|
||||
RemoveAllRadioButtons();
|
||||
ZeroMemory(&m_tc, sizeof(m_tc));
|
||||
m_tc.cbSize = sizeof(m_tc);
|
||||
m_tc.pfCallback = CTaskDialog::StaticTaskDialogProc;
|
||||
|
||||
m_SelectedButtonID = 0;
|
||||
m_SelectedRadioButtonID = 0;
|
||||
m_VerificationCheckboxState = FALSE;
|
||||
|
||||
m_vWindowTitle.clear();
|
||||
m_vMainInstruction.clear();
|
||||
m_vContent.clear();
|
||||
m_vVerificationText.clear();
|
||||
m_vExpandedInformation.clear();
|
||||
m_vExpandedControlText.clear();
|
||||
m_vCollapsedControlText.clear();
|
||||
m_vFooter.clear();
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)
|
||||
// The dwCommonButtons parameter can be a combination of:
|
||||
// TDCBF_OK_BUTTON OK button
|
||||
// TDCBF_YES_BUTTON Yes button
|
||||
// TDCBF_NO_BUTTON No button
|
||||
// TDCBF_CANCEL_BUTTON Cancel button
|
||||
// TDCBF_RETRY_BUTTON Retry button
|
||||
// TDCBF_CLOSE_BUTTON Close button
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
m_tc.dwCommonButtons = dwCommonButtons;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetContent(LPCTSTR pszContent)
|
||||
// Sets the task dialog's primary content.
|
||||
{
|
||||
StoreText(m_vContent, pszContent);
|
||||
m_tc.pszContent = &m_vContent.front();
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_SET_ELEMENT_TEXT, (WPARAM)TDE_CONTENT, (LPARAM)(LPCWSTR)T2W(pszContent));
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetDefaultButton(int nButtonID)
|
||||
// Sets the task dialog's default button.
|
||||
// Can be either a button ID or one of the common buttons
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
m_tc.nDefaultButton = nButtonID;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetDefaultRadioButton(int nRadioButtonID)
|
||||
// Sets the default radio button.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
m_tc.nDefaultRadioButton = nRadioButtonID;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetDialogWidth(UINT nWidth /*= 0*/)
|
||||
// The width of the task dialog's client area. If 0, the
|
||||
// task dialog manager will calculate the ideal width.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
m_tc.cxWidth = nWidth;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetExpansionArea(LPCTSTR pszExpandedInfo, LPCTSTR pszExpandedLabel /* = _T("")*/, LPCTSTR pszCollapsedLabel /* = _T("")*/)
|
||||
// Sets the text in the expandable area of the Task Dialog.
|
||||
{
|
||||
StoreText(m_vExpandedInformation, pszExpandedInfo);
|
||||
m_tc.pszExpandedInformation = &m_vExpandedInformation.front();
|
||||
|
||||
StoreText(m_vExpandedControlText, pszExpandedLabel);
|
||||
m_tc.pszExpandedControlText = &m_vExpandedControlText.front();
|
||||
|
||||
StoreText(m_vCollapsedControlText, pszCollapsedLabel);
|
||||
m_tc.pszCollapsedControlText = &m_vCollapsedControlText.front();
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_SET_ELEMENT_TEXT, (WPARAM)TDE_EXPANDED_INFORMATION, (LPARAM)(LPCWSTR)T2W(pszExpandedInfo));
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetFooterIcon(HICON hFooterIcon)
|
||||
// Sets the icon that will be displayed in the Task Dialog's footer.
|
||||
{
|
||||
m_tc.hFooterIcon = hFooterIcon;
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_UPDATE_ICON, (WPARAM)TDIE_ICON_FOOTER, (LPARAM)hFooterIcon);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetFooterIcon(LPCTSTR lpszFooterIcon)
|
||||
// Sets the icon that will be displayed in the Task Dialog's footer.
|
||||
// Possible icons:
|
||||
// TD_ERROR_ICON A stop-sign icon appears in the task dialog.
|
||||
// TD_WARNING_ICON An exclamation-point icon appears in the task dialog.
|
||||
// TD_INFORMATION_ICON An icon consisting of a lowercase letter i in a circle appears in the task dialog.
|
||||
// TD_SHIELD_ICON A shield icon appears in the task dialog.
|
||||
// or a value passed via MAKEINTRESOURCE
|
||||
{
|
||||
m_tc.pszFooterIcon = (LPCWSTR)lpszFooterIcon;
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_UPDATE_ICON, (WPARAM)TDIE_ICON_FOOTER, (LPARAM)lpszFooterIcon);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetFooterText(LPCTSTR pszFooter)
|
||||
// Sets the text that will be displayed in the Task Dialog's footer.
|
||||
{
|
||||
StoreText(m_vFooter, pszFooter);
|
||||
m_tc.pszFooter = &m_vFooter.front();
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_SET_ELEMENT_TEXT, (WPARAM)TDE_FOOTER, (LPARAM)(LPCWSTR)T2W(pszFooter));
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetMainIcon(HICON hMainIcon)
|
||||
// Sets Task Dialog's main icon.
|
||||
{
|
||||
m_tc.hMainIcon = hMainIcon;
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_UPDATE_ICON, (WPARAM)TDIE_ICON_MAIN, (LPARAM)hMainIcon);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetMainIcon(LPCTSTR lpszMainIcon)
|
||||
// Sets Task Dialog's main icon.
|
||||
// Possible icons:
|
||||
// TD_ERROR_ICON A stop-sign icon appears in the task dialog.
|
||||
// TD_WARNING_ICON An exclamation-point icon appears in the task dialog.
|
||||
// TD_INFORMATION_ICON An icon consisting of a lowercase letter i in a circle appears in the task dialog.
|
||||
// TD_SHIELD_ICON A shield icon appears in the task dialog.
|
||||
// or a value passed via MAKEINTRESOURCE
|
||||
//
|
||||
// Note: Some values of main icon will also generate a MessageBeep when the TaskDialog is created.
|
||||
{
|
||||
m_tc.pszMainIcon = (LPCWSTR)lpszMainIcon;
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_UPDATE_ICON, (WPARAM)TDIE_ICON_MAIN, (LPARAM)lpszMainIcon);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetMainInstruction(LPCTSTR pszMainInstruction)
|
||||
// Sets the Task Dialog's main instruction text.
|
||||
{
|
||||
StoreText(m_vMainInstruction, pszMainInstruction);
|
||||
m_tc.pszMainInstruction = &m_vMainInstruction.front();
|
||||
|
||||
if (IsWindow())
|
||||
SendMessage(TDM_SET_ELEMENT_TEXT, (WPARAM)TDE_FOOTER, (LPARAM)(LPCWSTR)T2W(pszMainInstruction));
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetOptions(TASKDIALOG_FLAGS dwFlags)
|
||||
// Sets the Task Dialog's options. These are a combination of:
|
||||
// TDF_ENABLE_HYPERLINKS
|
||||
// TDF_USE_HICON_MAIN
|
||||
// TDF_USE_HICON_FOOTER
|
||||
// TDF_ALLOW_DIALOG_CANCELLATION
|
||||
// TDF_USE_COMMAND_LINKS
|
||||
// TDF_USE_COMMAND_LINKS_NO_ICON
|
||||
// TDF_EXPAND_FOOTER_AREA
|
||||
// TDF_EXPANDED_BY_DEFAULT
|
||||
// TDF_VERIFICATION_FLAG_CHECKED
|
||||
// TDF_SHOW_PROGRESS_BAR
|
||||
// TDF_SHOW_MARQUEE_PROGRESS_BAR
|
||||
// TDF_CALLBACK_TIMER
|
||||
// TDF_POSITION_RELATIVE_TO_WINDOW
|
||||
// TDF_RTL_LAYOUT
|
||||
// TDF_NO_DEFAULT_RADIO_BUTTON
|
||||
// TDF_CAN_BE_MINIMIZED
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
m_tc.dwFlags = dwFlags;
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetProgressBarMarquee(BOOL bEnabled /* = TRUE*/, int nMarqueeSpeed /* = 0*/)
|
||||
// Starts and stops the marquee display of the progress bar, and sets the speed of the marquee.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_SET_PROGRESS_BAR_MARQUEE, (WPARAM)bEnabled, (LPARAM)nMarqueeSpeed);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetProgressBarPosition(int nProgressPos)
|
||||
// Sets the current position for a progress bar.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_SET_PROGRESS_BAR_POS, (WPARAM)nProgressPos, 0);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetProgressBarRange(int nMinRange, int nMaxRange)
|
||||
// Sets the minimum and maximum values for the hosted progress bar.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange));
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetProgressBarState(int nNewState /* = PBST_NORMAL*/)
|
||||
// Sets the current state of the progress bar. Possible states are:
|
||||
// PBST_NORMAL
|
||||
// PBST_PAUSE
|
||||
// PBST_ERROR
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_SET_PROGRESS_BAR_STATE, (WPARAM)nNewState, 0);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetVerificationCheckbox(BOOL bChecked)
|
||||
// Simulates a click on the verification checkbox of the Task Dialog, if it exists.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_CLICK_VERIFICATION, (WPARAM)bChecked, (LPARAM)bChecked);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetVerificationCheckboxText(LPCTSTR pszVerificationText)
|
||||
// Sets the text for the verification check box.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
StoreText(m_vVerificationText, pszVerificationText);
|
||||
m_tc.pszVerificationText = &m_vVerificationText.front();
|
||||
}
|
||||
|
||||
inline void CTaskDialog::SetWindowTitle(LPCTSTR pszWindowTitle)
|
||||
// Sets the Task Dialog's window title.
|
||||
{
|
||||
assert (m_hWnd == NULL);
|
||||
StoreText(m_vWindowTitle, pszWindowTitle);
|
||||
m_tc.pszWindowTitle = &m_vWindowTitle.front();
|
||||
}
|
||||
|
||||
inline HRESULT CALLBACK CTaskDialog::StaticTaskDialogProc(HWND hWnd, UINT uNotification, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData)
|
||||
// TaskDialogs direct their messages here.
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dwRefData);
|
||||
|
||||
assert( GetApp() );
|
||||
|
||||
try
|
||||
{
|
||||
CTaskDialog* t = (CTaskDialog*)GetApp()->GetCWndFromMap(hWnd);
|
||||
if (0 == t)
|
||||
{
|
||||
// The CTaskDialog pointer wasn't found in the map, so add it now
|
||||
|
||||
// Retrieve the pointer to the TLS Data
|
||||
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||||
if (NULL == pTLSData)
|
||||
throw CWinException(_T("Unable to get TLS"));
|
||||
|
||||
// Retrieve pointer to CTaskDialog object from Thread Local Storage TLS
|
||||
t = (CTaskDialog*)(pTLSData->pCWnd);
|
||||
if (NULL == t)
|
||||
throw CWinException(_T("Failed to route message"));
|
||||
|
||||
pTLSData->pCWnd = NULL;
|
||||
|
||||
// Store the CTaskDialog pointer in the HWND map
|
||||
t->m_hWnd = hWnd;
|
||||
t->AddToMap();
|
||||
}
|
||||
|
||||
return t->TaskDialogProc(uNotification, wParam, lParam);
|
||||
}
|
||||
|
||||
catch (const CWinException &e)
|
||||
{
|
||||
// Most CWinExceptions will end up here unless caught earlier.
|
||||
e.what();
|
||||
}
|
||||
|
||||
return 0L;
|
||||
|
||||
} // LRESULT CALLBACK StaticTaskDialogProc(...)
|
||||
|
||||
inline void CTaskDialog::StoreText(std::vector<WCHAR>& vWChar, LPCTSTR pFromTChar)
|
||||
{
|
||||
// Stores a TChar string in a WCHAR vector
|
||||
|
||||
std::vector<TCHAR> vTChar;
|
||||
|
||||
if (IS_INTRESOURCE(pFromTChar)) // support MAKEINTRESOURCE
|
||||
{
|
||||
tString ts = LoadString((UINT)pFromTChar);
|
||||
int len = pFromTChar? ts.length() + 1 : 1;
|
||||
vTChar.assign(len, _T('\0'));
|
||||
vWChar.assign(len, _T('\0'));
|
||||
if (pFromTChar)
|
||||
lstrcpy( &vTChar.front(), ts.c_str());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = lstrlen(pFromTChar) +1;
|
||||
vTChar.assign(len, _T('\0'));
|
||||
vWChar.assign(len, _T('\0'));
|
||||
lstrcpy( &vTChar.front(), pFromTChar);
|
||||
}
|
||||
|
||||
lstrcpyW(&vWChar.front(), T2W(&vTChar.front()) );
|
||||
}
|
||||
|
||||
inline LRESULT CTaskDialog::TaskDialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
// Handles the Task Dialog's notificaions.
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case TDN_BUTTON_CLICKED:
|
||||
return OnTDButtonClicked((int)wParam);
|
||||
|
||||
case TDN_CREATED:
|
||||
OnTDCreated();
|
||||
break;
|
||||
case TDN_DESTROYED:
|
||||
Cleanup(); // Prepare this CWnd to be reused.
|
||||
OnTDDestroyed();
|
||||
break;
|
||||
case TDN_DIALOG_CONSTRUCTED:
|
||||
OnTDConstructed();
|
||||
break;
|
||||
case TDN_EXPANDO_BUTTON_CLICKED:
|
||||
OnTDExpandButtonClicked((BOOL)wParam);
|
||||
break;
|
||||
case TDN_HELP:
|
||||
OnTDHelp();
|
||||
break;
|
||||
case TDN_HYPERLINK_CLICKED:
|
||||
OnTDHyperlinkClicked(W2T((LPCWSTR)lParam));
|
||||
break;
|
||||
case TDN_NAVIGATED:
|
||||
OnTDNavigatePage();
|
||||
break;
|
||||
case TDN_RADIO_BUTTON_CLICKED:
|
||||
OnTDRadioButtonClicked((int)wParam);
|
||||
break;
|
||||
case TDN_TIMER:
|
||||
return OnTDTimer((DWORD)wParam);
|
||||
|
||||
case TDN_VERIFICATION_CLICKED:
|
||||
OnTDVerificationCheckboxClicked((BOOL)wParam);
|
||||
break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline LRESULT CTaskDialog::TaskDialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Override this function in your class derrived from CDialog if you wish to handle messages
|
||||
// A typical function might look like this:
|
||||
|
||||
// switch (uMsg)
|
||||
// {
|
||||
// case MESSAGE1: // Some Windows API message
|
||||
// OnMessage1(); // A user defined function
|
||||
// break; // Also do default processing
|
||||
// case MESSAGE2:
|
||||
// OnMessage2();
|
||||
// return x; // Don't do default processing, but instead return
|
||||
// // a value recommended by the Windows API documentation
|
||||
// }
|
||||
|
||||
// Always pass unhandled messages on to TaskDialogProcDefault
|
||||
return TaskDialogProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
inline void CTaskDialog::UpdateElementText(TASKDIALOG_ELEMENTS eElement, LPCTSTR pszNewText)
|
||||
// Updates a text element on the Task Dialog.
|
||||
{
|
||||
assert(m_hWnd);
|
||||
SendMessage(TDM_UPDATE_ELEMENT_TEXT, (WPARAM)eElement, (LPARAM)(LPCWSTR)T2W(pszNewText));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // _WIN32XX_TASKDIALOG_H_
|
241
mmc_updater/depends/win32cpp/thread.h
Normal file
241
mmc_updater/depends/win32cpp/thread.h
Normal file
@ -0,0 +1,241 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// The CThread class simplifies the use of threads with Win32++.
|
||||
// To use threads in your Win32++ application, inherit a class from
|
||||
// CThread, and override InitInstance. When your class is instanciated,
|
||||
// a new thread is started, and the InitInstance function is called to
|
||||
// run in the new thread.
|
||||
|
||||
// If your thread is used to run one or more windows, InitInstance should
|
||||
// return TRUE, causing the MessageLoop function to be called. If your
|
||||
// thread doesn't require a MessageLoop, it should return FALSE. Threads
|
||||
// which don't run a message loop as sometimes referred to as "worker" threads.
|
||||
|
||||
// Note: It is your job to end the thread before CThread ends!
|
||||
// To end a thread with a message loop, use PostQuitMessage on the thread.
|
||||
// To end a thread without a message loop, set an event, and end the thread
|
||||
// when the event is received.
|
||||
|
||||
// Hint: It is never a good idea to use things like TerminateThread or ExitThread to
|
||||
// end your thread. These represent poor programming techniques, and are likely
|
||||
// to leak memory and resources.
|
||||
|
||||
// More Hints for thread programming:
|
||||
// 1) Avoid using SendMessage between threads, as this will cause one thread to wait for
|
||||
// the other to respond. Use PostMessage between threads to avoid this problem.
|
||||
// 2) Access to variables and resources shared between threads need to be made thread safe.
|
||||
// Having one thread modify a resouce or variable while another thread is accessing it is
|
||||
// a recipe for disaster.
|
||||
// 3) Thread Local Storage (TLS) can be used to replace global variables to make them thread
|
||||
// safe. With TLS, each thread gets its own copy of the variable.
|
||||
// 4) Critical Sections can be used to make shared resources thread safe.
|
||||
// 5) Window messages (including user defined messages) can be posted between GUI threads to
|
||||
// communicate information between them.
|
||||
// 6) Events (created by CreateEvent) can be used to comunicate information between threads
|
||||
// (both GUI and worker threads).
|
||||
// 7) Avoid using sleep to synchronise threads. Generally speaking, the various wait
|
||||
// functions (e.g. WaitForSingleObject) will be better for this.
|
||||
|
||||
// About Threads:
|
||||
// Each program that executes has a "process" allocated to it. A process has one or more
|
||||
// threads. Threads run independantly of each other. It is the job of the operating system
|
||||
// to manage the running of the threads, and do the task switching between threads as required.
|
||||
// Systems with multiple CPUs will be able to run as many threads simultaneously as there are
|
||||
// CPUs.
|
||||
|
||||
// Threads behave like a program within a program. When the main thread starts, the application
|
||||
// runs the WinMain function and ends when WinMain ends. When another thread starts, it too
|
||||
// will run the function provided to it, and end when that function ends.
|
||||
|
||||
|
||||
#ifndef _WIN32XX_WINTHREAD_H_
|
||||
#define _WIN32XX_WINTHREAD_H_
|
||||
|
||||
|
||||
#include <process.h>
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
//////////////////////////////////////
|
||||
// Declaration of the CThread class
|
||||
//
|
||||
class CThread
|
||||
{
|
||||
public:
|
||||
CThread();
|
||||
CThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag);
|
||||
virtual ~CThread();
|
||||
|
||||
// Overridables
|
||||
virtual BOOL InitInstance();
|
||||
virtual int MessageLoop();
|
||||
|
||||
// Operations
|
||||
HANDLE GetThread() const;
|
||||
int GetThreadID() const;
|
||||
int GetThreadPriority() const;
|
||||
DWORD ResumeThread() const;
|
||||
BOOL SetThreadPriority(int nPriority) const;
|
||||
DWORD SuspendThread() const;
|
||||
|
||||
private:
|
||||
CThread(const CThread&); // Disable copy construction
|
||||
CThread& operator = (const CThread&); // Disable assignment operator
|
||||
void CreateThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag);
|
||||
static UINT WINAPI StaticThreadCallback(LPVOID pCThread);
|
||||
|
||||
HANDLE m_hThread; // Handle of this thread
|
||||
UINT m_nThreadID; // ID of this thread
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
///////////////////////////////////////
|
||||
// Definitions for the CThread class
|
||||
//
|
||||
inline CThread::CThread() : m_hThread(0), m_nThreadID(0)
|
||||
{
|
||||
CreateThread(0, 0, CREATE_SUSPENDED);
|
||||
}
|
||||
|
||||
inline CThread::CThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag)
|
||||
: m_hThread(0), m_nThreadID(0)
|
||||
|
||||
{
|
||||
// Valid argument values:
|
||||
// pSecurityAttributes Either a pointer to SECURITY_ATTRIBUTES or 0
|
||||
// stack_size Either the stack size or 0
|
||||
// initflag Either CREATE_SUSPENDED or 0
|
||||
|
||||
CreateThread(pSecurityAttributes, stack_size, initflag);
|
||||
}
|
||||
|
||||
inline CThread::~CThread()
|
||||
{
|
||||
// A thread's state is set to signalled when the thread terminates.
|
||||
// If your thread is still running at this point, you have a bug.
|
||||
if (0 != WaitForSingleObject(m_hThread, 0))
|
||||
TRACE(_T("*** Error *** Ending CThread before ending its thread\n"));
|
||||
|
||||
// Close the thread's handle
|
||||
::CloseHandle(m_hThread);
|
||||
}
|
||||
|
||||
inline void CThread::CreateThread(LPSECURITY_ATTRIBUTES pSecurityAttributes, unsigned stack_size, unsigned initflag)
|
||||
{
|
||||
// NOTE: By default, the thread is created in the default state.
|
||||
m_hThread = (HANDLE)_beginthreadex(pSecurityAttributes, stack_size, CThread::StaticThreadCallback, (LPVOID) this, initflag, &m_nThreadID);
|
||||
|
||||
if (0 == m_hThread)
|
||||
throw CWinException(_T("Failed to create thread"));
|
||||
}
|
||||
|
||||
inline HANDLE CThread::GetThread() const
|
||||
{
|
||||
assert(m_hThread);
|
||||
return m_hThread;
|
||||
}
|
||||
|
||||
inline int CThread::GetThreadID() const
|
||||
{
|
||||
assert(m_hThread);
|
||||
return m_nThreadID;
|
||||
}
|
||||
|
||||
inline int CThread::GetThreadPriority() const
|
||||
{
|
||||
assert(m_hThread);
|
||||
return ::GetThreadPriority(m_hThread);
|
||||
}
|
||||
|
||||
inline BOOL CThread::InitInstance()
|
||||
{
|
||||
// Override this function to perform tasks when the thread starts.
|
||||
|
||||
// return TRUE to run a message loop, otherwise return FALSE.
|
||||
// A thread with a window must run a message loop.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline int CThread::MessageLoop()
|
||||
{
|
||||
// Override this function if your thread needs a different message loop
|
||||
return GetApp()->MessageLoop();
|
||||
}
|
||||
|
||||
inline DWORD CThread::ResumeThread() const
|
||||
{
|
||||
assert(m_hThread);
|
||||
return ::ResumeThread(m_hThread);
|
||||
}
|
||||
|
||||
inline DWORD CThread::SuspendThread() const
|
||||
{
|
||||
assert(m_hThread);
|
||||
return ::SuspendThread(m_hThread);
|
||||
}
|
||||
|
||||
inline BOOL CThread::SetThreadPriority(int nPriority) const
|
||||
{
|
||||
assert(m_hThread);
|
||||
return ::SetThreadPriority(m_hThread, nPriority);
|
||||
}
|
||||
|
||||
inline UINT WINAPI CThread::StaticThreadCallback(LPVOID pCThread)
|
||||
// When the thread starts, it runs this function.
|
||||
{
|
||||
// Get the pointer for this CMyThread object
|
||||
CThread* pThread = (CThread*)pCThread;
|
||||
|
||||
if (pThread->InitInstance())
|
||||
return pThread->MessageLoop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // #define _WIN32XX_WINTHREAD_H_
|
||||
|
1361
mmc_updater/depends/win32cpp/toolbar.h
Normal file
1361
mmc_updater/depends/win32cpp/toolbar.h
Normal file
File diff suppressed because it is too large
Load Diff
624
mmc_updater/depends/win32cpp/treeview.h
Normal file
624
mmc_updater/depends/win32cpp/treeview.h
Normal file
@ -0,0 +1,624 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef _WIN32XX_TREEVIEW_H_
|
||||
#define _WIN32XX_TREEVIEW_H_
|
||||
|
||||
#include "wincore.h"
|
||||
#include "commctrl.h"
|
||||
|
||||
// Disable macros from Windowsx.h
|
||||
#undef GetNextSibling
|
||||
#undef GetPrevSibling
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
class CTreeView : public CWnd
|
||||
{
|
||||
public:
|
||||
CTreeView() {}
|
||||
virtual ~CTreeView() {}
|
||||
virtual void PreRegisterClass(WNDCLASS &wc);
|
||||
|
||||
// Attributes
|
||||
COLORREF GetBkColor() const;
|
||||
HTREEITEM GetChild(HTREEITEM hItem) const;
|
||||
UINT GetCount() const;
|
||||
HTREEITEM GetDropHiLightItem() const;
|
||||
HWND GetEditControl() const;
|
||||
HTREEITEM GetFirstVisible() const;
|
||||
HIMAGELIST GetImageList(int iImageType) const;
|
||||
UINT GetIndent() const;
|
||||
COLORREF GetInsertMarkColor() const;
|
||||
BOOL GetItem(TVITEM& Item) const;
|
||||
DWORD_PTR GetItemData(HTREEITEM hItem) const;
|
||||
int GetItemHeight() const;
|
||||
BOOL GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage ) const;
|
||||
BOOL GetItemRect(HTREEITEM hItem, CRect& rc, BOOL bTextOnly) const;
|
||||
tString GetItemText(HTREEITEM hItem, UINT nTextMax /* = 260 */) const;
|
||||
HTREEITEM GetLastVisible() const;
|
||||
HTREEITEM GetNextItem(HTREEITEM hItem, UINT nCode) const;
|
||||
HTREEITEM GetNextSibling(HTREEITEM hItem) const;
|
||||
HTREEITEM GetNextVisible(HTREEITEM hItem) const;
|
||||
HTREEITEM GetParentItem(HTREEITEM hItem) const;
|
||||
HTREEITEM GetPrevSibling(HTREEITEM hItem) const;
|
||||
HTREEITEM GetPrevVisible(HTREEITEM hItem) const;
|
||||
HTREEITEM GetRootItem() const;
|
||||
int GetScrollTime() const;
|
||||
HTREEITEM GetSelection() const;
|
||||
COLORREF GetTextColor() const;
|
||||
HWND GetToolTips() const;
|
||||
UINT GetVisibleCount() const;
|
||||
BOOL ItemHasChildren(HTREEITEM hItem) const;
|
||||
COLORREF SetBkColor(COLORREF clrBk) const;
|
||||
HIMAGELIST SetImageList(HIMAGELIST himl, int nType) const;
|
||||
void SetIndent(int indent) const;
|
||||
BOOL SetInsertMark(HTREEITEM hItem, BOOL fAfter = TRUE) const;
|
||||
COLORREF SetInsertMarkColor(COLORREF clrInsertMark) const;
|
||||
BOOL SetItem(TVITEM& Item) const;
|
||||
BOOL SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR szText, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) const;
|
||||
BOOL SetItemData(HTREEITEM hItem, DWORD_PTR dwData) const;
|
||||
int SetItemHeight(SHORT cyItem) const;
|
||||
BOOL SetItemImage(HTREEITEM hItem, int nImage, int nSelectedImage) const;
|
||||
BOOL SetItemText(HTREEITEM hItem, LPCTSTR szText) const;
|
||||
UINT SetScrollTime(UINT uScrollTime) const;
|
||||
COLORREF SetTextColor(COLORREF clrText) const;
|
||||
HWND SetToolTips(HWND hwndTooltip) const;
|
||||
|
||||
// Operations
|
||||
HIMAGELIST CreateDragImage(HTREEITEM hItem) const;
|
||||
BOOL DeleteAllItems() const;
|
||||
BOOL DeleteItem(HTREEITEM hItem) const;
|
||||
HWND EditLabel(HTREEITEM hItem) const;
|
||||
BOOL EndEditLabelNow(BOOL fCancel) const;
|
||||
BOOL EnsureVisible(HTREEITEM hItem) const;
|
||||
BOOL Expand(HTREEITEM hItem, UINT nCode) const;
|
||||
HTREEITEM HitTest(TVHITTESTINFO& ht) const;
|
||||
HTREEITEM InsertItem(TVINSERTSTRUCT& tvIS) const;
|
||||
BOOL Select(HTREEITEM hitem, UINT flag) const;
|
||||
BOOL SelectDropTarget(HTREEITEM hItem) const;
|
||||
BOOL SelectItem(HTREEITEM hItem) const;
|
||||
BOOL SelectSetFirstVisible(HTREEITEM hItem) const;
|
||||
BOOL SortChildren(HTREEITEM hItem, BOOL fRecurse) const;
|
||||
BOOL SortChildrenCB(TVSORTCB& sort, BOOL fRecurse) const;
|
||||
|
||||
private:
|
||||
CTreeView(const CTreeView&); // Disable copy construction
|
||||
CTreeView& operator = (const CTreeView&); // Disable assignment operator
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
inline void CTreeView::PreRegisterClass(WNDCLASS &wc)
|
||||
{
|
||||
// Set the Window Class
|
||||
wc.lpszClassName = WC_TREEVIEW;
|
||||
}
|
||||
|
||||
// Attributes
|
||||
inline COLORREF CTreeView::GetBkColor() const
|
||||
// Retrieves the current background color of the control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetBkColor( m_hWnd );
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetChild(HTREEITEM hItem) const
|
||||
// Retrieves the first child item of the specified tree-view item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetChild(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline UINT CTreeView::GetCount() const
|
||||
// Retrieves a count of the items in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetCount( m_hWnd );
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetDropHiLightItem() const
|
||||
// Retrieves the tree-view item that is the target of a drag-and-drop operation.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetDropHilight(m_hWnd);
|
||||
}
|
||||
|
||||
inline HWND CTreeView::GetEditControl() const
|
||||
// Retrieves the handle to the edit control being used to edit a tree-view item's text.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetEditControl( m_hWnd );
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetFirstVisible() const
|
||||
// Retrieves the first visible item in a tree-view control window.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetFirstVisible(m_hWnd);
|
||||
}
|
||||
|
||||
inline HIMAGELIST CTreeView::GetImageList(int iImageType) const
|
||||
// Retrieves the handle to the normal or state image list associated with a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetImageList( m_hWnd, iImageType );
|
||||
}
|
||||
|
||||
inline UINT CTreeView::GetIndent() const
|
||||
// Retrieves the amount, in pixels, that child items are indented relative to their parent items.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetIndent( m_hWnd );
|
||||
}
|
||||
|
||||
inline COLORREF CTreeView::GetInsertMarkColor() const
|
||||
// Retrieves the color used to draw the insertion mark for the tree view.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetInsertMarkColor( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::GetItem(TVITEM& Item) const
|
||||
// Retrieves some or all of a tree-view item's attributes.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetItem( m_hWnd, &Item );
|
||||
}
|
||||
|
||||
inline DWORD_PTR CTreeView::GetItemData(HTREEITEM hItem) const
|
||||
// Retrieves a tree-view item's application data.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
TVITEM tvi = {0};
|
||||
tvi.mask = TVIF_PARAM;
|
||||
tvi.hItem = hItem;
|
||||
TreeView_GetItem( m_hWnd, &tvi );
|
||||
return tvi.lParam;
|
||||
}
|
||||
|
||||
inline int CTreeView::GetItemHeight() const
|
||||
// Retrieves the current height of the tree-view item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetItemHeight( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage ) const
|
||||
// Retrieves the index of the tree-view item's image and selected image.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
TVITEM tvi = {0};
|
||||
tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
||||
tvi.hItem = hItem;
|
||||
BOOL bResult = TreeView_GetItem( m_hWnd, &tvi );
|
||||
nImage = tvi.iImage;
|
||||
nSelectedImage = tvi.iSelectedImage;
|
||||
return bResult;
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::GetItemRect(HTREEITEM hItem, CRect& rc, BOOL bTextOnly) const
|
||||
// Retrieves the bounding rectangle for a tree-view item and indicates whether the item is visible.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetItemRect( m_hWnd, hItem, &rc, bTextOnly );
|
||||
}
|
||||
|
||||
inline tString CTreeView::GetItemText(HTREEITEM hItem, UINT nTextMax /* = 260 */) const
|
||||
// Retrieves the text for a tree-view item.
|
||||
// Note: Although the tree-view control allows any length string to be stored
|
||||
// as item text, only the first 260 characters are displayed.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
tString t;
|
||||
if (nTextMax > 0)
|
||||
{
|
||||
TVITEM tvi = {0};
|
||||
tvi.hItem = hItem;
|
||||
tvi.mask = TVIF_TEXT;
|
||||
tvi.cchTextMax = nTextMax;
|
||||
std::vector<TCHAR> vTChar(nTextMax +1, _T('\0'));
|
||||
TCHAR* pTCharArray = &vTChar.front();
|
||||
tvi.pszText = pTCharArray;
|
||||
::SendMessage(m_hWnd, TVM_GETITEM, 0L, (LPARAM)&tvi);
|
||||
t = tvi.pszText;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetLastVisible() const
|
||||
// Retrieves the last expanded item in a tree-view control.
|
||||
// This does not retrieve the last item visible in the tree-view window.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetLastVisible(m_hWnd);
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetNextItem(HTREEITEM hItem, UINT nCode) const
|
||||
// Retrieves the tree-view item that bears the specified relationship to a specified item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetNextItem( m_hWnd, hItem, nCode);
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetNextSibling(HTREEITEM hItem) const
|
||||
// Retrieves the next sibling item of a specified item in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetNextSibling(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetNextVisible(HTREEITEM hItem) const
|
||||
// Retrieves the next visible item that follows a specified item in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetNextVisible(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetParentItem(HTREEITEM hItem) const
|
||||
// Retrieves the parent item of the specified tree-view item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetParent(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetPrevSibling(HTREEITEM hItem) const
|
||||
// Retrieves the previous sibling item of a specified item in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetPrevSibling(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetPrevVisible(HTREEITEM hItem) const
|
||||
// Retrieves the first visible item that precedes a specified item in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetPrevSibling(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetRootItem() const
|
||||
// Retrieves the topmost or very first item of the tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetRoot(m_hWnd);
|
||||
}
|
||||
|
||||
inline int CTreeView::GetScrollTime() const
|
||||
// Retrieves the maximum scroll time for the tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetScrollTime( m_hWnd );
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::GetSelection() const
|
||||
// Retrieves the currently selected item in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetSelection(m_hWnd);
|
||||
}
|
||||
|
||||
inline COLORREF CTreeView::GetTextColor() const
|
||||
// Retrieves the current text color of the control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetTextColor( m_hWnd );
|
||||
}
|
||||
|
||||
inline HWND CTreeView::GetToolTips() const
|
||||
// Retrieves the handle to the child ToolTip control used by a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetToolTips( m_hWnd );
|
||||
}
|
||||
|
||||
inline UINT CTreeView::GetVisibleCount() const
|
||||
// Obtains the number of items that can be fully visible in the client window of a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_GetVisibleCount( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::ItemHasChildren(HTREEITEM hItem) const
|
||||
// Returns true of the tree-view item has one or more children
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
if (TreeView_GetChild( m_hWnd, hItem ))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline COLORREF CTreeView::SetBkColor(COLORREF clrBk) const
|
||||
// Sets the background color of the control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetBkColor( m_hWnd, clrBk );
|
||||
}
|
||||
|
||||
inline HIMAGELIST CTreeView::SetImageList(HIMAGELIST himl, int nType) const
|
||||
// Sets the normal or state image list for a tree-view control
|
||||
// and redraws the control using the new images.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetImageList( m_hWnd, himl, nType );
|
||||
}
|
||||
|
||||
inline void CTreeView::SetIndent(int indent) const
|
||||
// Sets the width of indentation for a tree-view control
|
||||
// and redraws the control to reflect the new width.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
TreeView_SetIndent( m_hWnd, indent );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter/* = TRUE*/) const
|
||||
// Sets the insertion mark in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetInsertMark( m_hWnd, hItem, fAfter );
|
||||
}
|
||||
|
||||
inline COLORREF CTreeView::SetInsertMarkColor(COLORREF clrInsertMark) const
|
||||
// Sets the color used to draw the insertion mark for the tree view.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetInsertMarkColor( m_hWnd, clrInsertMark );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SetItem(TVITEM& Item) const
|
||||
// Sets some or all of a tree-view item's attributes.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetItem( m_hWnd, &Item );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR szText, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) const
|
||||
// Sets some or all of a tree-view item's attributes.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
TVITEM tvi = {0};
|
||||
tvi.hItem = hItem;
|
||||
tvi.mask = nMask;
|
||||
tvi.pszText = (LPTSTR)szText;
|
||||
tvi.iImage = nImage;
|
||||
tvi.iSelectedImage = nSelectedImage;
|
||||
tvi.state = nState;
|
||||
tvi.stateMask = nStateMask;
|
||||
tvi.lParam = lParam;
|
||||
return TreeView_SetItem( m_hWnd, &tvi );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SetItemData(HTREEITEM hItem, DWORD_PTR dwData) const
|
||||
// Sets the tree-view item's application data.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
TVITEM tvi = {0};
|
||||
tvi.hItem = hItem;
|
||||
tvi.mask = TVIF_PARAM;
|
||||
tvi.lParam = dwData;
|
||||
return TreeView_SetItem( m_hWnd, &tvi );
|
||||
}
|
||||
|
||||
inline int CTreeView::SetItemHeight(SHORT cyItem) const
|
||||
// Sets the height of the tree-view items.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetItemHeight( m_hWnd, cyItem );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SetItemImage(HTREEITEM hItem, int nImage, int nSelectedImage) const
|
||||
// Sets the tree-view item's application image.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
TVITEM tvi = {0};
|
||||
tvi.hItem = hItem;
|
||||
tvi.iImage = nImage;
|
||||
tvi.iSelectedImage = nSelectedImage;
|
||||
tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
||||
return TreeView_SetItem(m_hWnd, &tvi );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SetItemText(HTREEITEM hItem, LPCTSTR szText) const
|
||||
// Sets the tree-view item's application text.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
|
||||
TVITEM tvi = {0};
|
||||
tvi.hItem = hItem;
|
||||
tvi.pszText = (LPTSTR)szText;
|
||||
tvi.mask = TVIF_TEXT;
|
||||
return TreeView_SetItem(m_hWnd, &tvi );
|
||||
}
|
||||
|
||||
inline UINT CTreeView::SetScrollTime(UINT uScrollTime) const
|
||||
// Sets the maximum scroll time for the tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetScrollTime( m_hWnd, uScrollTime );
|
||||
}
|
||||
|
||||
inline COLORREF CTreeView::SetTextColor(COLORREF clrText) const
|
||||
// Sets the text color of the control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetTextColor( m_hWnd, clrText );
|
||||
}
|
||||
|
||||
inline HWND CTreeView::SetToolTips(HWND hwndTooltip) const
|
||||
// Sets a tree-view control's child ToolTip control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SetToolTips( m_hWnd, hwndTooltip );
|
||||
}
|
||||
|
||||
// Operations
|
||||
|
||||
inline HIMAGELIST CTreeView::CreateDragImage(HTREEITEM hItem) const
|
||||
// Creates a dragging bitmap for the specified item in a tree-view control.
|
||||
// It also creates an image list for the bitmap and adds the bitmap to the image list.
|
||||
// An application can display the image when dragging the item by using the image list functions.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_CreateDragImage( m_hWnd, hItem );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::DeleteAllItems() const
|
||||
// Deletes all items from a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_DeleteAllItems( m_hWnd );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::DeleteItem(HTREEITEM hItem) const
|
||||
// Removes an item and all its children from a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_DeleteItem( m_hWnd, hItem );
|
||||
}
|
||||
|
||||
inline HWND CTreeView::EditLabel(HTREEITEM hItem) const
|
||||
// Begins in-place editing of the specified item's text, replacing the text of the item
|
||||
// with a single-line edit control containing the text.
|
||||
// The specified item is implicitly selected and focused.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_EditLabel( m_hWnd, hItem );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::EndEditLabelNow(BOOL fCancel) const
|
||||
// Ends the editing of a tree-view item's label.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_EndEditLabelNow(m_hWnd, fCancel);
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::EnsureVisible(HTREEITEM hItem) const
|
||||
// Ensures that a tree-view item is visible, expanding the parent item or
|
||||
// scrolling the tree-view control, if necessary.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_EnsureVisible( m_hWnd, hItem );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::Expand(HTREEITEM hItem, UINT nCode) const
|
||||
// The TreeView_Expand macro expands or collapses the list of child items associated
|
||||
// with the specified parent item, if any.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_Expand( m_hWnd, hItem, nCode );
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::HitTest(TVHITTESTINFO& ht) const
|
||||
// Determines the location of the specified point relative to the client area of a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_HitTest( m_hWnd, &ht );
|
||||
}
|
||||
|
||||
inline HTREEITEM CTreeView::InsertItem(TVINSERTSTRUCT& tvIS) const
|
||||
// Inserts a new item in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_InsertItem( m_hWnd, &tvIS );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::Select(HTREEITEM hitem, UINT flag) const
|
||||
// Selects the specified tree-view item, scrolls the item into view, or redraws
|
||||
// the item in the style used to indicate the target of a drag-and-drop operation.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_Select(m_hWnd, hitem, flag );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SelectDropTarget(HTREEITEM hItem) const
|
||||
// Redraws a specified tree-view control item in the style used to indicate the
|
||||
// target of a drag-and-drop operation.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SelectDropTarget(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SelectItem(HTREEITEM hItem) const
|
||||
// Selects the specified tree-view item.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SelectItem(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SelectSetFirstVisible(HTREEITEM hItem) const
|
||||
// Scrolls the tree-view control vertically to ensure that the specified item is visible.
|
||||
// If possible, the specified item becomes the first visible item at the top of the control's window.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SelectSetFirstVisible(m_hWnd, hItem);
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) const
|
||||
// Sorts the child items of the specified parent item in a tree-view control.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SortChildren( m_hWnd, hItem, fRecurse );
|
||||
}
|
||||
|
||||
inline BOOL CTreeView::SortChildrenCB(TVSORTCB& sort, BOOL fRecurse) const
|
||||
// Sorts tree-view items using an application-defined callback function that compares the items.
|
||||
{
|
||||
assert(::IsWindow(m_hWnd));
|
||||
return TreeView_SortChildrenCB( m_hWnd, &sort, fRecurse );
|
||||
}
|
||||
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // #ifndef _WIN32XX_TREEVIEW_H_
|
||||
|
420
mmc_updater/depends/win32cpp/wceframe.h
Normal file
420
mmc_updater/depends/win32cpp/wceframe.h
Normal file
@ -0,0 +1,420 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// WceFrame.h
|
||||
// Definitions for the CCmdBar and CWceFrame
|
||||
|
||||
// These classes are provide a frame window for use on Window CE devices such
|
||||
// as Pocket PCs. The frame uses CommandBar (a control unique to the Windows CE
|
||||
// operating systems) to display the menu and toolbar.
|
||||
//
|
||||
// Use the PocketPCWceFrame generic application as the starting point for your own
|
||||
// frame based applications on the Pocket PC.
|
||||
//
|
||||
// Refer to the Scribble demo application for an example of how these classes
|
||||
// can be used.
|
||||
|
||||
|
||||
#ifndef _WIN32XX_WCEFRAME_H_
|
||||
#define _WIN32XX_WCEFRAME_H_
|
||||
|
||||
|
||||
#include "wincore.h"
|
||||
#include <commctrl.h>
|
||||
#include <vector>
|
||||
#include "default_resource.h"
|
||||
|
||||
#if defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)
|
||||
#define SHELL_AYGSHELL
|
||||
#endif
|
||||
|
||||
#ifdef SHELL_AYGSHELL
|
||||
#include <aygshell.h>
|
||||
#pragma comment(lib, "aygshell.lib")
|
||||
#endif // SHELL_AYGSHELL
|
||||
|
||||
#if (_WIN32_WCE < 0x500 && defined(SHELL_AYGSHELL)) || _WIN32_WCE == 420
|
||||
#pragma comment(lib, "ccrtrtti.lib")
|
||||
#endif
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
|
||||
////////////////////////////////////
|
||||
// Declaration of the CCmdBar class
|
||||
//
|
||||
class CCmdBar : public CWnd
|
||||
{
|
||||
public:
|
||||
CCmdBar();
|
||||
virtual ~CCmdBar();
|
||||
virtual BOOL AddAdornments(DWORD dwFlags);
|
||||
virtual int AddBitmap(int idBitmap, int iNumImages, int iImageWidth, int iImageHeight);
|
||||
virtual BOOL AddButtons(int nButtons, TBBUTTON* pTBButton);
|
||||
virtual HWND Create(HWND hwndParent);
|
||||
virtual int GetHeight() const;
|
||||
virtual HWND InsertComboBox(int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton);
|
||||
virtual BOOL IsVisible();
|
||||
virtual BOOL Show(BOOL fShow);
|
||||
|
||||
private:
|
||||
|
||||
#ifdef SHELL_AYGSHELL
|
||||
SHMENUBARINFO m_mbi;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// Declaration of the CWceFrame class
|
||||
// A mini frame based on CCmdBar
|
||||
class CWceFrame : public CWnd
|
||||
{
|
||||
public:
|
||||
CWceFrame();
|
||||
virtual ~CWceFrame();
|
||||
virtual void AddToolBarButton(UINT nID);
|
||||
CRect GetViewRect() const;
|
||||
CCmdBar& GetMenuBar() const {return (CCmdBar&)m_MenuBar;}
|
||||
virtual void OnActivate(WPARAM wParam, LPARAM lParam);
|
||||
virtual void OnCreate();
|
||||
virtual void PreCreate(CREATESTRUCT &cs);
|
||||
virtual void RecalcLayout();
|
||||
virtual void SetButtons(const std::vector<UINT> ToolBarData);
|
||||
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
protected:
|
||||
std::vector<UINT> m_ToolBarData;
|
||||
|
||||
private:
|
||||
CCmdBar m_MenuBar;
|
||||
tString m_tsAppName;
|
||||
|
||||
#ifdef SHELL_AYGSHELL
|
||||
SHACTIVATEINFO m_sai;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Definitions for the CCmdBar class
|
||||
// This class wraps CommandBar_Create which
|
||||
// creates a CommandBar at the top of the window
|
||||
inline CCmdBar::CCmdBar()
|
||||
{
|
||||
}
|
||||
|
||||
inline CCmdBar::~CCmdBar()
|
||||
{
|
||||
if (IsWindow())
|
||||
::CommandBar_Destroy(m_hWnd);
|
||||
}
|
||||
|
||||
|
||||
inline BOOL CCmdBar::AddAdornments(DWORD dwFlags)
|
||||
{
|
||||
BOOL bReturn = CommandBar_AddAdornments(m_hWnd, dwFlags, 0);
|
||||
|
||||
if (!bReturn)
|
||||
throw CWinException(_T("AddAdornments failed"));
|
||||
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
inline int CCmdBar::AddBitmap(int idBitmap, int iNumImages, int iImageWidth, int iImageHeight)
|
||||
{
|
||||
HINSTANCE hInst = GetApp()->GetInstanceHandle();
|
||||
return CommandBar_AddBitmap(m_hWnd, hInst, idBitmap, iNumImages, iImageWidth, iImageHeight);
|
||||
}
|
||||
|
||||
inline BOOL CCmdBar::AddButtons(int nButtons, TBBUTTON* pTBButton)
|
||||
{
|
||||
BOOL bReturn = CommandBar_AddButtons(m_hWnd, nButtons, pTBButton);
|
||||
if (!bReturn)
|
||||
throw CWinException(_T("Failed to add buttons to commandbar"));
|
||||
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
inline HWND CCmdBar::Create(HWND hParent)
|
||||
{
|
||||
#ifdef SHELL_AYGSHELL
|
||||
SHMENUBARINFO mbi;
|
||||
|
||||
memset(&mbi, 0, sizeof(SHMENUBARINFO));
|
||||
mbi.cbSize = sizeof(SHMENUBARINFO);
|
||||
mbi.hwndParent = hParent;
|
||||
mbi.nToolBarId = IDW_MAIN;
|
||||
mbi.hInstRes = GetApp()->GetInstanceHandle();
|
||||
mbi.nBmpId = 0;
|
||||
mbi.cBmpImages = 0;
|
||||
|
||||
if (SHCreateMenuBar(&mbi))
|
||||
{
|
||||
m_hWnd = mbi.hwndMB;
|
||||
}
|
||||
else
|
||||
throw CWinException(_T("Failed to create MenuBar"));
|
||||
|
||||
#else
|
||||
m_hWnd = CommandBar_Create(GetApp()->GetInstanceHandle(), hParent, IDW_MENUBAR);
|
||||
|
||||
if (m_hWnd == NULL)
|
||||
throw CWinException(_T("Failed to create CommandBar"));
|
||||
|
||||
CommandBar_InsertMenubar(m_hWnd, GetApp()->GetInstanceHandle(), IDW_MAIN, 0);
|
||||
#endif
|
||||
return m_hWnd;
|
||||
}
|
||||
|
||||
inline int CCmdBar::GetHeight() const
|
||||
{
|
||||
return CommandBar_Height(m_hWnd);
|
||||
}
|
||||
|
||||
inline HWND CCmdBar::InsertComboBox(int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton)
|
||||
{
|
||||
HINSTANCE hInst = GetApp()->GetInstanceHandle();
|
||||
HWND hWnd = CommandBar_InsertComboBox(m_hWnd, hInst, iWidth, dwStyle, idComboBox, iButton);
|
||||
|
||||
if (!hWnd)
|
||||
throw CWinException(_T("InsertComboBox failed"));
|
||||
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
inline BOOL CCmdBar::IsVisible()
|
||||
{
|
||||
return ::CommandBar_IsVisible(m_hWnd);
|
||||
}
|
||||
|
||||
inline BOOL CCmdBar::Show(BOOL fShow)
|
||||
{
|
||||
return ::CommandBar_Show(m_hWnd, fShow);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Definitions for the CWceFrame class
|
||||
// This class creates a simple frame using CCmdBar
|
||||
inline CWceFrame::CWceFrame()
|
||||
{
|
||||
#ifdef SHELL_AYGSHELL
|
||||
// Initialize the shell activate info structure
|
||||
memset (&m_sai, 0, sizeof (m_sai));
|
||||
m_sai.cbSize = sizeof (m_sai);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline CWceFrame::~CWceFrame()
|
||||
{
|
||||
}
|
||||
|
||||
inline void CWceFrame::AddToolBarButton(UINT nID)
|
||||
// Adds Resource IDs to toolbar buttons.
|
||||
// A resource ID of 0 is a separator
|
||||
{
|
||||
m_ToolBarData.push_back(nID);
|
||||
}
|
||||
|
||||
inline CRect CWceFrame::GetViewRect() const
|
||||
{
|
||||
CRect r;
|
||||
::GetClientRect(m_hWnd, &r);
|
||||
|
||||
#ifndef SHELL_AYGSHELL
|
||||
// Reduce the size of the client rectange, by the commandbar height
|
||||
r.top += m_MenuBar.GetHeight();
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void CWceFrame::OnCreate()
|
||||
{
|
||||
// Create the Commandbar
|
||||
m_MenuBar.Create(m_hWnd);
|
||||
|
||||
// Set the keyboard accelerators
|
||||
HACCEL hAccel = LoadAccelerators(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(IDW_MAIN));
|
||||
GetApp()->SetAccelerators(hAccel, this);
|
||||
|
||||
// Add the toolbar buttons
|
||||
if (m_ToolBarData.size() > 0)
|
||||
SetButtons(m_ToolBarData);
|
||||
|
||||
#ifndef SHELL_AYGSHELL
|
||||
// Add close button
|
||||
m_MenuBar.AddAdornments(0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
inline void CWceFrame::OnActivate(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
#ifdef SHELL_AYGSHELL
|
||||
// Notify shell of our activate message
|
||||
SHHandleWMActivate(m_hWnd, wParam, lParam, &m_sai, FALSE);
|
||||
|
||||
UINT fActive = LOWORD(wParam);
|
||||
if ((fActive == WA_ACTIVE) || (fActive == WA_CLICKACTIVE))
|
||||
{
|
||||
// Reposition the window when it's activated
|
||||
RecalcLayout();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void CWceFrame::PreCreate(CREATESTRUCT &cs)
|
||||
{
|
||||
cs.style = WS_VISIBLE;
|
||||
m_tsAppName = _T("Win32++ Application");
|
||||
|
||||
// Choose a unique class name for this app
|
||||
if (LoadString(IDW_MAIN) != _T(""))
|
||||
{
|
||||
m_tsAppName = LoadString(IDW_MAIN);
|
||||
}
|
||||
|
||||
cs.lpszClass = m_tsAppName.c_str();
|
||||
}
|
||||
|
||||
/* inline BOOL CWceFrame::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
HACCEL hAccelTable = ::LoadAccelerators(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(IDW_MAIN));
|
||||
if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST)
|
||||
{
|
||||
if (TranslateAccelerator(m_hWnd, hAccelTable, pMsg))
|
||||
return TRUE;
|
||||
}
|
||||
return CWnd::PreTranslateMessage(pMsg);
|
||||
} */
|
||||
|
||||
inline void CWceFrame::RecalcLayout()
|
||||
{
|
||||
HWND hwndCB = m_MenuBar.GetHwnd();
|
||||
if (hwndCB)
|
||||
{
|
||||
CRect rc; // Desktop window size
|
||||
CRect rcMenuBar; // MenuBar window size
|
||||
|
||||
::SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
||||
::GetWindowRect(hwndCB, &rcMenuBar);
|
||||
rc.bottom -= (rcMenuBar.bottom - rcMenuBar.top);
|
||||
|
||||
MoveWindow(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, FALSE);
|
||||
}
|
||||
|
||||
ShowWindow(TRUE);
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
inline void CWceFrame::SetButtons(const std::vector<UINT> ToolBarData)
|
||||
// Define the resource IDs for the toolbar like this in the Frame's constructor
|
||||
// m_ToolBarData.push_back ( 0 ); // Separator
|
||||
// m_ToolBarData.clear();
|
||||
// m_ToolBarData.push_back ( IDM_FILE_NEW );
|
||||
// m_ToolBarData.push_back ( IDM_FILE_OPEN );
|
||||
// m_ToolBarData.push_back ( IDM_FILE_SAVE );
|
||||
|
||||
{
|
||||
int iImages = 0;
|
||||
int iNumButtons = (int)ToolBarData.size();
|
||||
|
||||
|
||||
if (iNumButtons > 0)
|
||||
{
|
||||
// Create the TBBUTTON array for each button
|
||||
std::vector<TBBUTTON> vTBB(iNumButtons);
|
||||
TBBUTTON* tbbArray = &vTBB.front();
|
||||
|
||||
for (int j = 0 ; j < iNumButtons; j++)
|
||||
{
|
||||
ZeroMemory(&tbbArray[j], sizeof(TBBUTTON));
|
||||
|
||||
if (ToolBarData[j] == 0)
|
||||
{
|
||||
tbbArray[j].fsStyle = TBSTYLE_SEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
tbbArray[j].iBitmap = iImages++;
|
||||
tbbArray[j].idCommand = ToolBarData[j];
|
||||
tbbArray[j].fsState = TBSTATE_ENABLED;
|
||||
tbbArray[j].fsStyle = TBSTYLE_BUTTON;
|
||||
tbbArray[j].iString = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the bitmap
|
||||
GetMenuBar().AddBitmap(IDW_MAIN, iImages , 16, 16);
|
||||
|
||||
// Add the buttons
|
||||
GetMenuBar().AddButtons(iNumButtons, tbbArray);
|
||||
}
|
||||
}
|
||||
|
||||
inline LRESULT CWceFrame::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
case WM_ACTIVATE:
|
||||
OnActivate(wParam, lParam);
|
||||
break;
|
||||
|
||||
#ifdef SHELL_AYGSHELL
|
||||
|
||||
case WM_SETTINGCHANGE:
|
||||
SHHandleWMSettingChange(m_hWnd, wParam, lParam, &m_sai);
|
||||
break;
|
||||
#endif
|
||||
|
||||
}
|
||||
return CWnd::WndProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Win32xx
|
||||
|
||||
#endif // _WIN32XX_WCEFRAME_H_
|
||||
|
58
mmc_updater/depends/win32cpp/wcestddef.h
Normal file
58
mmc_updater/depends/win32cpp/wcestddef.h
Normal file
@ -0,0 +1,58 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma comment(linker, "/nodefaultlib:libc.lib")
|
||||
#pragma comment(linker, "/nodefaultlib:libcd.lib")
|
||||
|
||||
|
||||
#include <ceconfig.h>
|
||||
#if defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)
|
||||
#define SHELL_AYGSHELL
|
||||
#endif
|
||||
|
||||
#ifdef _CE_DCOM
|
||||
#define _ATL_APARTMENT_THREADED
|
||||
#endif
|
||||
|
||||
#if defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)
|
||||
#ifndef _DEVICE_RESOLUTION_AWARE
|
||||
#define _DEVICE_RESOLUTION_AWARE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if _WIN32_WCE == 420 || _WIN32_WCE == 0x420
|
||||
// For Pocket PC 2003
|
||||
#pragma comment(lib, "ccrtrtti.lib")
|
||||
#endif
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
|
||||
// NOTE - this value is not strongly correlated to the Windows CE OS version being targeted
|
||||
#undef WINVER
|
||||
#define WINVER _WIN32_WCE
|
||||
|
||||
#ifdef _DEVICE_RESOLUTION_AWARE
|
||||
#include "DeviceResolutionAware.h"
|
||||
#endif
|
||||
|
||||
#if _WIN32_WCE < 0x500 && ( defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP) )
|
||||
#ifdef _X86_
|
||||
#if defined(_DEBUG)
|
||||
#pragma comment(lib, "libcmtx86d.lib")
|
||||
#else
|
||||
#pragma comment(lib, "libcmtx86.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <altcecrt.h>
|
||||
|
||||
#endif// _MSC_VER >= 1300
|
||||
|
||||
#ifdef SHELL_AYGSHELL
|
||||
#include <aygshell.h>
|
||||
#pragma comment(lib, "aygshell.lib")
|
||||
#endif // SHELL_AYGSHELL
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
760
mmc_updater/depends/win32cpp/webbrowser.h
Normal file
760
mmc_updater/depends/win32cpp/webbrowser.h
Normal file
@ -0,0 +1,760 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WIN32XX_WEBBROWSER_H_
|
||||
#define _WIN32XX_WEBBROWSER_H_
|
||||
|
||||
#include <exdisp.h>
|
||||
#include <ocidl.h>
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
///////////////////////////////////////////////////
|
||||
// Declaration of the CAXWindow class
|
||||
// This class implements an ActiveX control container
|
||||
class CAXWindow : public IOleClientSite, public IOleInPlaceSite, public IOleInPlaceFrame,
|
||||
public IOleControlSite, public IDispatch
|
||||
{
|
||||
public:
|
||||
CAXWindow();
|
||||
virtual ~CAXWindow();
|
||||
virtual void Activate(BOOL fFocus);
|
||||
virtual void CreateControl(BSTR bstrClsid);
|
||||
virtual void CreateControl(CLSID clsid);
|
||||
virtual void Remove();
|
||||
virtual void SetParent(HWND hWndParent);
|
||||
virtual void SetLocation(int x, int y, int width, int height);
|
||||
virtual void SetVisible(BOOL fVisible);
|
||||
virtual void SetStatusWindow(HWND hWndStatus);
|
||||
virtual void TranslateKey(MSG msg);
|
||||
IDispatch* GetDispatch();
|
||||
IUnknown* GetUnknown();
|
||||
|
||||
// IUnknown Methods
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IOleClientSite Methods
|
||||
STDMETHODIMP SaveObject();
|
||||
STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMk);
|
||||
STDMETHODIMP GetContainer(LPOLECONTAINER* ppContainer);
|
||||
STDMETHODIMP ShowObject();
|
||||
STDMETHODIMP OnShowWindow(BOOL fShow);
|
||||
STDMETHODIMP RequestNewObjectLayout();
|
||||
|
||||
// IOleWindow Methods
|
||||
STDMETHODIMP GetWindow(HWND* phwnd);
|
||||
STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
|
||||
|
||||
// IOleInPlaceSite Methods
|
||||
STDMETHODIMP CanInPlaceActivate();
|
||||
STDMETHODIMP OnInPlaceActivate();
|
||||
STDMETHODIMP OnUIActivate();
|
||||
STDMETHODIMP GetWindowContext(IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo);
|
||||
STDMETHODIMP Scroll(SIZE scrollExtent);
|
||||
STDMETHODIMP OnUIDeactivate(BOOL fUndoable);
|
||||
STDMETHODIMP OnInPlaceDeactivate();
|
||||
STDMETHODIMP DiscardUndoState();
|
||||
STDMETHODIMP DeactivateAndUndo();
|
||||
STDMETHODIMP OnPosRectChange(LPCRECT lprcPosRect);
|
||||
|
||||
// IOleInPlaceUIWindow Methods
|
||||
STDMETHODIMP GetBorder(LPRECT lprectBorder);
|
||||
STDMETHODIMP RequestBorderSpace(LPCBORDERWIDTHS lpborderwidths);
|
||||
STDMETHODIMP SetBorderSpace(LPCBORDERWIDTHS lpborderwidths);
|
||||
STDMETHODIMP SetActiveObject(IOleInPlaceActiveObject* pActiveObject, LPCOLESTR lpszObjName);
|
||||
|
||||
// IOleInPlaceFrame Methods
|
||||
STDMETHODIMP InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
|
||||
STDMETHODIMP SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);
|
||||
STDMETHODIMP RemoveMenus(HMENU hmenuShared);
|
||||
STDMETHODIMP SetStatusText(LPCOLESTR pszStatusText);
|
||||
STDMETHODIMP EnableModeless(BOOL fEnable);
|
||||
STDMETHODIMP TranslateAccelerator(LPMSG lpmsg, WORD wID);
|
||||
|
||||
// IOleControlSite Methods
|
||||
STDMETHODIMP OnControlInfoChanged();
|
||||
STDMETHODIMP LockInPlaceActive(BOOL fLock);
|
||||
STDMETHODIMP GetExtendedControl(IDispatch** ppDisp);
|
||||
STDMETHODIMP TransformCoords(POINTL* pptlHimetric, POINTF* pptfContainer, DWORD dwFlags);
|
||||
STDMETHODIMP TranslateAccelerator(LPMSG pMsg, DWORD grfModifiers);
|
||||
STDMETHODIMP OnFocus(BOOL fGotFocus);
|
||||
STDMETHODIMP ShowPropertyFrame();
|
||||
|
||||
// IDispatch Methods
|
||||
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, unsigned int cNames, LCID lcid, DISPID* rgdispid);
|
||||
STDMETHODIMP GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo** pptinfo);
|
||||
STDMETHODIMP GetTypeInfoCount(unsigned int* pctinfo);
|
||||
STDMETHODIMP Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexecinfo, unsigned int* puArgErr);
|
||||
|
||||
private:
|
||||
ULONG m_cRefs; // ref count
|
||||
HWND m_hWnd; // window handle of the container
|
||||
HWND m_hWndStatus; // status window handle
|
||||
IUnknown* m_pUnk; // IUnknown of contained object
|
||||
CRect m_rcControl; // size of control
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Declaration of the CWebBrowser class
|
||||
// This class uses an AciveX Container provided by
|
||||
// CAXWindow to host the IWebBrower2 interface.
|
||||
class CWebBrowser : public CWnd
|
||||
{
|
||||
public:
|
||||
CWebBrowser();
|
||||
virtual ~CWebBrowser();
|
||||
virtual void AddWebBrowserControl(void);
|
||||
virtual CAXWindow& GetAXWindow() const { return (CAXWindow&)m_AXContainer; }
|
||||
virtual IWebBrowser2* GetIWebBrowser2() const { return m_pIWebBrowser2; }
|
||||
virtual void Navigate(LPCTSTR str);
|
||||
|
||||
protected:
|
||||
virtual void OnCreate();
|
||||
virtual void OnSize(int width, int height);
|
||||
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
CAXWindow m_AXContainer; // The ActiveX Container
|
||||
IWebBrowser2* m_pIWebBrowser2;// Interface to the ActiveX web browser control
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
/////////////////////////////////////////
|
||||
// Definitions for the CAXWindow class
|
||||
//
|
||||
inline CAXWindow::CAXWindow() : m_cRefs(1), m_hWnd(NULL), m_pUnk(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
inline CAXWindow::~CAXWindow()
|
||||
{
|
||||
}
|
||||
|
||||
inline void CAXWindow::CreateControl(BSTR bstrClsid)
|
||||
{
|
||||
CLSID clsid;
|
||||
CLSIDFromString(bstrClsid, &clsid);
|
||||
CreateControl(clsid);
|
||||
}
|
||||
|
||||
inline void CAXWindow::Activate(BOOL fFocus)
|
||||
{
|
||||
if (!m_pUnk)
|
||||
return;
|
||||
|
||||
if (fFocus)
|
||||
{
|
||||
IOleObject* pioo;
|
||||
HRESULT hr = m_pUnk->QueryInterface(IID_IOleObject, (void**)&pioo);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
pioo->DoVerb(OLEIVERB_UIACTIVATE, NULL, this, 0, m_hWnd, &m_rcControl);
|
||||
pioo->Release();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CAXWindow::CreateControl(CLSID clsid)
|
||||
{
|
||||
CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&m_pUnk);
|
||||
|
||||
if (!m_pUnk)
|
||||
return;
|
||||
|
||||
IOleObject* pioo;
|
||||
HRESULT hr = m_pUnk->QueryInterface(IID_IOleObject, (void**)&pioo);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
pioo->SetClientSite(this);
|
||||
pioo->Release();
|
||||
|
||||
IPersistStreamInit* ppsi;
|
||||
hr = m_pUnk->QueryInterface(IID_IPersistStreamInit, (void**)&ppsi);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ppsi->InitNew();
|
||||
ppsi->Release();
|
||||
}
|
||||
}
|
||||
|
||||
inline STDMETHODIMP_(ULONG) CAXWindow::AddRef()
|
||||
{
|
||||
return ++m_cRefs;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::CanInPlaceActivate()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::ContextSensitiveHelp(BOOL fEnterMode)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fEnterMode);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::DeactivateAndUndo()
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::DiscardUndoState()
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::EnableModeless(BOOL fEnable)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fEnable);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetBorder(LPRECT lprectBorder)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lprectBorder);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetContainer(LPOLECONTAINER* ppContainer)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ppContainer);
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
inline IDispatch* CAXWindow::GetDispatch()
|
||||
{
|
||||
if (!m_pUnk)
|
||||
return NULL;
|
||||
|
||||
HRESULT hr;
|
||||
IDispatch* pdisp;
|
||||
|
||||
hr = m_pUnk->QueryInterface(IID_IDispatch, (void**)&pdisp);
|
||||
return pdisp;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetExtendedControl(IDispatch** ppDisp)
|
||||
{
|
||||
if (ppDisp == NULL)
|
||||
return E_INVALIDARG;
|
||||
|
||||
*ppDisp = (IDispatch*)this;
|
||||
(*ppDisp)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, unsigned int cNames, LCID lcid, DISPID* rgdispid)
|
||||
{
|
||||
UNREFERENCED_PARAMETER((IID)riid); // IID cast required for the MinGW compiler
|
||||
UNREFERENCED_PARAMETER(rgszNames);
|
||||
UNREFERENCED_PARAMETER(cNames);
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
|
||||
*rgdispid = DISPID_UNKNOWN;
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMk)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dwAssign);
|
||||
UNREFERENCED_PARAMETER(dwWhichMoniker);
|
||||
UNREFERENCED_PARAMETER(ppMk);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo** pptinfo)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(itinfo);
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
UNREFERENCED_PARAMETER(pptinfo);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetTypeInfoCount(unsigned int* pctinfo)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pctinfo);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline IUnknown* CAXWindow::GetUnknown()
|
||||
{
|
||||
if (!m_pUnk)
|
||||
return NULL;
|
||||
|
||||
m_pUnk->AddRef();
|
||||
return m_pUnk;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetWindow(HWND* lphwnd)
|
||||
{
|
||||
if (!IsWindow(m_hWnd))
|
||||
return S_FALSE;
|
||||
|
||||
*lphwnd = m_hWnd;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::GetWindowContext (IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppIIPUIWin,
|
||||
LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
|
||||
{
|
||||
*ppFrame = (IOleInPlaceFrame*)this;
|
||||
*ppIIPUIWin = NULL;
|
||||
|
||||
RECT rect;
|
||||
GetClientRect(m_hWnd, &rect);
|
||||
lprcPosRect->left = 0;
|
||||
lprcPosRect->top = 0;
|
||||
lprcPosRect->right = rect.right;
|
||||
lprcPosRect->bottom = rect.bottom;
|
||||
|
||||
CopyRect(lprcClipRect, lprcPosRect);
|
||||
|
||||
lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO);
|
||||
lpFrameInfo->fMDIApp = FALSE;
|
||||
lpFrameInfo->hwndFrame = m_hWnd;
|
||||
lpFrameInfo->haccel = 0;
|
||||
lpFrameInfo->cAccelEntries = 0;
|
||||
|
||||
(*ppFrame)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hmenuShared);
|
||||
UNREFERENCED_PARAMETER(lpMenuWidths);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexecinfo, unsigned int* puArgErr)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dispid);
|
||||
UNREFERENCED_PARAMETER((IID)riid); // IID cast required for the MinGW compiler
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
UNREFERENCED_PARAMETER(wFlags);
|
||||
UNREFERENCED_PARAMETER(pdispparams);
|
||||
UNREFERENCED_PARAMETER(pvarResult);
|
||||
UNREFERENCED_PARAMETER(pexecinfo);
|
||||
UNREFERENCED_PARAMETER(puArgErr);
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::LockInPlaceActive(BOOL fLock)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fLock);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnControlInfoChanged()
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnFocus(BOOL fGotFocus)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fGotFocus);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnInPlaceActivate()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnInPlaceDeactivate()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnPosRectChange(LPCRECT lprcPosRect)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lprcPosRect);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnShowWindow(BOOL fShow)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fShow);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnUIActivate()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::OnUIDeactivate(BOOL fUndoable)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fUndoable);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::QueryInterface(REFIID riid, void** ppvObject)
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_POINTER;
|
||||
|
||||
if (IsEqualIID(riid, IID_IOleClientSite))
|
||||
*ppvObject = (IOleClientSite*)this;
|
||||
else if (IsEqualIID(riid, IID_IOleInPlaceSite))
|
||||
*ppvObject = (IOleInPlaceSite*)this;
|
||||
else if (IsEqualIID(riid, IID_IOleInPlaceFrame))
|
||||
*ppvObject = (IOleInPlaceFrame*)this;
|
||||
else if (IsEqualIID(riid, IID_IOleInPlaceUIWindow))
|
||||
*ppvObject = (IOleInPlaceUIWindow*)this;
|
||||
else if (IsEqualIID(riid, IID_IOleControlSite))
|
||||
*ppvObject = (IOleControlSite*)this;
|
||||
else if (IsEqualIID(riid, IID_IOleWindow))
|
||||
*ppvObject = this;
|
||||
else if (IsEqualIID(riid, IID_IDispatch))
|
||||
*ppvObject = (IDispatch*)this;
|
||||
else if (IsEqualIID(riid, IID_IUnknown))
|
||||
*ppvObject = this;
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP_(ULONG) CAXWindow::Release()
|
||||
{
|
||||
return --m_cRefs;
|
||||
}
|
||||
|
||||
inline void CAXWindow::Remove()
|
||||
{
|
||||
if (!m_pUnk)
|
||||
return;
|
||||
|
||||
IOleObject* pioo;
|
||||
HRESULT hr = m_pUnk->QueryInterface(IID_IOleObject, (void**)&pioo);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pioo->Close(OLECLOSE_NOSAVE);
|
||||
pioo->SetClientSite(NULL);
|
||||
pioo->Release();
|
||||
}
|
||||
|
||||
IOleInPlaceObject* pipo;
|
||||
hr = m_pUnk->QueryInterface(IID_IOleInPlaceObject, (void**)&pipo);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pipo->UIDeactivate();
|
||||
pipo->InPlaceDeactivate();
|
||||
pipo->Release();
|
||||
}
|
||||
|
||||
m_pUnk->Release();
|
||||
m_pUnk = NULL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::RemoveMenus(HMENU hmenuShared)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hmenuShared);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::RequestBorderSpace(LPCBORDERWIDTHS lpborderwidths)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lpborderwidths);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::RequestNewObjectLayout()
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::SaveObject()
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::Scroll(SIZE scrollExtent)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(scrollExtent);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::SetActiveObject(IOleInPlaceActiveObject* pActiveObject, LPCOLESTR lpszObjName)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pActiveObject);
|
||||
UNREFERENCED_PARAMETER(lpszObjName);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::SetBorderSpace(LPCBORDERWIDTHS lpborderwidths)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lpborderwidths);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline void CAXWindow::SetLocation(int x, int y, int width, int height)
|
||||
{
|
||||
m_rcControl.SetRect(x, y, x + width, y + height);
|
||||
|
||||
if (!m_pUnk)
|
||||
return;
|
||||
|
||||
IOleInPlaceObject* pipo;
|
||||
HRESULT hr = m_pUnk->QueryInterface(IID_IOleInPlaceObject, (void**)&pipo);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
pipo->SetObjectRects(&m_rcControl, &m_rcControl);
|
||||
pipo->Release();
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hmenuShared);
|
||||
UNREFERENCED_PARAMETER(holemenu);
|
||||
UNREFERENCED_PARAMETER(hwndActiveObject);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline void CAXWindow::SetParent(HWND hWndParent)
|
||||
{
|
||||
m_hWnd = hWndParent;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::SetStatusText(LPCOLESTR pszStatusText)
|
||||
{
|
||||
if (NULL == pszStatusText)
|
||||
return E_POINTER;
|
||||
|
||||
#ifndef _UNICODE
|
||||
char status[MAX_PATH];
|
||||
// Convert the Wide string to char
|
||||
WideCharToMultiByte(CP_ACP, 0, pszStatusText, -1, status, MAX_PATH, NULL, NULL);
|
||||
|
||||
if (IsWindow(m_hWndStatus))
|
||||
SendMessage(m_hWndStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)status);
|
||||
#else
|
||||
if (IsWindow(m_hWndStatus))
|
||||
SendMessage(m_hWndStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)pszStatusText);
|
||||
#endif
|
||||
|
||||
return (S_OK);
|
||||
}
|
||||
|
||||
inline void CAXWindow::SetStatusWindow(HWND hWndStatus)
|
||||
{
|
||||
m_hWndStatus = hWndStatus;
|
||||
}
|
||||
|
||||
inline void CAXWindow::SetVisible(BOOL fVisible)
|
||||
{
|
||||
if (!m_pUnk)
|
||||
return;
|
||||
|
||||
IOleObject* pioo;
|
||||
HRESULT hr = m_pUnk->QueryInterface(IID_IOleObject, (void**)&pioo);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
if (fVisible)
|
||||
{
|
||||
pioo->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, this, 0, m_hWnd, &m_rcControl);
|
||||
pioo->DoVerb(OLEIVERB_SHOW, NULL, this, 0, m_hWnd, &m_rcControl);
|
||||
}
|
||||
else
|
||||
pioo->DoVerb(OLEIVERB_HIDE, NULL, this, 0, m_hWnd, NULL);
|
||||
|
||||
pioo->Release();
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::ShowObject()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::ShowPropertyFrame()
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::TransformCoords(POINTL* pptlHimetric, POINTF* pptfContainer, DWORD dwFlags)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pptlHimetric);
|
||||
UNREFERENCED_PARAMETER(pptfContainer);
|
||||
UNREFERENCED_PARAMETER(dwFlags);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::TranslateAccelerator(LPMSG lpmsg, WORD wID)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lpmsg);
|
||||
UNREFERENCED_PARAMETER(wID);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline STDMETHODIMP CAXWindow::TranslateAccelerator(LPMSG pMsg, DWORD grfModifiers)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pMsg);
|
||||
UNREFERENCED_PARAMETER(grfModifiers);
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
inline void CAXWindow::TranslateKey(MSG msg)
|
||||
{
|
||||
if (!m_pUnk)
|
||||
return;
|
||||
|
||||
IOleInPlaceActiveObject* pao;
|
||||
HRESULT hr = m_pUnk->QueryInterface(IID_IOleInPlaceActiveObject, (void**)&pao);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
pao->TranslateAccelerator(&msg);
|
||||
pao->Release();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// Definitions for the CWebBrowser class
|
||||
//
|
||||
inline CWebBrowser::CWebBrowser() : m_pIWebBrowser2(0)
|
||||
{
|
||||
OleInitialize(NULL);
|
||||
}
|
||||
|
||||
inline CWebBrowser::~CWebBrowser()
|
||||
{
|
||||
if (m_pIWebBrowser2)
|
||||
{
|
||||
m_pIWebBrowser2->Stop();
|
||||
m_pIWebBrowser2->Release();
|
||||
}
|
||||
|
||||
OleUninitialize();
|
||||
}
|
||||
|
||||
inline void CWebBrowser::AddWebBrowserControl()
|
||||
{
|
||||
GetAXWindow().CreateControl(CLSID_WebBrowser);
|
||||
GetAXWindow().SetParent(m_hWnd);
|
||||
GetAXWindow().SetVisible(TRUE);
|
||||
GetAXWindow().Activate(TRUE);
|
||||
|
||||
IUnknown* pUnk = GetAXWindow().GetUnknown();
|
||||
if(pUnk)
|
||||
{
|
||||
// Store the pointer to the WebBrowser control
|
||||
HRESULT hr = pUnk->QueryInterface(IID_IWebBrowser2, (void**)&m_pIWebBrowser2);
|
||||
pUnk->Release();
|
||||
|
||||
// Navigate to an empty page
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
VARIANT vURL;
|
||||
vURL.vt = VT_BSTR;
|
||||
vURL.bstrVal = SysAllocString(L"about:blank");
|
||||
VARIANT ve1, ve2, ve3, ve4;
|
||||
ve1.vt = VT_EMPTY;
|
||||
ve2.vt = VT_EMPTY;
|
||||
ve3.vt = VT_EMPTY;
|
||||
ve4.vt = VT_EMPTY;
|
||||
|
||||
m_pIWebBrowser2->Navigate2(&vURL, &ve1, &ve2, &ve3, &ve4);
|
||||
|
||||
VariantClear(&vURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void CWebBrowser::Navigate(LPCTSTR pTChar)
|
||||
{
|
||||
// Navigate to our web page
|
||||
VARIANT vURL;
|
||||
vURL.vt = VT_BSTR;
|
||||
vURL.bstrVal = SysAllocString(T2W(pTChar));
|
||||
VARIANT ve1, ve2, ve3, ve4;
|
||||
ve1.vt = VT_EMPTY;
|
||||
ve2.vt = VT_EMPTY;
|
||||
ve3.vt = VT_EMPTY;
|
||||
ve4.vt = VT_EMPTY;
|
||||
|
||||
GetIWebBrowser2()->Navigate2(&vURL, &ve1, &ve2, &ve3, &ve4);
|
||||
|
||||
VariantClear(&vURL); // Also frees memory allocated by SysAllocateString
|
||||
}
|
||||
|
||||
inline void CWebBrowser::OnCreate()
|
||||
{
|
||||
AddWebBrowserControl();
|
||||
}
|
||||
|
||||
inline void CWebBrowser::OnSize(int width, int height)
|
||||
{
|
||||
// position the container
|
||||
GetAXWindow().SetLocation(0, 0, width, height);
|
||||
}
|
||||
|
||||
inline LRESULT CWebBrowser::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_SIZE:
|
||||
OnSize(LOWORD(lParam), HIWORD(lParam));
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
GetAXWindow().Remove();
|
||||
break;
|
||||
}
|
||||
|
||||
return CWnd::WndProcDefault(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // _WIN32XX_WEBBROWSER_H_
|
||||
|
2977
mmc_updater/depends/win32cpp/wincore.h
Normal file
2977
mmc_updater/depends/win32cpp/wincore.h
Normal file
File diff suppressed because it is too large
Load Diff
649
mmc_updater/depends/win32cpp/winutils.h
Normal file
649
mmc_updater/depends/win32cpp/winutils.h
Normal file
@ -0,0 +1,649 @@
|
||||
// Win32++ Version 7.2
|
||||
// Released: 5th AUgust 2011
|
||||
//
|
||||
// David Nash
|
||||
// email: dnash@bigpond.net.au
|
||||
// url: https://sourceforge.net/projects/win32-framework
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2005-2011 David Nash
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to
|
||||
// any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify,
|
||||
// merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom
|
||||
// the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WIN32XX_WINUTILS_H_
|
||||
#define _WIN32XX_WINUTILS_H_
|
||||
|
||||
|
||||
// define useful macros from WindowsX.h
|
||||
#ifndef GET_X_LPARAM
|
||||
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
|
||||
#endif
|
||||
#ifndef GET_Y_LPARAM
|
||||
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
|
||||
#endif
|
||||
|
||||
// Define our own MIN and MAX macros
|
||||
// this avoids inconsistencies with Dev-C++ and other compilers, and
|
||||
// avoids conflicts between typical min/max macros and std::min/std::max
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
|
||||
namespace Win32xx
|
||||
{
|
||||
// Forward declarations
|
||||
class CPoint;
|
||||
class CRect;
|
||||
CWinApp* GetApp();
|
||||
void TRACE(LPCTSTR str);
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Definition of the CSize class
|
||||
// This class can be used to replace the SIZE structure
|
||||
class CSize : public SIZE
|
||||
{
|
||||
public:
|
||||
CSize() { cx = 0; cy = 0; }
|
||||
CSize(int CX, int CY) { cx = CX; cy = CY; }
|
||||
CSize(SIZE sz) { cx = sz.cx; cy = sz.cy; }
|
||||
CSize(POINT pt) { cx = pt.x; cy = pt.y; }
|
||||
CSize(DWORD dw) { cx = (short)LOWORD(dw); cy = (short)HIWORD(dw); }
|
||||
void SetSize(int CX, int CY) { cx = CX; cy = CY; }
|
||||
|
||||
// Operators
|
||||
operator LPSIZE() { return this; }
|
||||
BOOL operator == (SIZE sz) const { return (cx == sz.cx && cy == sz.cy); }
|
||||
BOOL operator != (SIZE sz) const { return (cx != sz.cx || cy != sz.cy); }
|
||||
void operator += (SIZE sz) { cx += sz.cx; cy += sz.cy; }
|
||||
void operator -= (SIZE sz) { cx -= sz.cx; cy -= sz.cy; }
|
||||
|
||||
// Operators returning CSize
|
||||
CSize operator - () const { return CSize (-cx, -cy); }
|
||||
CSize operator + (SIZE sz) const { return CSize (cx + sz.cx, cy + sz.cy); }
|
||||
CSize operator - (SIZE sz) const { return CSize (cx - sz.cx, cy - sz.cy); }
|
||||
|
||||
// Operators returning CPoint
|
||||
CPoint operator + (POINT point) const;
|
||||
CPoint operator - (POINT point) const;
|
||||
|
||||
// Operators returning CRect
|
||||
CRect operator + (RECT rc) const;
|
||||
CRect operator - (RECT rc) const;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Definition of the CPoint class
|
||||
// This class can be used to replace the POINT structure
|
||||
class CPoint : public POINT
|
||||
{
|
||||
public:
|
||||
CPoint() { x = 0; y = 0; }
|
||||
CPoint(int X, int Y) { x = X; y = Y; }
|
||||
CPoint(POINT pt) { x = pt.x ; y = pt.y; }
|
||||
CPoint(POINTS pts) { x = pts.x; y = pts.y; }
|
||||
CPoint(SIZE sz) { x = sz.cx; y = sz.cy; }
|
||||
CPoint(DWORD dw) { x = (short) LOWORD(dw); y = (short) HIWORD(dw); }
|
||||
|
||||
void Offset(int dx, int dy) { x += dx; y += dy; }
|
||||
void Offset(POINT pt) { x += pt.x; y += pt.y; }
|
||||
void Offset(SIZE sz) { x += sz.cx; y += sz.cy; }
|
||||
void SetPoint(int X, int Y) { x = X; y = Y; }
|
||||
|
||||
// Operators
|
||||
operator LPPOINT() { return this; }
|
||||
BOOL operator == (POINT pt) const { return ((x == pt.x) && (y == pt.y)); }
|
||||
BOOL operator != (POINT pt) const { return ((x != pt.x) || (y != pt.y)); }
|
||||
void operator += (SIZE sz) { x += sz.cx; y += sz.cy; }
|
||||
void operator -= (SIZE sz) { x -= sz.cx; y -= sz.cy; }
|
||||
void operator += (POINT pt) { x += pt.x; y += pt.y; }
|
||||
void operator -= (POINT pt) { x -= pt.x; y -= pt.y; }
|
||||
|
||||
// Operators returning CPoint
|
||||
CPoint operator - () const { return CPoint(-x, -y); }
|
||||
CPoint operator + (SIZE sz) const { return CPoint(x + sz.cx, y + sz.cy); }
|
||||
CPoint operator - (SIZE sz) const { return CPoint(x - sz.cx, y - sz.cy); }
|
||||
CPoint operator + (POINT pt) const { return CPoint(x + pt.x, y + pt.y); }
|
||||
CPoint operator - (POINT pt) const { return CPoint(x - pt.x, y - pt.y); }
|
||||
|
||||
// Operators returning CRect
|
||||
CRect operator + (RECT rc) const;
|
||||
CRect operator - (RECT rc) const;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Definition of the CRect class
|
||||
// This class can be used to replace the RECT structure.
|
||||
class CRect : public RECT
|
||||
{
|
||||
public:
|
||||
CRect() { left = top = right = bottom = 0; }
|
||||
CRect(int l, int t, int r, int b) { left = l; top = t; right = r; bottom = b; }
|
||||
CRect(RECT rc) { left = rc.left; top = rc.top; right = rc.right; bottom = rc.bottom; }
|
||||
CRect(POINT pt, SIZE sz) { right = (left = pt.x) + sz.cx; bottom = (top = pt.y) + sz.cy; }
|
||||
CRect(POINT topLeft, POINT bottomRight) { left = topLeft.x; top = topLeft.y; right = bottomRight.x; bottom = bottomRight.y; }
|
||||
|
||||
BOOL CopyRect(RECT rc) { return ::CopyRect(this, &rc); }
|
||||
BOOL DeflateRect(int x, int y) { return ::InflateRect(this, -x, -y); }
|
||||
BOOL DeflateRect(SIZE size) { return ::InflateRect(this, -size.cx, -size.cy); }
|
||||
BOOL DeflateRect(RECT rc) { return ::InflateRect(this, rc.left - rc.right, rc.top - rc.bottom); }
|
||||
BOOL DeflateRect(int l, int t, int r, int b){ return ::InflateRect(this, l - r, t - b); }
|
||||
BOOL EqualRect(RECT rc) const { return ::EqualRect(&rc, this); }
|
||||
BOOL InflateRect(int dx, int dy) { return ::InflateRect(this, dx, dy); }
|
||||
BOOL InflateRect(SIZE sz) { return ::InflateRect(this, sz.cx, sz.cy); }
|
||||
BOOL InflateRect(RECT rc) { return ::InflateRect(this, rc.right - rc.left, rc.bottom - rc.top); }
|
||||
BOOL InflateRect(int l, int t, int r, int b){ return ::InflateRect(this, r - l, b - t); }
|
||||
BOOL IntersectRect(RECT rc1, RECT rc2) { return ::IntersectRect(this, &rc1, &rc2); }
|
||||
BOOL IsRectEmpty() const { return ::IsRectEmpty(this);}
|
||||
BOOL IsRectNull() const { return (left == 0 && right == 0 && top == 0 && bottom == 0); }
|
||||
CRect MulDiv(int nMult, int nDiv) const { return CRect ((left * nMult) / nDiv, (top * nMult) / nDiv,
|
||||
(right * nMult) / nDiv, (bottom * nMult) / nDiv); }
|
||||
void NormalizeRect() { int nTemp; if (left > right) { nTemp = left; left = right; right = nTemp; }
|
||||
if (top > bottom) { nTemp = top; top = bottom; bottom = nTemp; } }
|
||||
BOOL OffsetRect(int dx, int dy) { return ::OffsetRect(this, dx, dy); }
|
||||
BOOL OffsetRect(POINT pt) { return ::OffsetRect(this, pt.x, pt.y); }
|
||||
BOOL OffsetRect(SIZE size) { return ::OffsetRect(this, size.cx, size.cy); }
|
||||
BOOL PtInRect(POINT pt) const { return ::PtInRect(this, pt); }
|
||||
BOOL SetRect(int l, int t, int r, int b) { return ::SetRect(this, l, t, r, b); }
|
||||
BOOL SetRect(POINT TopLeft, POINT BtmRight) { return ::SetRect(this, TopLeft.x, TopLeft.y, BtmRight.x, BtmRight.y); }
|
||||
BOOL SetRectEmpty() { return ::SetRectEmpty(this); }
|
||||
BOOL SubtractRect(RECT rc1, RECT rc2) { return ::SubtractRect(this, &rc1, &rc2); }
|
||||
BOOL UnionRect(RECT rc1, RECT rc2) { return ::UnionRect(this, &rc1, &rc2); }
|
||||
|
||||
// Reposition rectangle
|
||||
void MoveToX (int x) { right = Width() + x; left = x; }
|
||||
void MoveToY (int y) { bottom = Height() + y; top = y; }
|
||||
void MoveToXY (int x, int y) { MoveToX(x); MoveToY(y); }
|
||||
void MoveToXY (POINT pt) { MoveToX (pt.x); MoveToY (pt.y); }
|
||||
|
||||
// Attributes
|
||||
int Height() const { return bottom - top; }
|
||||
int Width() const { return right - left; }
|
||||
CSize Size() const { return CSize(Width(), Height()); }
|
||||
CPoint CenterPoint() const { return CPoint((left + right) / 2, (top + bottom) / 2); }
|
||||
CPoint TopLeft() const { return CPoint(left, top); }
|
||||
CPoint BottomRight() const { return CPoint(right, bottom); }
|
||||
|
||||
// operators
|
||||
operator LPRECT() { return this; }
|
||||
BOOL operator == (RECT rc) const { return ::EqualRect(this, &rc); }
|
||||
BOOL operator != (RECT rc) const { return !::EqualRect(this, &rc); }
|
||||
void operator += (POINT pt) { ::OffsetRect(this, pt.x, pt.y); }
|
||||
void operator += (SIZE size) { ::OffsetRect(this, size.cx, size.cy); }
|
||||
void operator += (RECT rc) { ::InflateRect(this, rc.right - rc.left, rc.bottom - rc.top); }
|
||||
void operator -= (RECT rc) { ::InflateRect(this, rc.left - rc.right, rc.top - rc.bottom); }
|
||||
void operator -= (POINT pt) { ::OffsetRect(this, -pt.x, -pt.y); }
|
||||
void operator -= (SIZE sz) { ::OffsetRect(this, -sz.cx, -sz.cy); }
|
||||
void operator &= (RECT rc) { ::IntersectRect(this, this, &rc); }
|
||||
void operator |= (RECT rc) { ::UnionRect(this, this, &rc); }
|
||||
|
||||
// Operators returning CRect
|
||||
CRect operator + (POINT pt) const { CRect rc(*this); ::OffsetRect(&rc, pt.x, pt.y); return rc; }
|
||||
CRect operator - (POINT pt) const { CRect rc(*this); ::OffsetRect(&rc, -pt.x, -pt.y); return rc; }
|
||||
CRect operator + (SIZE sz) const { CRect rc(*this); ::OffsetRect(&rc, sz.cx, sz.cy); return rc; }
|
||||
CRect operator - (SIZE sz) const { CRect rc(*this); ::OffsetRect(&rc, -sz.cx, -sz.cy); return rc; }
|
||||
CRect operator + (RECT rc) const { CRect rc1(*this); rc1.InflateRect(rc); return rc1; }
|
||||
CRect operator - (RECT rc) const { CRect rc1(*this); rc1.DeflateRect(rc); return rc1; }
|
||||
CRect operator & (RECT rc) const { CRect rc1; ::IntersectRect(&rc1, this, &rc); return rc1; }
|
||||
CRect operator | (RECT rc) const { CRect rc1; ::UnionRect(&rc1, this, &rc); return rc1; }
|
||||
};
|
||||
|
||||
// CSize member function definitions
|
||||
inline CPoint CSize::operator + (POINT pt) const { return CPoint(pt) + *this; }
|
||||
inline CPoint CSize::operator - (POINT pt) const { return CPoint(pt) - *this; }
|
||||
inline CRect CSize::operator + (RECT rc) const { return CRect(rc) + *this; }
|
||||
inline CRect CSize::operator - (RECT rc) const { return CRect(rc) - *this; }
|
||||
|
||||
// CPoint member function definitions
|
||||
inline CRect CPoint::operator + (RECT rc) const { return CRect(rc) + *this; }
|
||||
inline CRect CPoint::operator - (RECT rc) const { return CRect(rc) - *this; }
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// Classes and functions (typedefs) for text conversions
|
||||
//
|
||||
// This section defines the following text conversions:
|
||||
// A2BSTR ANSI to BSTR
|
||||
// A2OLE ANSI to OLE
|
||||
// A2T ANSI to TCHAR
|
||||
// A2W ANSI to WCHAR
|
||||
// OLE2A OLE to ANSI
|
||||
// OLE2T OLE to TCHAR
|
||||
// OLE2W OLE to WCHAR
|
||||
// T2A TCHAR to ANSI
|
||||
// T2BSTR TCHAR to BSTR
|
||||
// T2OLE TCHAR to OLE
|
||||
// T2W TCHAR to WCHAR
|
||||
// W2A WCHAR to ANSI
|
||||
// W2BSTR WCHAR to BSTR
|
||||
// W2OLE WCHAR to OLE
|
||||
// W2T WCHAR to TCHAR
|
||||
|
||||
// About different character and string types:
|
||||
// ------------------------------------------
|
||||
// char (or CHAR) character types are ANSI (8 bits).
|
||||
// wchar_t (or WCHAR) character types are Unicode (16 bits).
|
||||
// TCHAR characters are Unicode if the _UNICODE macro is defined, otherwise they are ANSI.
|
||||
// BSTR (Basic String) is a type of string used in Visual Basic and COM programming.
|
||||
// OLE is the same as WCHAR. It is used in Visual Basic and COM programming.
|
||||
|
||||
|
||||
// Forward declarations of our classes. They are defined later.
|
||||
class CA2A;
|
||||
class CA2W;
|
||||
class CW2A;
|
||||
class CW2W;
|
||||
class CA2BSTR;
|
||||
class CW2BSTR;
|
||||
|
||||
// typedefs for the well known text conversions
|
||||
typedef CA2W A2W;
|
||||
typedef CW2A W2A;
|
||||
typedef CW2BSTR W2BSTR;
|
||||
typedef CA2BSTR A2BSTR;
|
||||
typedef CW2A BSTR2A;
|
||||
typedef CW2W BSTR2W;
|
||||
|
||||
#ifdef _UNICODE
|
||||
typedef CA2W A2T;
|
||||
typedef CW2A T2A;
|
||||
typedef CW2W T2W;
|
||||
typedef CW2W W2T;
|
||||
typedef CW2BSTR T2BSTR;
|
||||
typedef BSTR2W BSTR2T;
|
||||
#else
|
||||
typedef CA2A A2T;
|
||||
typedef CA2A T2A;
|
||||
typedef CA2W T2W;
|
||||
typedef CW2A W2T;
|
||||
typedef CA2BSTR T2BSTR;
|
||||
typedef BSTR2A BSTR2T;
|
||||
#endif
|
||||
|
||||
typedef A2W A2OLE;
|
||||
typedef T2W T2OLE;
|
||||
typedef CW2W W2OLE;
|
||||
typedef W2A OLE2A;
|
||||
typedef W2T OLE2T;
|
||||
typedef CW2W OLE2W;
|
||||
|
||||
class CA2W
|
||||
{
|
||||
public:
|
||||
CA2W(LPCSTR pStr) : m_pStr(pStr)
|
||||
{
|
||||
if (pStr)
|
||||
{
|
||||
// Resize the vector and assign null WCHAR to each element
|
||||
int length = (int)strlen(pStr)+1;
|
||||
m_vWideArray.assign(length, L'\0');
|
||||
|
||||
// Fill our vector with the converted WCHAR array
|
||||
MultiByteToWideChar(CP_ACP, 0, pStr, -1, &m_vWideArray[0], length);
|
||||
}
|
||||
}
|
||||
~CA2W() {}
|
||||
operator LPCWSTR() { return m_pStr? &m_vWideArray[0] : NULL; }
|
||||
operator LPOLESTR() { return m_pStr? (LPOLESTR)&m_vWideArray[0] : (LPOLESTR)NULL; }
|
||||
operator LPBSTR() { return m_pStr? (LPBSTR)&m_vWideArray[0] : (LPBSTR)NULL; }
|
||||
|
||||
private:
|
||||
CA2W(const CA2W&);
|
||||
CA2W& operator= (const CA2W&);
|
||||
std::vector<wchar_t> m_vWideArray;
|
||||
LPCSTR m_pStr;
|
||||
};
|
||||
|
||||
class CW2A
|
||||
{
|
||||
public:
|
||||
CW2A(LPCWSTR pWStr) : m_pWStr(pWStr)
|
||||
{
|
||||
// Resize the vector and assign null char to each element
|
||||
int length = (int)wcslen(pWStr)+1;
|
||||
m_vAnsiArray.assign(length, '\0');
|
||||
|
||||
// Fill our vector with the converted char array
|
||||
WideCharToMultiByte(CP_ACP, 0, pWStr, -1, &m_vAnsiArray[0], length, NULL,NULL);
|
||||
}
|
||||
|
||||
~CW2A() {}
|
||||
operator LPCSTR() { return m_pWStr? &m_vAnsiArray[0] : NULL; }
|
||||
|
||||
private:
|
||||
CW2A(const CW2A&);
|
||||
CW2A& operator= (const CW2A&);
|
||||
std::vector<char> m_vAnsiArray;
|
||||
LPCWSTR m_pWStr;
|
||||
};
|
||||
|
||||
class CW2W
|
||||
{
|
||||
public:
|
||||
CW2W(LPCWSTR pWStr) : m_pWStr(pWStr) {}
|
||||
operator LPCWSTR() { return (LPWSTR)m_pWStr; }
|
||||
operator LPOLESTR() { return (LPOLESTR)m_pWStr; }
|
||||
|
||||
private:
|
||||
CW2W(const CW2W&);
|
||||
CW2W& operator= (const CW2W&);
|
||||
|
||||
LPCWSTR m_pWStr;
|
||||
};
|
||||
|
||||
class CA2A
|
||||
{
|
||||
public:
|
||||
CA2A(LPCSTR pStr) : m_pStr(pStr) {}
|
||||
operator LPCSTR() { return (LPSTR)m_pStr; }
|
||||
|
||||
private:
|
||||
CA2A(const CA2A&);
|
||||
CA2A& operator= (const CA2A&);
|
||||
|
||||
LPCSTR m_pStr;
|
||||
};
|
||||
|
||||
class CW2BSTR
|
||||
{
|
||||
public:
|
||||
CW2BSTR(LPCWSTR pWStr) { m_bstrString = ::SysAllocString(pWStr); }
|
||||
~CW2BSTR() { ::SysFreeString(m_bstrString); }
|
||||
operator BSTR() { return m_bstrString;}
|
||||
|
||||
private:
|
||||
CW2BSTR(const CW2BSTR&);
|
||||
CW2BSTR& operator= (const CW2BSTR&);
|
||||
BSTR m_bstrString;
|
||||
};
|
||||
|
||||
class CA2BSTR
|
||||
{
|
||||
public:
|
||||
CA2BSTR(LPCSTR pStr) { m_bstrString = ::SysAllocString(A2W(pStr)); }
|
||||
~CA2BSTR() { ::SysFreeString(m_bstrString); }
|
||||
operator BSTR() { return m_bstrString;}
|
||||
|
||||
private:
|
||||
CA2BSTR(const CA2BSTR&);
|
||||
CA2BSTR& operator= (const CA2BSTR&);
|
||||
BSTR m_bstrString;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// Global Functions
|
||||
//
|
||||
|
||||
inline CWnd* FromHandle(HWND hWnd)
|
||||
// Returns the CWnd object associated with the window handle
|
||||
{
|
||||
assert( GetApp() );
|
||||
CWnd* pWnd = GetApp()->GetCWndFromMap(hWnd);
|
||||
if (::IsWindow(hWnd) && pWnd == 0)
|
||||
{
|
||||
GetApp()->AddTmpWnd(hWnd);
|
||||
pWnd = GetApp()->GetCWndFromMap(hWnd);
|
||||
::PostMessage(hWnd, UWM_CLEANUPTEMPS, 0, 0);
|
||||
}
|
||||
|
||||
return pWnd;
|
||||
}
|
||||
|
||||
|
||||
inline CWinApp* GetApp()
|
||||
// Returns a pointer to the CWinApp derrived class
|
||||
{
|
||||
return CWinApp::SetnGetThis();
|
||||
}
|
||||
|
||||
inline CPoint GetCursorPos()
|
||||
{
|
||||
CPoint pt;
|
||||
::GetCursorPos(&pt);
|
||||
return pt;
|
||||
}
|
||||
|
||||
inline HBITMAP LoadBitmap (LPCTSTR lpszName)
|
||||
{
|
||||
assert(GetApp());
|
||||
|
||||
HBITMAP hBitmap = (HBITMAP)::LoadImage (GetApp()->GetResourceHandle(), lpszName, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
inline HBITMAP LoadBitmap (int nID)
|
||||
{
|
||||
return LoadBitmap(MAKEINTRESOURCE(nID));
|
||||
}
|
||||
|
||||
|
||||
inline void TRACE(LPCTSTR str)
|
||||
// TRACE sends a string to the debug/output pane, or an external debugger
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
OutputDebugString(str);
|
||||
#else
|
||||
UNREFERENCED_PARAMETER(str); // no-op
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32_WCE // for Win32/64 operating systems, not WinCE
|
||||
|
||||
inline int GetWinVersion()
|
||||
{
|
||||
DWORD dwVersion = GetVersion();
|
||||
int Platform = (dwVersion < 0x80000000)? 2:1;
|
||||
int MajorVer = LOBYTE(LOWORD(dwVersion));
|
||||
int MinorVer = HIBYTE(LOWORD(dwVersion));
|
||||
|
||||
int nVersion = 1000*Platform + 100*MajorVer + MinorVer;
|
||||
|
||||
// Return values and window versions:
|
||||
// 1400 Windows 95
|
||||
// 1410 Windows 98
|
||||
// 1490 Windows ME
|
||||
// 2400 Windows NT
|
||||
// 2500 Windows 2000
|
||||
// 2501 Windows XP
|
||||
// 2502 Windows Server 2003
|
||||
// 2600 Windows Vista and Windows Server 2008
|
||||
// 2601 Windows 7
|
||||
|
||||
return nVersion;
|
||||
}
|
||||
|
||||
inline int GetComCtlVersion()
|
||||
{
|
||||
// Load the Common Controls DLL
|
||||
HMODULE hComCtl = ::LoadLibraryA("COMCTL32.DLL");
|
||||
if (!hComCtl)
|
||||
return 0;
|
||||
|
||||
int ComCtlVer = 400;
|
||||
|
||||
if (::GetProcAddress(hComCtl, "InitCommonControlsEx"))
|
||||
{
|
||||
// InitCommonControlsEx is unique to 4.7 and later
|
||||
ComCtlVer = 470;
|
||||
|
||||
if (::GetProcAddress(hComCtl, "DllGetVersion"))
|
||||
{
|
||||
typedef HRESULT CALLBACK DLLGETVERSION(DLLVERSIONINFO*);
|
||||
DLLGETVERSION* pfnDLLGetVersion = NULL;
|
||||
|
||||
pfnDLLGetVersion = (DLLGETVERSION*)::GetProcAddress(hComCtl, "DllGetVersion");
|
||||
if(pfnDLLGetVersion)
|
||||
{
|
||||
DLLVERSIONINFO dvi;
|
||||
dvi.cbSize = sizeof dvi;
|
||||
if(NOERROR == pfnDLLGetVersion(&dvi))
|
||||
{
|
||||
DWORD dwVerMajor = dvi.dwMajorVersion;
|
||||
DWORD dwVerMinor = dvi.dwMinorVersion;
|
||||
ComCtlVer = 100 * dwVerMajor + dwVerMinor;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (::GetProcAddress(hComCtl, "InitializeFlatSB"))
|
||||
ComCtlVer = 471; // InitializeFlatSB is unique to version 4.71
|
||||
}
|
||||
|
||||
::FreeLibrary(hComCtl);
|
||||
|
||||
// return values and DLL versions
|
||||
// 400 dll ver 4.00 Windows 95/Windows NT 4.0
|
||||
// 470 dll ver 4.70 Internet Explorer 3.x
|
||||
// 471 dll ver 4.71 Internet Explorer 4.0
|
||||
// 472 dll ver 4.72 Internet Explorer 4.01 and Windows 98
|
||||
// 580 dll ver 5.80 Internet Explorer 5
|
||||
// 581 dll ver 5.81 Windows 2000 and Windows ME
|
||||
// 582 dll ver 5.82 Windows XP or Vista without XP themes
|
||||
// 600 dll ver 6.00 Windows XP with XP themes
|
||||
// 610 dll ver 6.10 Windows Vista with XP themes
|
||||
// 616 dll ver 6.16 Windows Vista SP1 or Windows 7 with XP themes
|
||||
|
||||
return ComCtlVer;
|
||||
}
|
||||
|
||||
inline UINT GetSizeofMenuItemInfo()
|
||||
{
|
||||
UINT uSize = sizeof(MENUITEMINFO);
|
||||
// For Win95 and NT, cbSize needs to be 44
|
||||
if (1400 == (GetWinVersion()) || (2400 == GetWinVersion()))
|
||||
uSize = 44;
|
||||
|
||||
return uSize;
|
||||
}
|
||||
|
||||
inline UINT GetSizeofNonClientMetrics()
|
||||
{
|
||||
// This function correctly determines the sizeof NONCLIENTMETRICS
|
||||
UINT uSize = sizeof (NONCLIENTMETRICS);
|
||||
|
||||
#if (WINVER >= 0x0600)
|
||||
if (GetWinVersion() < 2600 && (uSize > 500)) // Is OS version less than Vista
|
||||
uSize -= sizeof(int); // Adjust size back to correct value
|
||||
#endif
|
||||
|
||||
return uSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// A global function to report the state of the left mouse button
|
||||
inline BOOL IsLeftButtonDown()
|
||||
{
|
||||
SHORT state;
|
||||
if (GetSystemMetrics(SM_SWAPBUTTON))
|
||||
// Mouse buttons are swapped
|
||||
state = GetAsyncKeyState(VK_RBUTTON);
|
||||
else
|
||||
// Mouse buttons are not swapped
|
||||
state = GetAsyncKeyState(VK_LBUTTON);
|
||||
|
||||
// returns true if the left mouse button is down
|
||||
return (state & 0x8000);
|
||||
}
|
||||
|
||||
inline BOOL IsAeroThemed()
|
||||
{
|
||||
BOOL bIsAeroThemed = FALSE;
|
||||
|
||||
// Test if Windows version is XP or greater
|
||||
if (GetWinVersion() >= 2501)
|
||||
{
|
||||
HMODULE hMod = ::LoadLibrary(_T("uxtheme.dll"));
|
||||
if(hMod)
|
||||
{
|
||||
// Declare pointers to IsCompositionActive function
|
||||
FARPROC pIsCompositionActive = ::GetProcAddress(hMod, "IsCompositionActive");
|
||||
|
||||
if(pIsCompositionActive)
|
||||
{
|
||||
if(pIsCompositionActive())
|
||||
{
|
||||
bIsAeroThemed = TRUE;
|
||||
}
|
||||
}
|
||||
::FreeLibrary(hMod);
|
||||
}
|
||||
}
|
||||
|
||||
return bIsAeroThemed;
|
||||
}
|
||||
|
||||
inline BOOL IsXPThemed()
|
||||
{
|
||||
BOOL bIsXPThemed = FALSE;
|
||||
|
||||
// Test if Windows version is XP or greater
|
||||
if (GetWinVersion() >= 2501)
|
||||
{
|
||||
HMODULE hMod = ::LoadLibrary(_T("uxtheme.dll"));
|
||||
if(hMod)
|
||||
{
|
||||
// Declare pointers to functions
|
||||
FARPROC pIsAppThemed = ::GetProcAddress(hMod, "IsAppThemed");
|
||||
FARPROC pIsThemeActive = ::GetProcAddress(hMod, "IsThemeActive");
|
||||
|
||||
if(pIsAppThemed && pIsThemeActive)
|
||||
{
|
||||
if(pIsAppThemed() && pIsThemeActive())
|
||||
{
|
||||
// Test if ComCtl32 dll used is version 6 or later
|
||||
bIsXPThemed = (GetComCtlVersion() >= 600);
|
||||
}
|
||||
}
|
||||
::FreeLibrary(hMod);
|
||||
}
|
||||
}
|
||||
|
||||
return bIsXPThemed;
|
||||
}
|
||||
|
||||
#endif // #ifndef _WIN32_WCE
|
||||
|
||||
// Required for WinCE
|
||||
#ifndef lstrcpyn
|
||||
inline LPTSTR lstrcpyn(LPTSTR lpstrDest, LPCTSTR lpstrSrc, int nLength)
|
||||
{
|
||||
if(NULL == lpstrDest || NULL == lpstrSrc || nLength <= 0)
|
||||
return NULL;
|
||||
int nLen = MIN((int)lstrlen(lpstrSrc), nLength - 1);
|
||||
LPTSTR lpstrRet = (LPTSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(TCHAR));
|
||||
lpstrDest[nLen] = _T('\0');
|
||||
return lpstrRet;
|
||||
}
|
||||
#endif // !lstrcpyn
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // _WIN32XX_WINUTILS_H_
|
23
mmc_updater/src/AppInfo.cpp
Normal file
23
mmc_updater/src/AppInfo.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "AppInfo.h"
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
#include "StandardDirs.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
std::string AppInfo::logFilePath()
|
||||
{
|
||||
return StandardDirs::appDataPath(organizationName(),appName()) + '/' + "update-log.txt";
|
||||
}
|
||||
|
||||
std::string AppInfo::updateErrorMessage(const std::string& details)
|
||||
{
|
||||
std::string result = "There was a problem installing the update:\n\n";
|
||||
result += details;
|
||||
result += "\n\nYou can try downloading and installing the latest version of "
|
||||
"MultiMC from http://multimc.org/";
|
||||
return result;
|
||||
}
|
||||
|
39
mmc_updater/src/AppInfo.h
Normal file
39
mmc_updater/src/AppInfo.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
/** This class provides project-specific updater properties,
|
||||
* such as the name of the application being updated and
|
||||
* the path to log details of the update install to.
|
||||
*/
|
||||
class AppInfo
|
||||
{
|
||||
public:
|
||||
// Basic application information
|
||||
static std::string name();
|
||||
static std::string appName();
|
||||
static std::string organizationName();
|
||||
|
||||
static std::string logFilePath();
|
||||
|
||||
/** Returns a message to display to the user in the event
|
||||
* of a problem installing the update.
|
||||
*/
|
||||
static std::string updateErrorMessage(const std::string& details);
|
||||
};
|
||||
|
||||
inline std::string AppInfo::name()
|
||||
{
|
||||
return "MultiMC Updater";
|
||||
}
|
||||
|
||||
inline std::string AppInfo::appName()
|
||||
{
|
||||
return "MultiMC";
|
||||
}
|
||||
|
||||
inline std::string AppInfo::organizationName()
|
||||
{
|
||||
return "MultiMC Contributors";
|
||||
}
|
||||
|
121
mmc_updater/src/CMakeLists.txt
Normal file
121
mmc_updater/src/CMakeLists.txt
Normal file
@ -0,0 +1,121 @@
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
include(GenerateCppResourceFile)
|
||||
|
||||
set (UPDATER_SOURCES
|
||||
AppInfo.cpp
|
||||
AppInfo.h
|
||||
DirIterator.cpp
|
||||
DirIterator.h
|
||||
FileUtils.cpp
|
||||
FileUtils.h
|
||||
Log.cpp
|
||||
Log.h
|
||||
ProcessUtils.cpp
|
||||
ProcessUtils.h
|
||||
StandardDirs.cpp
|
||||
StandardDirs.h
|
||||
UpdateDialog.cpp
|
||||
UpdateInstaller.cpp
|
||||
UpdateInstaller.h
|
||||
UpdateScript.cpp
|
||||
UpdateScript.h
|
||||
UpdaterOptions.cpp
|
||||
UpdaterOptions.h
|
||||
)
|
||||
|
||||
add_definitions(-DTIXML_USE_STL)
|
||||
|
||||
if (WIN32)
|
||||
set(UPDATER_SOURCES ${UPDATER_SOURCES} UpdateDialogWin32.cpp UpdateDialogWin32.h)
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
set(UPDATER_SOURCES ${UPDATER_SOURCES} UpdateDialogAscii.cpp UpdateDialogAscii.h)
|
||||
add_definitions(-Wall -Werror -Wconversion)
|
||||
if (APPLE)
|
||||
set(MAC_DOCK_ICON_CPP_FILE ${CMAKE_CURRENT_BINARY_DIR}/mac_dock_icon.cpp)
|
||||
set(MAC_INFO_PLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/mac_info_plist.cpp)
|
||||
generate_cpp_resource_file(resource_macdockicon ${CMAKE_CURRENT_SOURCE_DIR}/resources/mac.icns ${MAC_DOCK_ICON_CPP_FILE})
|
||||
generate_cpp_resource_file(resource_macplist ${CMAKE_CURRENT_SOURCE_DIR}/resources/Info.plist ${MAC_INFO_PLIST_FILE})
|
||||
set(UPDATER_SOURCES ${UPDATER_SOURCES}
|
||||
MacBundle.h
|
||||
MacBundle.cpp
|
||||
StandardDirs.mm
|
||||
StlSymbolsLeopard.cpp
|
||||
UpdateDialogCocoa.mm
|
||||
UpdateDialogCocoa.h
|
||||
mac_dock_icon.cpp
|
||||
mac_info_plist.cpp
|
||||
)
|
||||
else() # linuxes and other similar systems
|
||||
find_package(GTK2 REQUIRED gtk)
|
||||
include_directories(${GTK2_INCLUDE_DIRS})
|
||||
add_library(updatergtk SHARED UpdateDialogGtk.cpp UpdateDialogGtk.h)
|
||||
target_link_libraries(updatergtk ${GTK2_LIBRARIES})
|
||||
|
||||
# embed the GTK helper library into the updater binary.
|
||||
# At runtime it will be extracted and loaded if the
|
||||
# GTK libraries are available
|
||||
get_property(GTK_UPDATER_LIB TARGET updatergtk PROPERTY LOCATION)
|
||||
set(GTK_BIN_CPP_FILE ${CMAKE_CURRENT_BINARY_DIR}/libupdatergtk.cpp)
|
||||
generate_cpp_resource_file(resource_updatergtk ${GTK_UPDATER_LIB} ${GTK_BIN_CPP_FILE})
|
||||
add_dependencies(resource_updatergtk updatergtk)
|
||||
|
||||
set(UPDATER_SOURCES ${UPDATER_SOURCES} UpdateDialogGtkFactory.cpp UpdateDialogGtkFactory.h ${GTK_BIN_CPP_FILE})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(updatershared STATIC ${UPDATER_SOURCES})
|
||||
|
||||
target_link_libraries(updatershared
|
||||
anyoption
|
||||
tinyxml
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
if (APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
find_library(SECURITY_LIBRARY Security)
|
||||
target_link_libraries(updatershared ${SECURITY_LIBRARY} ${COCOA_LIBRARY})
|
||||
else()
|
||||
add_dependencies(updatershared resource_updatergtk)
|
||||
endif()
|
||||
target_link_libraries(updatershared pthread dl)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(EXE_FLAGS WIN32 resources/updater.rc)
|
||||
endif()
|
||||
|
||||
add_executable(updater ${EXE_FLAGS} main.cpp)
|
||||
|
||||
target_link_libraries(updater
|
||||
updatershared
|
||||
)
|
||||
|
||||
|
||||
#### Updater Executable ####
|
||||
IF(WIN32)
|
||||
INSTALL(TARGETS updater
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
LIBRARY DESTINATION . COMPONENT Runtime
|
||||
RUNTIME DESTINATION . COMPONENT Runtime
|
||||
)
|
||||
ENDIF()
|
||||
IF(UNIX)
|
||||
IF(APPLE)
|
||||
INSTALL(TARGETS updater
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
RUNTIME DESTINATION MultiMC.app/Contents/MacOS COMPONENT Runtime
|
||||
)
|
||||
ELSE()
|
||||
INSTALL(TARGETS updater
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
RUNTIME DESTINATION bin COMPONENT Runtime
|
||||
)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
85
mmc_updater/src/DirIterator.cpp
Normal file
85
mmc_updater/src/DirIterator.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "DirIterator.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
DirIterator::DirIterator(const char* path)
|
||||
{
|
||||
m_path = path;
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
m_dir = opendir(path);
|
||||
m_entry = 0;
|
||||
#else
|
||||
// to list the contents of a directory, the first
|
||||
// argument to FindFirstFile needs to be a wildcard
|
||||
// of the form: C:\path\to\dir\*
|
||||
std::string searchPath = m_path;
|
||||
if (!endsWith(searchPath,"/"))
|
||||
{
|
||||
searchPath.append("/");
|
||||
}
|
||||
searchPath.append("*");
|
||||
m_findHandle = FindFirstFile(searchPath.c_str(),&m_findData);
|
||||
m_firstEntry = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
DirIterator::~DirIterator()
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
closedir(m_dir);
|
||||
#else
|
||||
FindClose(m_findHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DirIterator::next()
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
m_entry = readdir(m_dir);
|
||||
return m_entry != 0;
|
||||
#else
|
||||
bool result;
|
||||
if (m_firstEntry)
|
||||
{
|
||||
m_firstEntry = false;
|
||||
return m_findHandle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FindNextFile(m_findHandle,&m_findData);
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string DirIterator::fileName() const
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
return m_entry->d_name;
|
||||
#else
|
||||
return m_findData.cFileName;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string DirIterator::filePath() const
|
||||
{
|
||||
return m_path + '/' + fileName();
|
||||
}
|
||||
|
||||
bool DirIterator::isDir() const
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
return m_entry->d_type == DT_DIR;
|
||||
#else
|
||||
return (m_findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
#endif
|
||||
}
|
||||
|
43
mmc_updater/src/DirIterator.h
Normal file
43
mmc_updater/src/DirIterator.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
/** Simple class for iterating over the files in a directory
|
||||
* and reporting their names and types.
|
||||
*/
|
||||
class DirIterator
|
||||
{
|
||||
public:
|
||||
DirIterator(const char* path);
|
||||
~DirIterator();
|
||||
|
||||
// iterate to the next entry in the directory
|
||||
bool next();
|
||||
|
||||
// methods to return information about
|
||||
// the current entry
|
||||
std::string fileName() const;
|
||||
std::string filePath() const;
|
||||
bool isDir() const;
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
DIR* m_dir;
|
||||
dirent* m_entry;
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
HANDLE m_findHandle;
|
||||
WIN32_FIND_DATA m_findData;
|
||||
bool m_firstEntry;
|
||||
#endif
|
||||
};
|
||||
|
557
mmc_updater/src/FileUtils.cpp
Normal file
557
mmc_updater/src/FileUtils.cpp
Normal file
@ -0,0 +1,557 @@
|
||||
#include "FileUtils.h"
|
||||
|
||||
#include "DirIterator.h"
|
||||
#include "Log.h"
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
FileUtils::IOException::IOException(const std::string& error)
|
||||
{
|
||||
init(errno,error);
|
||||
}
|
||||
|
||||
FileUtils::IOException::IOException(int errorCode, const std::string& error)
|
||||
{
|
||||
init(errorCode,error);
|
||||
}
|
||||
|
||||
void FileUtils::IOException::init(int errorCode, const std::string& error)
|
||||
{
|
||||
m_error = error;
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
m_errorCode = errorCode;
|
||||
|
||||
if (m_errorCode > 0)
|
||||
{
|
||||
m_error += " details: " + std::string(strerror(m_errorCode));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
m_errorCode = 0;
|
||||
m_error += " GetLastError returned: " + intToStr(GetLastError());
|
||||
#endif
|
||||
}
|
||||
|
||||
FileUtils::IOException::~IOException() throw ()
|
||||
{
|
||||
}
|
||||
|
||||
FileUtils::IOException::Type FileUtils::IOException::type() const
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
switch (m_errorCode)
|
||||
{
|
||||
case 0:
|
||||
return NoError;
|
||||
case EROFS:
|
||||
return ReadOnlyFileSystem;
|
||||
case ENOSPC:
|
||||
return DiskFull;
|
||||
default:
|
||||
return Unknown;
|
||||
}
|
||||
#else
|
||||
return Unknown;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FileUtils::fileExists(const char* path) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
struct stat fileInfo;
|
||||
if (lstat(path,&fileInfo) != 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw IOException("Error checking for file " + std::string(path));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
DWORD result = GetFileAttributes(path);
|
||||
if (result == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
int FileUtils::fileMode(const char* path) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
struct stat fileInfo;
|
||||
if (stat(path,&fileInfo) != 0)
|
||||
{
|
||||
throw IOException("Error reading file permissions for " + std::string(path));
|
||||
}
|
||||
return fileInfo.st_mode;
|
||||
#else
|
||||
// not implemented for Windows
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::chmod(const char* path, int mode) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (::chmod(path,static_cast<mode_t>(mode)) != 0)
|
||||
{
|
||||
throw IOException("Failed to set permissions on " + std::string(path) + " to " + intToStr(mode));
|
||||
}
|
||||
#else
|
||||
// TODO - Not implemented under Windows - all files
|
||||
// get default permissions
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::moveFile(const char* src, const char* dest) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (rename(src,dest) != 0)
|
||||
{
|
||||
throw IOException("Unable to rename " + std::string(src) + " to " + std::string(dest));
|
||||
}
|
||||
#else
|
||||
if (!MoveFile(src,dest))
|
||||
{
|
||||
throw IOException("Unable to rename " + std::string(src) + " to " + std::string(dest));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::mkpath(const char* dir) throw (IOException)
|
||||
{
|
||||
std::string currentPath;
|
||||
std::istringstream stream(dir);
|
||||
while (!stream.eof())
|
||||
{
|
||||
std::string segment;
|
||||
std::getline(stream,segment,'/');
|
||||
currentPath += segment;
|
||||
if (!currentPath.empty() && !fileExists(currentPath.c_str()))
|
||||
{
|
||||
mkdir(currentPath.c_str());
|
||||
}
|
||||
currentPath += '/';
|
||||
}
|
||||
}
|
||||
|
||||
void FileUtils::mkdir(const char* dir) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (::mkdir(dir,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0)
|
||||
{
|
||||
throw IOException("Unable to create directory " + std::string(dir));
|
||||
}
|
||||
#else
|
||||
if (!CreateDirectory(dir,0 /* default security attributes */))
|
||||
{
|
||||
throw IOException("Unable to create directory " + std::string(dir));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::rmdir(const char* dir) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (::rmdir(dir) != 0)
|
||||
{
|
||||
throw IOException("Unable to remove directory " + std::string(dir));
|
||||
}
|
||||
#else
|
||||
if (!RemoveDirectory(dir))
|
||||
{
|
||||
throw IOException("Unable to remove directory " + std::string(dir));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::createSymLink(const char* link, const char* target) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (symlink(target,link) != 0)
|
||||
{
|
||||
throw IOException("Unable to create symlink " + std::string(link) + " to " + std::string(target));
|
||||
}
|
||||
#else
|
||||
// symlinks are not supported under Windows (at least, not universally.
|
||||
// Windows Vista and later do actually support symlinks)
|
||||
LOG(Warn,"Skipping symlink creation - not implemented in Windows");
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::removeFile(const char* src) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (unlink(src) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
throw IOException("Unable to remove file " + std::string(src));
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!DeleteFile(src))
|
||||
{
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
// if another process is using the file, try moving it to
|
||||
// a temporary directory and then
|
||||
// scheduling it for deletion on reboot
|
||||
std::string tempDeletePathBase = tempPath();
|
||||
tempDeletePathBase += '/';
|
||||
tempDeletePathBase += fileName(src);
|
||||
|
||||
int suffix = 0;
|
||||
std::string tempDeletePath = tempDeletePathBase;
|
||||
while (fileExists(tempDeletePath.c_str()))
|
||||
{
|
||||
++suffix;
|
||||
tempDeletePath = tempDeletePathBase + '_' + intToStr(suffix);
|
||||
}
|
||||
|
||||
LOG(Warn,"Unable to remove file " + std::string(src) + " - it may be in use. Moving to "
|
||||
+ tempDeletePath + " and scheduling delete on reboot.");
|
||||
moveFile(src,tempDeletePath.c_str());
|
||||
MoveFileEx(tempDeletePath.c_str(),0,MOVEFILE_DELAY_UNTIL_REBOOT);
|
||||
}
|
||||
else if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
throw IOException("Unable to remove file " + std::string(src));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FileUtils::fileName(const char* path)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
char* pathCopy = strdup(path);
|
||||
std::string basename = ::basename(pathCopy);
|
||||
free(pathCopy);
|
||||
return basename;
|
||||
#else
|
||||
char baseName[MAX_PATH];
|
||||
char extension[MAX_PATH];
|
||||
_splitpath_s(path,
|
||||
0, /* drive */
|
||||
0, /* drive length */
|
||||
0, /* dir */
|
||||
0, /* dir length */
|
||||
baseName,
|
||||
MAX_PATH, /* baseName length */
|
||||
extension,
|
||||
MAX_PATH /* extension length */
|
||||
);
|
||||
return std::string(baseName) + std::string(extension);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FileUtils::dirname(const char* path)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
char* pathCopy = strdup(path);
|
||||
std::string dirname = ::dirname(pathCopy);
|
||||
free(pathCopy);
|
||||
return dirname;
|
||||
#else
|
||||
char drive[3];
|
||||
char dir[MAX_PATH];
|
||||
|
||||
_splitpath_s(path,
|
||||
drive, /* drive */
|
||||
3, /* drive length */
|
||||
dir,
|
||||
MAX_PATH, /* dir length */
|
||||
0, /* filename */
|
||||
0, /* filename length */
|
||||
0, /* extension */
|
||||
0 /* extension length */
|
||||
);
|
||||
|
||||
std::string result;
|
||||
if (drive[0])
|
||||
{
|
||||
result += std::string(drive);
|
||||
}
|
||||
result += dir;
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::touch(const char* path) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
// see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/touch.html
|
||||
//
|
||||
// we use utimes/futimes instead of utimensat/futimens for compatibility
|
||||
// with older Linux and Mac
|
||||
|
||||
if (fileExists(path))
|
||||
{
|
||||
utimes(path,0 /* use current date/time */);
|
||||
}
|
||||
else
|
||||
{
|
||||
int fd = creat(path,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if (fd != -1)
|
||||
{
|
||||
futimes(fd,0 /* use current date/time */);
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw IOException("Unable to touch file " + std::string(path));
|
||||
}
|
||||
}
|
||||
#else
|
||||
HANDLE result = CreateFile(path,GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0);
|
||||
if (result == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw IOException("Unable to touch file " + std::string(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseHandle(result);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::rmdirRecursive(const char* path) throw (IOException)
|
||||
{
|
||||
// remove dir contents
|
||||
DirIterator dir(path);
|
||||
while (dir.next())
|
||||
{
|
||||
std::string name = dir.fileName();
|
||||
if (name != "." && name != "..")
|
||||
{
|
||||
if (dir.isDir())
|
||||
{
|
||||
rmdir(dir.filePath().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
removeFile(dir.filePath().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the directory itself
|
||||
rmdir(path);
|
||||
}
|
||||
|
||||
std::string FileUtils::canonicalPath(const char* path)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
// on Linux and Mac OS 10.6, realpath() can allocate the required
|
||||
// amount of memory automatically, however Mac OS 10.5 does not support
|
||||
// this, so we used a fixed-sized buffer on all platforms
|
||||
char canonicalPathBuffer[PATH_MAX+1];
|
||||
if (realpath(path,canonicalPathBuffer) != 0)
|
||||
{
|
||||
return std::string(canonicalPathBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw IOException("Error reading canonical path for " + std::string(path));
|
||||
}
|
||||
#else
|
||||
throw IOException("canonicalPath() not implemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FileUtils::toWindowsPathSeparators(const std::string& str)
|
||||
{
|
||||
std::string result = str;
|
||||
std::replace(result.begin(),result.end(),'/','\\');
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string FileUtils::toUnixPathSeparators(const std::string& str)
|
||||
{
|
||||
std::string result = str;
|
||||
std::replace(result.begin(),result.end(),'\\','/');
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string FileUtils::tempPath()
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
std::string tmpDir(notNullString(getenv("TMPDIR")));
|
||||
if (tmpDir.empty())
|
||||
{
|
||||
tmpDir = "/tmp";
|
||||
}
|
||||
return tmpDir;
|
||||
#else
|
||||
char buffer[MAX_PATH+1];
|
||||
GetTempPath(MAX_PATH+1,buffer);
|
||||
return toUnixPathSeparators(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool startsWithDriveLetter(const char* path)
|
||||
{
|
||||
return strlen(path) >= 2 &&
|
||||
(isalpha(path[0])) &&
|
||||
path[1] == ':';
|
||||
}
|
||||
|
||||
bool FileUtils::isRelative(const char* path)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
return strlen(path) == 0 || path[0] != '/';
|
||||
#else
|
||||
// on Windows, a path is relative if it does not start with:
|
||||
// - '\\' (a UNC name)
|
||||
// - '[Drive Letter]:\'
|
||||
// - A single backslash
|
||||
//
|
||||
// the input path is assumed to have already been converted to use
|
||||
// Unix-style path separators
|
||||
|
||||
std::string pathStr(path);
|
||||
|
||||
if ((!pathStr.empty() && pathStr.at(0) == '/') ||
|
||||
(startsWith(pathStr,"//")) ||
|
||||
(startsWithDriveLetter(pathStr.c_str())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileUtils::writeFile(const char* path, const char* data, int length) throw (IOException)
|
||||
{
|
||||
std::ofstream stream(path,std::ios::binary | std::ios::trunc);
|
||||
stream.write(data,length);
|
||||
}
|
||||
|
||||
std::string FileUtils::readFile(const char* path) throw (IOException)
|
||||
{
|
||||
std::ifstream inputFile(path, std::ios::in | std::ios::binary);
|
||||
std::string content;
|
||||
inputFile.seekg(0, std::ios::end);
|
||||
content.resize(static_cast<unsigned int>(inputFile.tellg()));
|
||||
inputFile.seekg(0, std::ios::beg);
|
||||
inputFile.read(&content[0], static_cast<int>(content.size()));
|
||||
return content;
|
||||
}
|
||||
|
||||
void FileUtils::copyFile(const char* src, const char* dest) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
std::ifstream inputFile(src,std::ios::binary);
|
||||
std::ofstream outputFile(dest,std::ios::binary | std::ios::trunc);
|
||||
|
||||
if (!inputFile.good())
|
||||
{
|
||||
throw IOException("Failed to read file " + std::string(src));
|
||||
}
|
||||
if (!outputFile.good())
|
||||
{
|
||||
throw IOException("Failed to write file " + std::string(dest));
|
||||
}
|
||||
|
||||
outputFile << inputFile.rdbuf();
|
||||
|
||||
if (inputFile.bad())
|
||||
{
|
||||
throw IOException("Error reading file " + std::string(src));
|
||||
}
|
||||
if (outputFile.bad())
|
||||
{
|
||||
throw IOException("Error writing file " + std::string(dest));
|
||||
}
|
||||
|
||||
chmod(dest,fileMode(src));
|
||||
#else
|
||||
if (!CopyFile(src,dest,FALSE))
|
||||
{
|
||||
throw IOException("Failed to copy " + std::string(src) + " to " + std::string(dest));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FileUtils::makeAbsolute(const char* path, const char* basePath)
|
||||
{
|
||||
if (isRelative(path))
|
||||
{
|
||||
assert(!isRelative(basePath));
|
||||
return std::string(basePath) + '/' + std::string(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
void FileUtils::chdir(const char* path) throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
if (::chdir(path) != 0)
|
||||
{
|
||||
throw FileUtils::IOException("Unable to change directory");
|
||||
}
|
||||
#else
|
||||
if (!SetCurrentDirectory(path))
|
||||
{
|
||||
throw FileUtils::IOException("Unable to change directory");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string FileUtils::getcwd() throw (IOException)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
char path[PATH_MAX];
|
||||
if (!::getcwd(path,PATH_MAX))
|
||||
{
|
||||
throw FileUtils::IOException("Failed to get current directory");
|
||||
}
|
||||
return std::string(path);
|
||||
#else
|
||||
char path[MAX_PATH];
|
||||
if (GetCurrentDirectory(MAX_PATH,path) == 0)
|
||||
{
|
||||
throw FileUtils::IOException("Failed to get current directory");
|
||||
}
|
||||
return toUnixPathSeparators(std::string(path));
|
||||
#endif
|
||||
}
|
||||
|
141
mmc_updater/src/FileUtils.h
Normal file
141
mmc_updater/src/FileUtils.h
Normal file
@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
|
||||
/** A set of functions for performing common operations
|
||||
* on files, throwing exceptions if an operation fails.
|
||||
*
|
||||
* Path arguments to FileUtils functions should use Unix-style path
|
||||
* separators.
|
||||
*/
|
||||
class FileUtils
|
||||
{
|
||||
public:
|
||||
/** Base class for exceptions reported by
|
||||
* FileUtils methods if an operation fails.
|
||||
*/
|
||||
class IOException : public std::exception
|
||||
{
|
||||
public:
|
||||
IOException(const std::string& error);
|
||||
IOException(int errorCode, const std::string& error);
|
||||
|
||||
virtual ~IOException() throw ();
|
||||
|
||||
enum Type
|
||||
{
|
||||
NoError,
|
||||
/** Unknown error type. Call what() to get the description
|
||||
* provided by the OS.
|
||||
*/
|
||||
Unknown,
|
||||
ReadOnlyFileSystem,
|
||||
DiskFull
|
||||
};
|
||||
|
||||
virtual const char* what() const throw ()
|
||||
{
|
||||
return m_error.c_str();
|
||||
}
|
||||
|
||||
Type type() const;
|
||||
|
||||
private:
|
||||
void init(int errorCode, const std::string& error);
|
||||
|
||||
std::string m_error;
|
||||
int m_errorCode;
|
||||
};
|
||||
|
||||
/** Remove a file. Throws an exception if the file
|
||||
* could not be removed.
|
||||
*
|
||||
* On Unix, a file can be removed even if it is in use if the user
|
||||
* has the necessary permissions. removeFile() tries to simulate
|
||||
* this behavior on Windows. If a file cannot be removed on Windows
|
||||
* because it is in use it will be moved to a temporary directory and
|
||||
* scheduled for deletion on the next restart.
|
||||
*/
|
||||
static void removeFile(const char* src) throw (IOException);
|
||||
|
||||
/** Set the permissions of a file. @p permissions uses the standard
|
||||
* Unix mode_t values.
|
||||
*/
|
||||
static void chmod(const char* path, int permissions) throw (IOException);
|
||||
|
||||
/** Returns true if the file at @p path exists. If @p path is a symlink,
|
||||
* returns true if the symlink itself exists, not the target.
|
||||
*/
|
||||
static bool fileExists(const char* path) throw (IOException);
|
||||
|
||||
/** Returns the Unix mode flags of @p path. If @p path is a symlink,
|
||||
* returns the mode flags of the target.
|
||||
*/
|
||||
static int fileMode(const char* path) throw (IOException);
|
||||
|
||||
static void moveFile(const char* src, const char* dest) throw (IOException);
|
||||
static void mkdir(const char* dir) throw (IOException);
|
||||
static void rmdir(const char* dir) throw (IOException);
|
||||
static void createSymLink(const char* link, const char* target) throw (IOException);
|
||||
static void touch(const char* path) throw (IOException);
|
||||
static void copyFile(const char* src, const char* dest) throw (IOException);
|
||||
|
||||
/** Create all the directories in @p path which do not yet exist.
|
||||
* @p path may be relative or absolute.
|
||||
*/
|
||||
static void mkpath(const char* path) throw (IOException);
|
||||
|
||||
/** Returns the file name part of a file path, including the extension. */
|
||||
static std::string fileName(const char* path);
|
||||
|
||||
/** Returns the directory part of a file path.
|
||||
* On Windows this includes the drive letter, if present in @p path.
|
||||
*/
|
||||
static std::string dirname(const char* path);
|
||||
|
||||
/** Remove a directory and all of its contents. */
|
||||
static void rmdirRecursive(const char* dir) throw (IOException);
|
||||
|
||||
/** Return the full, absolute path to a file, resolving any
|
||||
* symlinks and removing redundant sections.
|
||||
*/
|
||||
static std::string canonicalPath(const char* path);
|
||||
|
||||
/** Returns the path to a directory for storing temporary files. */
|
||||
static std::string tempPath();
|
||||
|
||||
/** Returns a copy of the path 'str' with Windows-style '\'
|
||||
* dir separators converted to Unix-style '/' separators
|
||||
*/
|
||||
static std::string toUnixPathSeparators(const std::string& str);
|
||||
|
||||
static std::string toWindowsPathSeparators(const std::string& str);
|
||||
|
||||
/** Returns true if the provided path is relative.
|
||||
* Or false if absolute.
|
||||
*/
|
||||
static bool isRelative(const char* path);
|
||||
|
||||
/** Converts @p path to an absolute path. If @p path is already absolute,
|
||||
* just returns @p path, otherwise prefixes it with @p basePath to make it absolute.
|
||||
*
|
||||
* @p basePath should be absolute.
|
||||
*/
|
||||
static std::string makeAbsolute(const char* path, const char* basePath);
|
||||
|
||||
static void writeFile(const char* path, const char* data, int length) throw (IOException);
|
||||
|
||||
static std::string readFile(const char* path) throw (IOException);
|
||||
|
||||
/** Changes the current working directory to @p path */
|
||||
static void chdir(const char* path) throw (IOException);
|
||||
|
||||
/** Returns the current working directory of the application. */
|
||||
static std::string getcwd() throw (IOException);
|
||||
};
|
||||
|
65
mmc_updater/src/Log.cpp
Normal file
65
mmc_updater/src/Log.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include "Log.h"
|
||||
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
#include "ProcessUtils.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
|
||||
Log m_globalLog;
|
||||
|
||||
Log* Log::instance()
|
||||
{
|
||||
return &m_globalLog;
|
||||
}
|
||||
|
||||
Log::Log()
|
||||
{
|
||||
}
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
}
|
||||
|
||||
void Log::open(const std::string& path)
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_output.open(path.c_str(),std::ios_base::out | std::ios_base::app);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void Log::writeToStream(std::ostream& stream, Type type, const char* text)
|
||||
{
|
||||
// Multiple processes may be writing to the same log file during
|
||||
// an update. No attempt is made to synchronize access to the file.
|
||||
//
|
||||
// Under Unix, appends to a single file on a local FS by multiple writers should be atomic
|
||||
// provided that the length of 'text' is less than PIPE_BUF
|
||||
//
|
||||
switch (type)
|
||||
{
|
||||
case Info:
|
||||
stream << "INFO ";
|
||||
break;
|
||||
case Warn:
|
||||
stream << "WARN ";
|
||||
break;
|
||||
case Error:
|
||||
stream << "ERROR ";
|
||||
break;
|
||||
}
|
||||
stream << '(' << intToStr(ProcessUtils::currentProcessId()) << ") " << text << std::endl;
|
||||
}
|
||||
|
||||
void Log::write(Type type, const char* text)
|
||||
{
|
||||
m_mutex.lock();
|
||||
writeToStream(std::cerr,type,text);
|
||||
if (m_output.is_open())
|
||||
{
|
||||
writeToStream(m_output,type,text);
|
||||
}
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
46
mmc_updater/src/Log.h
Normal file
46
mmc_updater/src/Log.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Info,
|
||||
Warn,
|
||||
Error
|
||||
};
|
||||
|
||||
Log();
|
||||
~Log();
|
||||
|
||||
void open(const std::string& path);
|
||||
|
||||
/** Write @p text to the log. This method is thread-safe. */
|
||||
void write(Type type, const std::string& text);
|
||||
/** Write @p text to the log. This method is thread-safe. */
|
||||
void write(Type type, const char* text);
|
||||
|
||||
static Log* instance();
|
||||
|
||||
private:
|
||||
static void writeToStream(std::ostream& stream, Type type, const char* text);
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::ofstream m_output;
|
||||
};
|
||||
|
||||
inline void Log::write(Type type, const std::string& text)
|
||||
{
|
||||
write(type,text.c_str());
|
||||
}
|
||||
|
||||
#define LOG(type,text) \
|
||||
Log::instance()->write(Log::type,text)
|
||||
|
||||
|
53
mmc_updater/src/MacBundle.cpp
Normal file
53
mmc_updater/src/MacBundle.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "MacBundle.h"
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "Log.h"
|
||||
|
||||
MacBundle::MacBundle(const std::string& path, const std::string& appName)
|
||||
: m_appName(appName)
|
||||
{
|
||||
m_path = path + '/' + appName + ".app";
|
||||
}
|
||||
|
||||
std::string MacBundle::bundlePath() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
void MacBundle::create(const std::string& infoPlist,
|
||||
const std::string& icon,
|
||||
const std::string& exePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// create the bundle directories
|
||||
FileUtils::mkpath(m_path.c_str());
|
||||
|
||||
std::string contentDir = m_path + "/Contents";
|
||||
std::string resourceDir = contentDir + "/Resources";
|
||||
std::string binDir = contentDir + "/MacOS";
|
||||
|
||||
FileUtils::mkpath(resourceDir.c_str());
|
||||
FileUtils::mkpath(binDir.c_str());
|
||||
|
||||
// create the Contents/Info.plist file
|
||||
FileUtils::writeFile((contentDir + "/Info.plist").c_str(),infoPlist.c_str(),static_cast<int>(infoPlist.size()));
|
||||
|
||||
// save the icon to Contents/Resources/<appname>.icns
|
||||
FileUtils::writeFile((resourceDir + '/' + m_appName + ".icns").c_str(),icon.c_str(),static_cast<int>(icon.size()));
|
||||
|
||||
// copy the app binary to Contents/MacOS/<appname>
|
||||
m_exePath = binDir + '/' + m_appName;
|
||||
FileUtils::copyFile(exePath.c_str(),m_exePath.c_str());
|
||||
}
|
||||
catch (const FileUtils::IOException& exception)
|
||||
{
|
||||
LOG(Error,"Unable to create app bundle. " + std::string(exception.what()));
|
||||
}
|
||||
}
|
||||
|
||||
std::string MacBundle::executablePath() const
|
||||
{
|
||||
return m_exePath;
|
||||
}
|
||||
|
35
mmc_updater/src/MacBundle.h
Normal file
35
mmc_updater/src/MacBundle.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
/** Class for creating minimal Mac app bundles. */
|
||||
class MacBundle
|
||||
{
|
||||
public:
|
||||
/** Create a MacBundle instance representing the bundle
|
||||
* in <path>/<appName>.app
|
||||
*/
|
||||
MacBundle(const std::string& path, const std::string& appName);
|
||||
|
||||
/** Create a simple Mac bundle.
|
||||
*
|
||||
* @param infoPlist The content of the Info.plist file
|
||||
* @param icon The content of the app icon
|
||||
* @param exePath The path of the file to use for the main app in the bundle.
|
||||
*/
|
||||
void create(const std::string& infoPlist,
|
||||
const std::string& icon,
|
||||
const std::string& exePath);
|
||||
|
||||
/** Returns the path of the main executable within the Mac bundle. */
|
||||
std::string executablePath() const;
|
||||
|
||||
/** Returns the path of the bundle */
|
||||
std::string bundlePath() const;
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
std::string m_appName;
|
||||
std::string m_exePath;
|
||||
};
|
||||
|
32
mmc_updater/src/Platform.h
Normal file
32
mmc_updater/src/Platform.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
// basic platform defines
|
||||
#ifdef __linux__
|
||||
#define PLATFORM_LINUX
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define PLATFORM_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
// disable warnings about exception specifications,
|
||||
// which are not implemented in Visual C++
|
||||
#pragma warning(disable:4290)
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define PLATFORM_MAC
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_LINUX) || defined(PLATFORM_MAC)
|
||||
#define PLATFORM_UNIX
|
||||
#endif
|
||||
|
||||
// platform-specific type aliases
|
||||
#if defined(PLATFORM_UNIX)
|
||||
#define PLATFORM_PID pid_t
|
||||
#else
|
||||
#define PLATFORM_PID DWORD
|
||||
#endif
|
536
mmc_updater/src/ProcessUtils.cpp
Normal file
536
mmc_updater/src/ProcessUtils.cpp
Normal file
@ -0,0 +1,536 @@
|
||||
#include "ProcessUtils.h"
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "Platform.h"
|
||||
#include "StringUtils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_MAC
|
||||
#include <Security/Security.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
PLATFORM_PID ProcessUtils::currentProcessId()
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
return getpid();
|
||||
#else
|
||||
return GetCurrentProcessId();
|
||||
#endif
|
||||
}
|
||||
|
||||
int ProcessUtils::runSync(const std::string& executable,
|
||||
const std::list<std::string>& args)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
return runSyncUnix(executable,args);
|
||||
#else
|
||||
return runWindows(executable,args,RunSync);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
int ProcessUtils::runSyncUnix(const std::string& executable,
|
||||
const std::list<std::string>& args)
|
||||
{
|
||||
PLATFORM_PID pid = runAsyncUnix(executable,args);
|
||||
int status = 0;
|
||||
if (waitpid(pid,&status,0) != -1)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
return static_cast<char>(WEXITSTATUS(status));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warn,"Child exited abnormally");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warn,"Failed to get exit status of child " + intToStr(pid));
|
||||
return WaitFailed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ProcessUtils::runAsync(const std::string& executable,
|
||||
const std::list<std::string>& args)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
runWindows(executable,args,RunAsync);
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
runAsyncUnix(executable,args);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ProcessUtils::runElevated(const std::string& executable,
|
||||
const std::list<std::string>& args,
|
||||
const std::string& task)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
(void)task;
|
||||
return runElevatedWindows(executable,args);
|
||||
#elif defined(PLATFORM_MAC)
|
||||
(void)task;
|
||||
return runElevatedMac(executable,args);
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
return runElevatedLinux(executable,args,task);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ProcessUtils::waitForProcess(PLATFORM_PID pid)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
pid_t result = ::waitpid(pid, 0, 0);
|
||||
if (result < 0)
|
||||
{
|
||||
LOG(Error,"waitpid() failed with error: " + std::string(strerror(errno)));
|
||||
}
|
||||
return result > 0;
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
HANDLE hProc;
|
||||
|
||||
if (!(hProc = OpenProcess(SYNCHRONIZE, FALSE, pid)))
|
||||
{
|
||||
LOG(Error,"Unable to get process handle for pid " + intToStr(pid) + " last error " + intToStr(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwRet = WaitForSingleObject(hProc, INFINITE);
|
||||
CloseHandle(hProc);
|
||||
|
||||
if (dwRet == WAIT_FAILED)
|
||||
{
|
||||
LOG(Error,"WaitForSingleObject failed with error " + intToStr(GetLastError()));
|
||||
}
|
||||
|
||||
return (dwRet == WAIT_OBJECT_0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_LINUX
|
||||
int ProcessUtils::runElevatedLinux(const std::string& executable,
|
||||
const std::list<std::string>& args,
|
||||
const std::string& _task)
|
||||
{
|
||||
std::string task(_task);
|
||||
if (task.empty())
|
||||
{
|
||||
task = FileUtils::fileName(executable.c_str());
|
||||
}
|
||||
|
||||
// try available graphical sudo instances until we find one that works.
|
||||
// The different sudo front-ends have different behaviors with respect to error codes:
|
||||
//
|
||||
// - 'kdesudo': return 1 if the user enters the wrong password 3 times or if
|
||||
// they cancel elevation
|
||||
//
|
||||
// - recent 'gksudo' versions: return 1 if the user enters the wrong password
|
||||
// : return -1 if the user cancels elevation
|
||||
//
|
||||
// - older 'gksudo' versions : return 0 if the user cancels elevation
|
||||
|
||||
std::vector<std::string> sudos;
|
||||
|
||||
if (getenv("KDE_SESSION_VERSION"))
|
||||
{
|
||||
sudos.push_back("kdesudo");
|
||||
}
|
||||
sudos.push_back("gksudo");
|
||||
|
||||
for (unsigned int i=0; i < sudos.size(); i++)
|
||||
{
|
||||
const std::string& sudoBinary = sudos.at(i);
|
||||
|
||||
std::list<std::string> sudoArgs;
|
||||
sudoArgs.push_back("-u");
|
||||
sudoArgs.push_back("root");
|
||||
|
||||
if (sudoBinary == "kdesudo")
|
||||
{
|
||||
sudoArgs.push_back("-d");
|
||||
sudoArgs.push_back("--comment");
|
||||
std::string sudoMessage = task + " needs administrative privileges. Please enter your password.";
|
||||
sudoArgs.push_back(sudoMessage);
|
||||
}
|
||||
else if (sudoBinary == "gksudo")
|
||||
{
|
||||
sudoArgs.push_back("--description");
|
||||
sudoArgs.push_back(task);
|
||||
}
|
||||
else
|
||||
{
|
||||
sudoArgs.push_back(task);
|
||||
}
|
||||
|
||||
sudoArgs.push_back("--");
|
||||
sudoArgs.push_back(executable);
|
||||
std::copy(args.begin(),args.end(),std::back_inserter(sudoArgs));
|
||||
|
||||
int result = ProcessUtils::runSync(sudoBinary,sudoArgs);
|
||||
|
||||
LOG(Info,"Tried to use sudo " + sudoBinary + " with response " + intToStr(result));
|
||||
|
||||
if (result != RunFailed)
|
||||
{
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return RunElevatedFailed;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_MAC
|
||||
int ProcessUtils::runElevatedMac(const std::string& executable,
|
||||
const std::list<std::string>& args)
|
||||
{
|
||||
// request elevation using the Security Service.
|
||||
//
|
||||
// This only works when the application is being run directly
|
||||
// from the Mac. Attempting to run the app via a remote SSH session
|
||||
// (for example) will fail with an interaction-not-allowed error
|
||||
|
||||
OSStatus status;
|
||||
AuthorizationRef authorizationRef;
|
||||
|
||||
status = AuthorizationCreate(
|
||||
NULL,
|
||||
kAuthorizationEmptyEnvironment,
|
||||
kAuthorizationFlagDefaults,
|
||||
&authorizationRef);
|
||||
|
||||
AuthorizationItem right = { kAuthorizationRightExecute, 0, NULL, 0 };
|
||||
AuthorizationRights rights = { 1, &right };
|
||||
|
||||
AuthorizationFlags flags = kAuthorizationFlagDefaults |
|
||||
kAuthorizationFlagInteractionAllowed |
|
||||
kAuthorizationFlagPreAuthorize |
|
||||
kAuthorizationFlagExtendRights;
|
||||
|
||||
if (status == errAuthorizationSuccess)
|
||||
{
|
||||
status = AuthorizationCopyRights(authorizationRef, &rights, NULL,
|
||||
flags, NULL);
|
||||
|
||||
if (status == errAuthorizationSuccess)
|
||||
{
|
||||
char** argv;
|
||||
argv = (char**) malloc(sizeof(char*) * args.size() + 1);
|
||||
|
||||
unsigned int i = 0;
|
||||
for (std::list<std::string>::const_iterator iter = args.begin(); iter != args.end(); iter++)
|
||||
{
|
||||
argv[i] = strdup(iter->c_str());
|
||||
++i;
|
||||
}
|
||||
argv[i] = NULL;
|
||||
|
||||
FILE* pipe = NULL;
|
||||
|
||||
char* tool = strdup(executable.c_str());
|
||||
|
||||
status = AuthorizationExecuteWithPrivileges(authorizationRef, tool,
|
||||
kAuthorizationFlagDefaults, argv, &pipe);
|
||||
|
||||
if (status == errAuthorizationSuccess)
|
||||
{
|
||||
// AuthorizationExecuteWithPrivileges does not provide a way to get the process ID
|
||||
// of the child process.
|
||||
//
|
||||
// Discussions on Apple development forums suggest two approaches for working around this,
|
||||
//
|
||||
// - Modify the child process to sent its process ID back to the parent via
|
||||
// the pipe passed to AuthorizationExecuteWithPrivileges.
|
||||
//
|
||||
// - Use the generic Unix wait() call.
|
||||
//
|
||||
// This code uses wait(), which is simpler, but suffers from the problem that wait() waits
|
||||
// for any child process, not necessarily the specific process launched
|
||||
// by AuthorizationExecuteWithPrivileges.
|
||||
//
|
||||
// Apple's documentation (see 'Authorization Services Programming Guide') suggests
|
||||
// installing files in an installer as a legitimate use for
|
||||
// AuthorizationExecuteWithPrivileges but in general strongly recommends
|
||||
// not using this call and discusses a number of other alternatives
|
||||
// for performing privileged operations,
|
||||
// which we could consider in future.
|
||||
|
||||
int childStatus;
|
||||
pid_t childPid = wait(&childStatus);
|
||||
|
||||
if (childStatus != 0)
|
||||
{
|
||||
LOG(Error,"elevated process failed with status " + intToStr(childStatus) + " pid "
|
||||
+ intToStr(childPid));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Info,"elevated process succeded with pid " + intToStr(childPid));
|
||||
}
|
||||
|
||||
return childStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Error,"failed to launch elevated process " + intToStr(status));
|
||||
return RunElevatedFailed;
|
||||
}
|
||||
|
||||
// If we want to know more information about what has happened:
|
||||
// http://developer.apple.com/mac/library/documentation/Security/Reference/authorization_ref/Reference/reference.html#//apple_ref/doc/uid/TP30000826-CH4g-CJBEABHG
|
||||
free(tool);
|
||||
for (i = 0; i < args.size(); i++)
|
||||
{
|
||||
free(argv[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Error,"failed to get rights to launch elevated process. status: " + intToStr(status));
|
||||
return RunElevatedFailed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return RunElevatedFailed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// convert a list of arguments in a space-separated string.
|
||||
// Arguments containing spaces are enclosed in quotes
|
||||
std::string quoteArgs(const std::list<std::string>& arguments)
|
||||
{
|
||||
std::string quotedArgs;
|
||||
for (std::list<std::string>::const_iterator iter = arguments.begin();
|
||||
iter != arguments.end();
|
||||
iter++)
|
||||
{
|
||||
std::string arg = *iter;
|
||||
|
||||
bool isQuoted = !arg.empty() &&
|
||||
arg.at(0) == '"' &&
|
||||
arg.at(arg.size()-1) == '"';
|
||||
|
||||
if (!isQuoted && arg.find(' ') != std::string::npos)
|
||||
{
|
||||
arg.insert(0,"\"");
|
||||
arg.append("\"");
|
||||
}
|
||||
quotedArgs += arg;
|
||||
quotedArgs += " ";
|
||||
}
|
||||
return quotedArgs;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
int ProcessUtils::runElevatedWindows(const std::string& executable,
|
||||
const std::list<std::string>& arguments)
|
||||
{
|
||||
std::string args = quoteArgs(arguments);
|
||||
|
||||
SHELLEXECUTEINFO executeInfo;
|
||||
ZeroMemory(&executeInfo,sizeof(executeInfo));
|
||||
executeInfo.cbSize = sizeof(SHELLEXECUTEINFO);
|
||||
executeInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
// request UAC elevation
|
||||
executeInfo.lpVerb = "runas";
|
||||
executeInfo.lpFile = executable.c_str();
|
||||
executeInfo.lpParameters = args.c_str();
|
||||
executeInfo.nShow = SW_SHOWNORMAL;
|
||||
|
||||
LOG(Info,"Attempting to execute " + executable + " with administrator priviledges");
|
||||
if (!ShellExecuteEx(&executeInfo))
|
||||
{
|
||||
LOG(Error,"Failed to start with admin priviledges using ShellExecuteEx()");
|
||||
return RunElevatedFailed;
|
||||
}
|
||||
|
||||
WaitForSingleObject(executeInfo.hProcess, INFINITE);
|
||||
|
||||
// this assumes the process succeeded - we need to check whether
|
||||
// this is actually the case.
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
PLATFORM_PID ProcessUtils::runAsyncUnix(const std::string& executable,
|
||||
const std::list<std::string>& args)
|
||||
{
|
||||
pid_t child = fork();
|
||||
if (child == 0)
|
||||
{
|
||||
// in child process
|
||||
char** argBuffer = new char*[args.size() + 2];
|
||||
argBuffer[0] = strdup(executable.c_str());
|
||||
int i = 1;
|
||||
for (std::list<std::string>::const_iterator iter = args.begin(); iter != args.end(); iter++)
|
||||
{
|
||||
argBuffer[i] = strdup(iter->c_str());
|
||||
++i;
|
||||
}
|
||||
argBuffer[i] = 0;
|
||||
|
||||
if (execvp(executable.c_str(),argBuffer) == -1)
|
||||
{
|
||||
LOG(Error,"error starting child: " + std::string(strerror(errno)));
|
||||
exit(RunFailed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Info,"Started child process " + intToStr(child));
|
||||
}
|
||||
return child;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
int ProcessUtils::runWindows(const std::string& _executable,
|
||||
const std::list<std::string>& _args,
|
||||
RunMode runMode)
|
||||
{
|
||||
// most Windows API functions allow back and forward slashes to be
|
||||
// used interchangeably. However, an application started with
|
||||
// CreateProcess() may fail to find Side-by-Side library dependencies
|
||||
// in the same directory as the executable if forward slashes are
|
||||
// used as path separators, so convert the path to use back slashes here.
|
||||
//
|
||||
// This may be related to LoadLibrary() requiring backslashes instead
|
||||
// of forward slashes.
|
||||
std::string executable = FileUtils::toWindowsPathSeparators(_executable);
|
||||
|
||||
std::list<std::string> args(_args);
|
||||
args.push_front(executable);
|
||||
std::string commandLine = quoteArgs(args);
|
||||
|
||||
STARTUPINFO startupInfo;
|
||||
ZeroMemory(&startupInfo,sizeof(startupInfo));
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
PROCESS_INFORMATION processInfo;
|
||||
ZeroMemory(&processInfo,sizeof(processInfo));
|
||||
|
||||
char* commandLineStr = strdup(commandLine.c_str());
|
||||
bool result = CreateProcess(
|
||||
executable.c_str(),
|
||||
commandLineStr,
|
||||
0 /* process attributes */,
|
||||
0 /* thread attributes */,
|
||||
false /* inherit handles */,
|
||||
NORMAL_PRIORITY_CLASS /* creation flags */,
|
||||
0 /* environment */,
|
||||
0 /* current directory */,
|
||||
&startupInfo /* startup info */,
|
||||
&processInfo /* process information */
|
||||
);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG(Error,"Failed to start child process. " + executable + " Last error: " + intToStr(GetLastError()));
|
||||
return RunFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (runMode == RunSync)
|
||||
{
|
||||
if (WaitForSingleObject(processInfo.hProcess,INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
DWORD status = WaitFailed;
|
||||
if (GetExitCodeProcess(processInfo.hProcess,&status) != 0)
|
||||
{
|
||||
LOG(Error,"Failed to get exit code for process");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Error,"Failed to wait for process to finish");
|
||||
return WaitFailed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// process is being run asynchronously - return zero as if it had
|
||||
// succeeded
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string ProcessUtils::currentProcessPath()
|
||||
{
|
||||
#ifdef PLATFORM_LINUX
|
||||
std::string path = FileUtils::canonicalPath("/proc/self/exe");
|
||||
LOG(Info,"Current process path " + path);
|
||||
return path;
|
||||
#elif defined(PLATFORM_MAC)
|
||||
uint32_t bufferSize = PATH_MAX;
|
||||
char buffer[bufferSize];
|
||||
_NSGetExecutablePath(buffer,&bufferSize);
|
||||
return buffer;
|
||||
#else
|
||||
char fileName[MAX_PATH];
|
||||
GetModuleFileName(0 /* get path of current process */,fileName,MAX_PATH);
|
||||
return fileName;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
void ProcessUtils::convertWindowsCommandLine(LPCWSTR commandLine, int& argc, char**& argv)
|
||||
{
|
||||
argc = 0;
|
||||
LPWSTR* argvUnicode = CommandLineToArgvW(commandLine,&argc);
|
||||
|
||||
argv = new char*[argc];
|
||||
for (int i=0; i < argc; i++)
|
||||
{
|
||||
const int BUFFER_SIZE = 4096;
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
int length = WideCharToMultiByte(CP_ACP,
|
||||
0 /* flags */,
|
||||
argvUnicode[i],
|
||||
-1, /* argvUnicode is null terminated */
|
||||
buffer,
|
||||
BUFFER_SIZE,
|
||||
0,
|
||||
false);
|
||||
|
||||
// note: if WideCharToMultiByte() fails it will return zero,
|
||||
// in which case we store a zero-length argument in argv
|
||||
if (length == 0)
|
||||
{
|
||||
argv[i] = new char[1];
|
||||
argv[i][0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the input string to WideCharToMultiByte is null-terminated,
|
||||
// the output is also null-terminated
|
||||
argv[i] = new char[length];
|
||||
strncpy(argv[i],buffer,length);
|
||||
}
|
||||
}
|
||||
LocalFree(argvUnicode);
|
||||
}
|
||||
#endif
|
||||
|
97
mmc_updater/src/ProcessUtils.h
Normal file
97
mmc_updater/src/ProcessUtils.h
Normal file
@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
/** A set of functions to get information about the current
|
||||
* process and launch new processes.
|
||||
*/
|
||||
class ProcessUtils
|
||||
{
|
||||
public:
|
||||
enum Errors
|
||||
{
|
||||
/** Status code returned by runElevated() if launching
|
||||
* the elevated process fails.
|
||||
*/
|
||||
RunElevatedFailed = 255,
|
||||
/** Status code returned by runSync() if the application
|
||||
* cannot be started.
|
||||
*/
|
||||
RunFailed = -8,
|
||||
/** Status code returned by runSync() if waiting for
|
||||
* the application to exit and reading its status code fails.
|
||||
*/
|
||||
WaitFailed = -1
|
||||
};
|
||||
|
||||
static PLATFORM_PID currentProcessId();
|
||||
|
||||
/** Returns the absolute path to the main binary for
|
||||
* the current process.
|
||||
*/
|
||||
static std::string currentProcessPath();
|
||||
|
||||
/** Start a process and wait for it to finish before
|
||||
* returning its exit code.
|
||||
*
|
||||
* Returns -1 if the process cannot be started.
|
||||
*/
|
||||
static int runSync(const std::string& executable,
|
||||
const std::list<std::string>& args);
|
||||
|
||||
/** Start a process and return without waiting for
|
||||
* it to finish.
|
||||
*/
|
||||
static void runAsync(const std::string& executable,
|
||||
const std::list<std::string>& args);
|
||||
|
||||
/** Run a process with administrative privileges and return the
|
||||
* status code of the process, or 0 on Windows.
|
||||
*
|
||||
* Returns RunElevatedFailed if the elevated process could
|
||||
* not be started.
|
||||
*/
|
||||
static int runElevated(const std::string& executable,
|
||||
const std::list<std::string>& args,
|
||||
const std::string& task);
|
||||
|
||||
/** Wait for a process to exit.
|
||||
* Returns true if the process was found and has exited or false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool waitForProcess(PLATFORM_PID pid);
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
/** Convert a unicode command line returned by GetCommandLineW()
|
||||
* to a standard (argc,argv) pair. The resulting argv array and each
|
||||
* element of argv must be freed using free()
|
||||
*/
|
||||
static void convertWindowsCommandLine(LPCWSTR commandLine, int& argc, char**& argv);
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum RunMode
|
||||
{
|
||||
RunSync,
|
||||
RunAsync
|
||||
};
|
||||
static int runElevatedLinux(const std::string& executable,
|
||||
const std::list<std::string>& args,
|
||||
const std::string& task);
|
||||
static int runElevatedMac(const std::string& executable,
|
||||
const std::list<std::string>& args);
|
||||
static int runElevatedWindows(const std::string& executable,
|
||||
const std::list<std::string>& args);
|
||||
|
||||
static PLATFORM_PID runAsyncUnix(const std::string& executable,
|
||||
const std::list<std::string>& args);
|
||||
static int runWindows(const std::string& executable,
|
||||
const std::list<std::string>& args,
|
||||
RunMode runMode);
|
||||
static int runSyncUnix(const std::string& executable,
|
||||
const std::list<std::string>& args);
|
||||
};
|
||||
|
63
mmc_updater/src/StandardDirs.cpp
Normal file
63
mmc_updater/src/StandardDirs.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "StandardDirs.h"
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
std::string StandardDirs::homeDir()
|
||||
{
|
||||
std::string dir = notNullString(getenv("HOME"));
|
||||
if (!dir.empty())
|
||||
{
|
||||
return dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
// note: if this process has been elevated with sudo,
|
||||
// this will return the home directory of the root user
|
||||
struct passwd* userData = getpwuid(getuid());
|
||||
return notNullString(userData->pw_dir);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string StandardDirs::appDataPath(const std::string& organizationName,
|
||||
const std::string& appName)
|
||||
{
|
||||
#ifdef PLATFORM_LINUX
|
||||
std::string xdgDataHome = notNullString(getenv("XDG_DATA_HOME"));
|
||||
if (xdgDataHome.empty())
|
||||
{
|
||||
xdgDataHome = homeDir() + "/.local/share";
|
||||
}
|
||||
xdgDataHome += "/data/" + organizationName + '/' + appName;
|
||||
return xdgDataHome;
|
||||
|
||||
#elif defined(PLATFORM_MAC)
|
||||
std::string path = applicationSupportFolderPath();
|
||||
path += '/' + appName;
|
||||
return path;
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
char buffer[MAX_PATH + 1];
|
||||
if (SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0 /* hToken */, SHGFP_TYPE_CURRENT, buffer) == S_OK)
|
||||
{
|
||||
std::string path = FileUtils::toUnixPathSeparators(notNullString(buffer));
|
||||
path += '/' + organizationName + '/' + appName;
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
#endif
|
||||
}
|
22
mmc_updater/src/StandardDirs.h
Normal file
22
mmc_updater/src/StandardDirs.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class StandardDirs
|
||||
{
|
||||
public:
|
||||
static std::string appDataPath(const std::string& organizationName,
|
||||
const std::string& appName);
|
||||
|
||||
private:
|
||||
#ifdef PLATFORM_UNIX
|
||||
static std::string homeDir();
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_MAC
|
||||
static std::string applicationSupportFolderPath();
|
||||
#endif
|
||||
};
|
||||
|
18
mmc_updater/src/StandardDirs.mm
Normal file
18
mmc_updater/src/StandardDirs.mm
Normal file
@ -0,0 +1,18 @@
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include "StandardDirs.h"
|
||||
|
||||
std::string StandardDirs::applicationSupportFolderPath()
|
||||
{
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
|
||||
NSUserDomainMask,
|
||||
true /* expand tildes */);
|
||||
|
||||
for (unsigned int i=0; i < [paths count]; i++)
|
||||
{
|
||||
NSString* path = [paths objectAtIndex:i];
|
||||
return std::string([path UTF8String]);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
75
mmc_updater/src/StlSymbolsLeopard.cpp
Normal file
75
mmc_updater/src/StlSymbolsLeopard.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// Workarounds for iostream symbols that are referenced when building on OS X 10.7 but missing from
|
||||
// OS X 10.5's stdlibc++.dylib.
|
||||
//
|
||||
// In the <iostream> headers these are declared as extern templates but the symbols are not present under 10.5.
|
||||
// This file forces the compiler to instantiate the templates.
|
||||
//
|
||||
// see http://stackoverflow.com/questions/3484043/os-x-program-runs-on-dev-machine-crashing-horribly-on-others
|
||||
|
||||
#include <iostream>
|
||||
|
||||
_GLIBCXX_BEGIN_NAMESPACE(std)
|
||||
// From ostream_insert.h
|
||||
template ostream& __ostream_insert(ostream&, const char*, streamsize);
|
||||
|
||||
#ifdef _GLIBCXX_USE_WCHAR_T
|
||||
template wostream& __ostream_insert(wostream&, const wchar_t*, streamsize);
|
||||
#endif
|
||||
|
||||
// From ostream.tcc
|
||||
template ostream& ostream::_M_insert(long);
|
||||
template ostream& ostream::_M_insert(unsigned long);
|
||||
template ostream& ostream::_M_insert(bool);
|
||||
#ifdef _GLIBCXX_USE_LONG_LONG
|
||||
template ostream& ostream::_M_insert(long long);
|
||||
template ostream& ostream::_M_insert(unsigned long long);
|
||||
#endif
|
||||
template ostream& ostream::_M_insert(double);
|
||||
template ostream& ostream::_M_insert(long double);
|
||||
template ostream& ostream::_M_insert(const void*);
|
||||
|
||||
#ifdef _GLIBCXX_USE_WCHAR_T
|
||||
template wostream& wostream::_M_insert(long);
|
||||
template wostream& wostream::_M_insert(unsigned long);
|
||||
template wostream& wostream::_M_insert(bool);
|
||||
#ifdef _GLIBCXX_USE_LONG_LONG
|
||||
template wostream& wostream::_M_insert(long long);
|
||||
template wostream& wostream::_M_insert(unsigned long long);
|
||||
#endif
|
||||
template wostream& wostream::_M_insert(double);
|
||||
template wostream& wostream::_M_insert(long double);
|
||||
template wostream& wostream::_M_insert(const void*);
|
||||
#endif
|
||||
|
||||
// From istream.tcc
|
||||
template istream& istream::_M_extract(unsigned short&);
|
||||
template istream& istream::_M_extract(unsigned int&);
|
||||
template istream& istream::_M_extract(long&);
|
||||
template istream& istream::_M_extract(unsigned long&);
|
||||
template istream& istream::_M_extract(bool&);
|
||||
#ifdef _GLIBCXX_USE_LONG_LONG
|
||||
template istream& istream::_M_extract(long long&);
|
||||
template istream& istream::_M_extract(unsigned long long&);
|
||||
#endif
|
||||
template istream& istream::_M_extract(float&);
|
||||
template istream& istream::_M_extract(double&);
|
||||
template istream& istream::_M_extract(long double&);
|
||||
template istream& istream::_M_extract(void*&);
|
||||
|
||||
#ifdef _GLIBCXX_USE_WCHAR_T
|
||||
template wistream& wistream::_M_extract(unsigned short&);
|
||||
template wistream& wistream::_M_extract(unsigned int&);
|
||||
template wistream& wistream::_M_extract(long&);
|
||||
template wistream& wistream::_M_extract(unsigned long&);
|
||||
template wistream& wistream::_M_extract(bool&);
|
||||
#ifdef _GLIBCXX_USE_LONG_LONG
|
||||
template wistream& wistream::_M_extract(long long&);
|
||||
template wistream& wistream::_M_extract(unsigned long long&);
|
||||
#endif
|
||||
template wistream& wistream::_M_extract(float&);
|
||||
template wistream& wistream::_M_extract(double&);
|
||||
template wistream& wistream::_M_extract(long double&);
|
||||
template wistream& wistream::_M_extract(void*&);
|
||||
#endif
|
||||
|
||||
_GLIBCXX_END_NAMESPACE
|
46
mmc_updater/src/StringUtils.h
Normal file
46
mmc_updater/src/StringUtils.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
|
||||
template <class T>
|
||||
inline std::string intToStr(T i)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << i;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
inline bool strToBool(const std::string& str)
|
||||
{
|
||||
return str == "true" || atoi(str.c_str()) != 0;
|
||||
}
|
||||
|
||||
/** Returns @p text if non-null or a pointer
|
||||
* to an empty null-terminated string otherwise.
|
||||
*/
|
||||
inline const char* notNullString(const char* text)
|
||||
{
|
||||
if (text)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
inline bool endsWith(const std::string& str, const char* text)
|
||||
{
|
||||
size_t length = strlen(text);
|
||||
return str.find(text,str.size() - length) != std::string::npos;
|
||||
}
|
||||
|
||||
inline bool startsWith(const std::string& str, const char* text)
|
||||
{
|
||||
return str.find(text,0) == 0;
|
||||
}
|
||||
|
25
mmc_updater/src/UpdateDialog.cpp
Normal file
25
mmc_updater/src/UpdateDialog.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "UpdateDialog.h"
|
||||
|
||||
UpdateDialog::UpdateDialog()
|
||||
: m_autoClose(false)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateDialog::setAutoClose(bool autoClose)
|
||||
{
|
||||
m_autoClose = autoClose;
|
||||
}
|
||||
|
||||
bool UpdateDialog::autoClose() const
|
||||
{
|
||||
return m_autoClose;
|
||||
}
|
||||
|
||||
void UpdateDialog::updateFinished()
|
||||
{
|
||||
if (m_autoClose)
|
||||
{
|
||||
quit();
|
||||
}
|
||||
}
|
||||
|
29
mmc_updater/src/UpdateDialog.h
Normal file
29
mmc_updater/src/UpdateDialog.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "UpdateObserver.h"
|
||||
|
||||
/** Base class for the updater's UI, sub-classed
|
||||
* by the different platform implementations.
|
||||
*/
|
||||
class UpdateDialog : public UpdateObserver
|
||||
{
|
||||
public:
|
||||
UpdateDialog();
|
||||
virtual ~UpdateDialog() {};
|
||||
|
||||
/** Sets whether the updater should automatically
|
||||
* exit once the update has been installed.
|
||||
*/
|
||||
void setAutoClose(bool autoClose);
|
||||
bool autoClose() const;
|
||||
|
||||
virtual void init(int argc, char** argv) = 0;
|
||||
virtual void exec() = 0;
|
||||
virtual void quit() = 0;
|
||||
|
||||
virtual void updateFinished();
|
||||
|
||||
private:
|
||||
bool m_autoClose;
|
||||
};
|
||||
|
70
mmc_updater/src/UpdateDialogAscii.cpp
Normal file
70
mmc_updater/src/UpdateDialogAscii.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "UpdateDialogAscii.h"
|
||||
|
||||
#include "AppInfo.h"
|
||||
#include "ProcessUtils.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
const char* introMessage =
|
||||
"%s (ASCII-art edition)\n"
|
||||
"====================================\n"
|
||||
"\n"
|
||||
"We have a nice graphical interface for the %s, but unfortunately\n"
|
||||
"we can't show it to you :(\n"
|
||||
"\n"
|
||||
"You can fix this by installing the GTK 2 libraries.\n\n"
|
||||
"Installing Updates...\n";
|
||||
|
||||
void UpdateDialogAscii::init(int /* argc */, char** /* argv */)
|
||||
{
|
||||
const char* path = "/tmp/update-progress";
|
||||
m_output.open(path);
|
||||
|
||||
char message[4096];
|
||||
sprintf(message,introMessage,AppInfo::name().c_str());
|
||||
m_output << message;
|
||||
|
||||
std::string command = "xterm";
|
||||
std::list<std::string> args;
|
||||
args.push_back("-hold");
|
||||
args.push_back("-T");
|
||||
args.push_back(AppInfo::name());
|
||||
args.push_back("-e");
|
||||
args.push_back("tail");
|
||||
args.push_back("-n+1");
|
||||
args.push_back("-f");
|
||||
args.push_back(path);
|
||||
|
||||
ProcessUtils::runAsync(command,args);
|
||||
}
|
||||
|
||||
void UpdateDialogAscii::updateError(const std::string& errorMessage)
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_output << "\nThere was a problem installing the update: " << errorMessage << std::endl;
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void UpdateDialogAscii::updateProgress(int percentage)
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_output << "Update Progress: " << intToStr(percentage) << '%' << std::endl;
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void UpdateDialogAscii::updateFinished()
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_output << "\nUpdate Finished. You can now restart " << AppInfo::appName() << "." << std::endl;
|
||||
m_mutex.unlock();
|
||||
|
||||
UpdateDialog::updateFinished();
|
||||
}
|
||||
|
||||
void UpdateDialogAscii::quit()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateDialogAscii::exec()
|
||||
{
|
||||
}
|
||||
|
32
mmc_updater/src/UpdateDialogAscii.h
Normal file
32
mmc_updater/src/UpdateDialogAscii.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "UpdateDialog.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
/** A fallback auto-update progress 'dialog' for use on
|
||||
* Linux when the GTK UI cannot be loaded.
|
||||
*
|
||||
* The 'dialog' consists of an xterm tailing the contents
|
||||
* of a file, into which progress messages are written.
|
||||
*/
|
||||
class UpdateDialogAscii : public UpdateDialog
|
||||
{
|
||||
public:
|
||||
// implements UpdateDialog
|
||||
virtual void init(int argc, char** argv);
|
||||
virtual void exec();
|
||||
virtual void quit();
|
||||
|
||||
// implements UpdateObserver
|
||||
virtual void updateError(const std::string& errorMessage);
|
||||
virtual void updateProgress(int percentage);
|
||||
virtual void updateFinished();
|
||||
|
||||
private:
|
||||
std::mutex m_mutex;
|
||||
std::ofstream m_output;
|
||||
};
|
||||
|
32
mmc_updater/src/UpdateDialogCocoa.h
Normal file
32
mmc_updater/src/UpdateDialogCocoa.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "UpdateDialog.h"
|
||||
#include "UpdateObserver.h"
|
||||
|
||||
class UpdateDialogPrivate;
|
||||
|
||||
class UpdateDialogCocoa : public UpdateDialog
|
||||
{
|
||||
public:
|
||||
UpdateDialogCocoa();
|
||||
~UpdateDialogCocoa();
|
||||
|
||||
// implements UpdateDialog
|
||||
virtual void init(int argc, char** argv);
|
||||
virtual void exec();
|
||||
virtual void quit();
|
||||
|
||||
// implements UpdateObserver
|
||||
virtual void updateError(const std::string& errorMessage);
|
||||
virtual void updateProgress(int percentage);
|
||||
virtual void updateFinished();
|
||||
|
||||
static void* createAutoreleasePool();
|
||||
static void releaseAutoreleasePool(void* data);
|
||||
|
||||
private:
|
||||
void enableDockIcon();
|
||||
|
||||
UpdateDialogPrivate* d;
|
||||
};
|
||||
|
194
mmc_updater/src/UpdateDialogCocoa.mm
Normal file
194
mmc_updater/src/UpdateDialogCocoa.mm
Normal file
@ -0,0 +1,194 @@
|
||||
#include "UpdateDialogCocoa.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include "AppInfo.h"
|
||||
#include "Log.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
@interface UpdateDialogDelegate : NSObject
|
||||
{
|
||||
@public UpdateDialogPrivate* dialog;
|
||||
}
|
||||
- (void) finishClicked;
|
||||
- (void) reportUpdateError:(id)arg;
|
||||
- (void) reportUpdateProgress:(id)arg;
|
||||
- (void) reportUpdateFinished:(id)arg;
|
||||
@end
|
||||
|
||||
class UpdateDialogPrivate
|
||||
{
|
||||
public:
|
||||
UpdateDialogPrivate()
|
||||
: hadError(false)
|
||||
{
|
||||
}
|
||||
|
||||
UpdateDialogDelegate* delegate;
|
||||
NSAutoreleasePool* pool;
|
||||
NSWindow* window;
|
||||
NSButton* finishButton;
|
||||
NSTextField* progressLabel;
|
||||
NSProgressIndicator* progressBar;
|
||||
bool hadError;
|
||||
};
|
||||
|
||||
@implementation UpdateDialogDelegate
|
||||
- (void) finishClicked
|
||||
{
|
||||
[NSApp stop:self];
|
||||
}
|
||||
- (void) reportUpdateError: (id)arg
|
||||
{
|
||||
dialog->hadError = true;
|
||||
|
||||
NSAlert* alert = [NSAlert
|
||||
alertWithMessageText: @"Update Problem"
|
||||
defaultButton: nil
|
||||
alternateButton: nil
|
||||
otherButton: nil
|
||||
informativeTextWithFormat: @"There was a problem installing the update:\n\n%@", arg];
|
||||
[alert runModal];
|
||||
}
|
||||
- (void) reportUpdateProgress: (id)arg
|
||||
{
|
||||
int percentage = [arg intValue];
|
||||
[dialog->progressBar setDoubleValue:(percentage/100.0)];
|
||||
}
|
||||
- (void) reportUpdateFinished: (id)arg
|
||||
{
|
||||
NSMutableString* message = [[NSMutableString alloc] init];
|
||||
if (!dialog->hadError)
|
||||
{
|
||||
[message appendString:@"Updates installed."];
|
||||
}
|
||||
else
|
||||
{
|
||||
[message appendString:@"Update failed."];
|
||||
}
|
||||
|
||||
[message appendString:@" Click 'Finish' to restart the application."];
|
||||
[dialog->progressLabel setTitleWithMnemonic:message];
|
||||
[message release];
|
||||
}
|
||||
@end
|
||||
|
||||
UpdateDialogCocoa::UpdateDialogCocoa()
|
||||
: d(new UpdateDialogPrivate)
|
||||
{
|
||||
[NSApplication sharedApplication];
|
||||
d->pool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
UpdateDialogCocoa::~UpdateDialogCocoa()
|
||||
{
|
||||
[d->pool release];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::enableDockIcon()
|
||||
{
|
||||
// convert the application to a foreground application and in
|
||||
// the process, enable the dock icon
|
||||
|
||||
// the reverse transformation is not possible, according to
|
||||
// http://stackoverflow.com/questions/2832961/is-it-possible-to-hide-the-dock-icon-programmatically
|
||||
ProcessSerialNumber psn;
|
||||
GetCurrentProcess(&psn);
|
||||
TransformProcessType(&psn,kProcessTransformToForegroundApplication);
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::init(int /* argc */, char** /* argv */)
|
||||
{
|
||||
enableDockIcon();
|
||||
|
||||
// make the updater the active application. This does not
|
||||
// happen automatically because the updater starts as a
|
||||
// background application
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
d->delegate = [[UpdateDialogDelegate alloc] init];
|
||||
d->delegate->dialog = d;
|
||||
|
||||
int width = 370;
|
||||
int height = 100;
|
||||
|
||||
d->window = [[NSWindow alloc] initWithContentRect:NSMakeRect(200, 200, width, height)
|
||||
styleMask:NSTitledWindowMask | NSMiniaturizableWindowMask
|
||||
backing:NSBackingStoreBuffered defer:NO];
|
||||
[d->window setTitle:[NSString stringWithUTF8String:AppInfo::name().c_str()]];
|
||||
|
||||
d->finishButton = [[NSButton alloc] init];
|
||||
[d->finishButton setTitle:@"Finish"];
|
||||
[d->finishButton setButtonType:NSMomentaryLightButton];
|
||||
[d->finishButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[d->finishButton setTarget:d->delegate];
|
||||
[d->finishButton setAction:@selector(finishClicked)];
|
||||
|
||||
d->progressBar = [[NSProgressIndicator alloc] init];
|
||||
[d->progressBar setIndeterminate:false];
|
||||
[d->progressBar setMinValue:0.0];
|
||||
[d->progressBar setMaxValue:1.0];
|
||||
|
||||
d->progressLabel = [[NSTextField alloc] init];
|
||||
[d->progressLabel setEditable:false];
|
||||
[d->progressLabel setSelectable:false];
|
||||
[d->progressLabel setTitleWithMnemonic:@"Installing Updates"];
|
||||
[d->progressLabel setBezeled:false];
|
||||
[d->progressLabel setDrawsBackground:false];
|
||||
|
||||
NSView* windowContent = [d->window contentView];
|
||||
[windowContent addSubview:d->progressLabel];
|
||||
[windowContent addSubview:d->progressBar];
|
||||
[windowContent addSubview:d->finishButton];
|
||||
|
||||
[d->progressLabel setFrame:NSMakeRect(10,70,width - 10,20)];
|
||||
[d->progressBar setFrame:NSMakeRect(10,40,width - 20,20)];
|
||||
[d->finishButton setFrame:NSMakeRect(width - 85,5,80,30)];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::exec()
|
||||
{
|
||||
[d->window makeKeyAndOrderFront:d->window];
|
||||
[d->window center];
|
||||
[NSApp run];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::updateError(const std::string& errorMessage)
|
||||
{
|
||||
[d->delegate performSelectorOnMainThread:@selector(reportUpdateError:)
|
||||
withObject:[NSString stringWithUTF8String:errorMessage.c_str()]
|
||||
waitUntilDone:false];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::updateProgress(int percentage)
|
||||
{
|
||||
[d->delegate performSelectorOnMainThread:@selector(reportUpdateProgress:)
|
||||
withObject:[NSNumber numberWithInt:percentage]
|
||||
waitUntilDone:false];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::updateFinished()
|
||||
{
|
||||
[d->delegate performSelectorOnMainThread:@selector(reportUpdateFinished:)
|
||||
withObject:nil
|
||||
waitUntilDone:false];
|
||||
UpdateDialog::updateFinished();
|
||||
}
|
||||
|
||||
void* UpdateDialogCocoa::createAutoreleasePool()
|
||||
{
|
||||
return [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::releaseAutoreleasePool(void* arg)
|
||||
{
|
||||
[(id)arg release];
|
||||
}
|
||||
|
||||
void UpdateDialogCocoa::quit()
|
||||
{
|
||||
[NSApp performSelectorOnMainThread:@selector(stop:) withObject:d->delegate waitUntilDone:false];
|
||||
}
|
||||
|
||||
|
155
mmc_updater/src/UpdateDialogGtk.cpp
Normal file
155
mmc_updater/src/UpdateDialogGtk.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
#include "UpdateDialogGtk.h"
|
||||
|
||||
#include "AppInfo.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
UpdateDialogGtk* update_dialog_gtk_new()
|
||||
{
|
||||
return new UpdateDialogGtk();
|
||||
}
|
||||
|
||||
UpdateDialogGtk::UpdateDialogGtk()
|
||||
: m_hadError(false)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateDialogGtk::init(int argc, char** argv)
|
||||
{
|
||||
gtk_init(&argc,&argv);
|
||||
|
||||
m_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(m_window),AppInfo::name().c_str());
|
||||
|
||||
m_progressLabel = gtk_label_new("Installing Updates");
|
||||
|
||||
GtkWidget* windowLayout = gtk_vbox_new(FALSE,3);
|
||||
GtkWidget* buttonLayout = gtk_hbox_new(FALSE,3);
|
||||
GtkWidget* labelLayout = gtk_hbox_new(FALSE,3);
|
||||
|
||||
m_finishButton = gtk_button_new_with_label("Finish");
|
||||
gtk_widget_set_sensitive(m_finishButton,false);
|
||||
|
||||
m_progressBar = gtk_progress_bar_new();
|
||||
|
||||
// give the dialog a sensible default size by setting a minimum
|
||||
// width on the progress bar. This is used instead of setting
|
||||
// a default size for the dialog since gtk_window_set_default_size()
|
||||
// is ignored when a dialog is marked as non-resizable
|
||||
gtk_widget_set_usize(m_progressBar,350,-1);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(m_finishButton),"clicked",
|
||||
GTK_SIGNAL_FUNC(UpdateDialogGtk::finish),this);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(m_window),windowLayout);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(m_window),12);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(labelLayout),m_progressLabel,false,false,0);
|
||||
gtk_box_pack_end(GTK_BOX(buttonLayout),m_finishButton,false,false,0);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(windowLayout),labelLayout,false,false,0);
|
||||
gtk_box_pack_start(GTK_BOX(windowLayout),m_progressBar,false,false,0);
|
||||
gtk_box_pack_start(GTK_BOX(windowLayout),buttonLayout,false,false,0);
|
||||
|
||||
|
||||
gtk_widget_show(m_progressLabel);
|
||||
gtk_widget_show(labelLayout);
|
||||
gtk_widget_show(windowLayout);
|
||||
gtk_widget_show(buttonLayout);
|
||||
gtk_widget_show(m_finishButton);
|
||||
gtk_widget_show(m_progressBar);
|
||||
|
||||
gtk_window_set_resizable(GTK_WINDOW(m_window),false);
|
||||
gtk_window_set_position(GTK_WINDOW(m_window),GTK_WIN_POS_CENTER);
|
||||
|
||||
gtk_widget_show(m_window);
|
||||
}
|
||||
|
||||
void UpdateDialogGtk::exec()
|
||||
{
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
void UpdateDialogGtk::finish(GtkWidget* widget, gpointer _dialog)
|
||||
{
|
||||
UpdateDialogGtk* dialog = static_cast<UpdateDialogGtk*>(_dialog);
|
||||
dialog->quit();
|
||||
}
|
||||
|
||||
void UpdateDialogGtk::quit()
|
||||
{
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
gboolean UpdateDialogGtk::notify(void* _message)
|
||||
{
|
||||
UpdateMessage* message = static_cast<UpdateMessage*>(_message);
|
||||
UpdateDialogGtk* dialog = static_cast<UpdateDialogGtk*>(message->receiver);
|
||||
switch (message->type)
|
||||
{
|
||||
case UpdateMessage::UpdateProgress:
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dialog->m_progressBar),message->progress/100.0);
|
||||
break;
|
||||
case UpdateMessage::UpdateFailed:
|
||||
{
|
||||
dialog->m_hadError = true;
|
||||
std::string errorMessage = AppInfo::updateErrorMessage(message->message);
|
||||
GtkWidget* errorDialog = gtk_message_dialog_new (GTK_WINDOW(dialog->m_window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"%s",
|
||||
errorMessage.c_str());
|
||||
gtk_dialog_run (GTK_DIALOG (errorDialog));
|
||||
gtk_widget_destroy (errorDialog);
|
||||
gtk_widget_set_sensitive(dialog->m_finishButton,true);
|
||||
}
|
||||
break;
|
||||
case UpdateMessage::UpdateFinished:
|
||||
{
|
||||
std::string message;
|
||||
if (dialog->m_hadError)
|
||||
{
|
||||
message = "Update failed.";
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "Update installed.";
|
||||
}
|
||||
message += " Click 'Finish' to restart the application.";
|
||||
gtk_label_set_text(GTK_LABEL(dialog->m_progressLabel),message.c_str());
|
||||
gtk_widget_set_sensitive(dialog->m_finishButton,true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
delete message;
|
||||
|
||||
// do not invoke this function again
|
||||
return false;
|
||||
}
|
||||
|
||||
// callbacks during update installation
|
||||
void UpdateDialogGtk::updateError(const std::string& errorMessage)
|
||||
{
|
||||
UpdateMessage* message = new UpdateMessage(this,UpdateMessage::UpdateFailed);
|
||||
message->message = errorMessage;
|
||||
g_idle_add(&UpdateDialogGtk::notify,message);
|
||||
}
|
||||
|
||||
void UpdateDialogGtk::updateProgress(int percentage)
|
||||
{
|
||||
UpdateMessage* message = new UpdateMessage(this,UpdateMessage::UpdateProgress);
|
||||
message->progress = percentage;
|
||||
g_idle_add(&UpdateDialogGtk::notify,message);
|
||||
}
|
||||
|
||||
void UpdateDialogGtk::updateFinished()
|
||||
{
|
||||
UpdateMessage* message = new UpdateMessage(this,UpdateMessage::UpdateFinished);
|
||||
g_idle_add(&UpdateDialogGtk::notify,message);
|
||||
UpdateDialog::updateFinished();
|
||||
}
|
||||
|
||||
|
42
mmc_updater/src/UpdateDialogGtk.h
Normal file
42
mmc_updater/src/UpdateDialogGtk.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "UpdateDialog.h"
|
||||
#include "UpdateMessage.h"
|
||||
#include "UpdateObserver.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
class UpdateDialogGtk : public UpdateDialog
|
||||
{
|
||||
public:
|
||||
UpdateDialogGtk();
|
||||
|
||||
// implements UpdateDialog
|
||||
virtual void init(int argc, char** argv);
|
||||
virtual void exec();
|
||||
virtual void quit();
|
||||
|
||||
// observer callbacks - these may be called
|
||||
// from a background thread
|
||||
virtual void updateError(const std::string& errorMessage);
|
||||
virtual void updateProgress(int percentage);
|
||||
virtual void updateFinished();
|
||||
|
||||
private:
|
||||
static void finish(GtkWidget* widget, gpointer dialog);
|
||||
static gboolean notify(void* message);
|
||||
|
||||
GtkWidget* m_window;
|
||||
GtkWidget* m_progressLabel;
|
||||
GtkWidget* m_finishButton;
|
||||
GtkWidget* m_progressBar;
|
||||
bool m_hadError;
|
||||
};
|
||||
|
||||
// helper functions which allow the GTK dialog to be loaded dynamically
|
||||
// at runtime and used only if the GTK libraries are actually present
|
||||
extern "C" {
|
||||
UpdateDialogGtk* update_dialog_gtk_new();
|
||||
}
|
||||
|
||||
|
59
mmc_updater/src/UpdateDialogGtkFactory.cpp
Normal file
59
mmc_updater/src/UpdateDialogGtkFactory.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "UpdateDialogGtkFactory.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "UpdateDialog.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class UpdateDialogGtk;
|
||||
|
||||
// GTK updater UI library embedded into
|
||||
// the updater binary
|
||||
extern unsigned char libupdatergtk_so[];
|
||||
extern unsigned int libupdatergtk_so_len;
|
||||
|
||||
// pointers to helper functions in the GTK updater UI library
|
||||
UpdateDialogGtk* (*update_dialog_gtk_new)() = 0;
|
||||
|
||||
bool extractFileFromBinary(const char* path, const void* buffer, size_t length)
|
||||
{
|
||||
int fd = open(path,O_CREAT | O_WRONLY | O_TRUNC,0755);
|
||||
size_t count = write(fd,buffer,length);
|
||||
if (fd < 0 || count < length)
|
||||
{
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
UpdateDialog* UpdateDialogGtkFactory::createDialog()
|
||||
{
|
||||
const char* libPath = "/tmp/libupdatergtk.so";
|
||||
|
||||
if (!extractFileFromBinary(libPath,libupdatergtk_so,libupdatergtk_so_len))
|
||||
{
|
||||
LOG(Warn,"Failed to load the GTK UI library - " + std::string(strerror(errno)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* gtkLib = dlopen(libPath,RTLD_LAZY);
|
||||
if (!gtkLib)
|
||||
{
|
||||
LOG(Warn,"Failed to load the GTK UI - " + std::string(dlerror()));
|
||||
return 0;
|
||||
}
|
||||
update_dialog_gtk_new = (UpdateDialogGtk* (*)()) dlsym(gtkLib,"update_dialog_gtk_new");
|
||||
return reinterpret_cast<UpdateDialog*>(update_dialog_gtk_new());
|
||||
}
|
||||
|
13
mmc_updater/src/UpdateDialogGtkFactory.h
Normal file
13
mmc_updater/src/UpdateDialogGtkFactory.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
class UpdateDialog;
|
||||
|
||||
/** Factory for loading the GTK version of the update dialog
|
||||
* dynamically at runtime if the GTK libraries are available.
|
||||
*/
|
||||
class UpdateDialogGtkFactory
|
||||
{
|
||||
public:
|
||||
static UpdateDialog* createDialog();
|
||||
};
|
||||
|
215
mmc_updater/src/UpdateDialogWin32.cpp
Normal file
215
mmc_updater/src/UpdateDialogWin32.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include "UpdateDialogWin32.h"
|
||||
|
||||
#include "AppInfo.h"
|
||||
#include "Log.h"
|
||||
|
||||
// enable themed controls
|
||||
// see http://msdn.microsoft.com/en-us/library/bb773175%28v=vs.85%29.aspx
|
||||
// for details
|
||||
#pragma comment(linker,"\"/manifestdependency:type='win32' \
|
||||
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
|
||||
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
|
||||
static const char* updateDialogClassName = "UPDATEDIALOG";
|
||||
|
||||
static std::map<HWND,UpdateDialogWin32*> windowDialogMap;
|
||||
|
||||
// enable the standard Windows font for a widget
|
||||
// (typically Tahoma or Segoe UI)
|
||||
void setDefaultFont(HWND window)
|
||||
{
|
||||
SendMessage(window, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
|
||||
}
|
||||
|
||||
LRESULT WINAPI updateDialogWindowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
std::map<HWND,UpdateDialogWin32*>::const_iterator iter = windowDialogMap.find(window);
|
||||
if (iter != windowDialogMap.end())
|
||||
{
|
||||
return iter->second->windowProc(window,message,wParam,lParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DefWindowProc(window,message,wParam,lParam);
|
||||
}
|
||||
};
|
||||
|
||||
void registerWindowClass()
|
||||
{
|
||||
WNDCLASSEX wcex;
|
||||
ZeroMemory(&wcex,sizeof(WNDCLASSEX));
|
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
|
||||
HBRUSH background = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
|
||||
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = updateDialogWindowProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hIcon = LoadIcon(GetModuleHandle(0),"IDI_APPICON");
|
||||
wcex.hCursor = LoadCursor(0,IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)background;
|
||||
wcex.lpszMenuName = (LPCTSTR)0;
|
||||
wcex.lpszClassName = updateDialogClassName;
|
||||
wcex.hIconSm = 0;
|
||||
wcex.hInstance = GetModuleHandle(0);
|
||||
|
||||
RegisterClassEx(&wcex);
|
||||
}
|
||||
|
||||
UpdateDialogWin32::UpdateDialogWin32()
|
||||
: m_hadError(false)
|
||||
{
|
||||
registerWindowClass();
|
||||
}
|
||||
|
||||
UpdateDialogWin32::~UpdateDialogWin32()
|
||||
{
|
||||
for (std::map<HWND,UpdateDialogWin32*>::iterator iter = windowDialogMap.begin();
|
||||
iter != windowDialogMap.end();
|
||||
iter++)
|
||||
{
|
||||
if (iter->second == this)
|
||||
{
|
||||
std::map<HWND,UpdateDialogWin32*>::iterator oldIter = iter;
|
||||
++iter;
|
||||
windowDialogMap.erase(oldIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateDialogWin32::init(int /* argc */, char** /* argv */)
|
||||
{
|
||||
int width = 300;
|
||||
int height = 130;
|
||||
|
||||
DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
m_window.CreateEx(0 /* dwExStyle */,
|
||||
updateDialogClassName /* class name */,
|
||||
AppInfo::name().c_str(),
|
||||
style,
|
||||
0, 0, width, height,
|
||||
0 /* parent */, 0 /* menu */, 0 /* reserved */);
|
||||
m_progressBar.Create(&m_window);
|
||||
m_finishButton.Create(&m_window);
|
||||
m_progressLabel.Create(&m_window);
|
||||
|
||||
installWindowProc(&m_window);
|
||||
installWindowProc(&m_finishButton);
|
||||
|
||||
setDefaultFont(m_progressLabel);
|
||||
setDefaultFont(m_finishButton);
|
||||
|
||||
m_progressBar.SetRange(0,100);
|
||||
m_finishButton.SetWindowText("Finish");
|
||||
m_finishButton.EnableWindow(false);
|
||||
m_progressLabel.SetWindowText("Installing Updates");
|
||||
|
||||
m_window.SetWindowPos(0,0,0,width,height,0);
|
||||
m_progressBar.SetWindowPos(0,10,40,width - 30,20,0);
|
||||
m_progressLabel.SetWindowPos(0,10,15,width - 30,20,0);
|
||||
m_finishButton.SetWindowPos(0,width-100,70,80,25,0);
|
||||
m_window.CenterWindow();
|
||||
m_window.ShowWindow();
|
||||
}
|
||||
|
||||
void UpdateDialogWin32::exec()
|
||||
{
|
||||
m_app.Run();
|
||||
}
|
||||
|
||||
void UpdateDialogWin32::updateError(const std::string& errorMessage)
|
||||
{
|
||||
UpdateMessage* message = new UpdateMessage(UpdateMessage::UpdateFailed);
|
||||
message->message = errorMessage;
|
||||
SendNotifyMessage(m_window.GetHwnd(),WM_USER,reinterpret_cast<WPARAM>(message),0);
|
||||
}
|
||||
|
||||
void UpdateDialogWin32::updateProgress(int percentage)
|
||||
{
|
||||
UpdateMessage* message = new UpdateMessage(UpdateMessage::UpdateProgress);
|
||||
message->progress = percentage;
|
||||
SendNotifyMessage(m_window.GetHwnd(),WM_USER,reinterpret_cast<WPARAM>(message),0);
|
||||
}
|
||||
|
||||
void UpdateDialogWin32::updateFinished()
|
||||
{
|
||||
UpdateMessage* message = new UpdateMessage(UpdateMessage::UpdateFinished);
|
||||
SendNotifyMessage(m_window.GetHwnd(),WM_USER,reinterpret_cast<WPARAM>(message),0);
|
||||
UpdateDialog::updateFinished();
|
||||
}
|
||||
|
||||
void UpdateDialogWin32::quit()
|
||||
{
|
||||
PostThreadMessage(GetWindowThreadProcessId(m_window.GetHwnd(), 0 /* process ID */), WM_QUIT, 0, 0);
|
||||
}
|
||||
|
||||
LRESULT WINAPI UpdateDialogWin32::windowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
if (window == m_window.GetHwnd())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
{
|
||||
if (reinterpret_cast<HWND>(lParam) == m_finishButton.GetHwnd())
|
||||
{
|
||||
quit();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_USER:
|
||||
{
|
||||
if (window == m_window.GetHwnd())
|
||||
{
|
||||
UpdateMessage* message = reinterpret_cast<UpdateMessage*>(wParam);
|
||||
switch (message->type)
|
||||
{
|
||||
case UpdateMessage::UpdateFailed:
|
||||
{
|
||||
m_hadError = true;
|
||||
std::string text = AppInfo::updateErrorMessage(message->message);
|
||||
MessageBox(m_window.GetHwnd(),text.c_str(),"Update Problem",MB_OK);
|
||||
}
|
||||
break;
|
||||
case UpdateMessage::UpdateProgress:
|
||||
m_progressBar.SetPos(message->progress);
|
||||
break;
|
||||
case UpdateMessage::UpdateFinished:
|
||||
{
|
||||
std::string message;
|
||||
m_finishButton.EnableWindow(true);
|
||||
if (m_hadError)
|
||||
{
|
||||
message = "Update failed.";
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "Updates installed.";
|
||||
}
|
||||
message += " Click 'Finish' to restart the application.";
|
||||
m_progressLabel.SetWindowText(message.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return DefWindowProc(window,message,wParam,lParam);
|
||||
}
|
||||
|
||||
void UpdateDialogWin32::installWindowProc(CWnd* window)
|
||||
{
|
||||
windowDialogMap[window->GetHwnd()] = this;
|
||||
}
|
39
mmc_updater/src/UpdateDialogWin32.h
Normal file
39
mmc_updater/src/UpdateDialogWin32.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform.h"
|
||||
#include "UpdateDialog.h"
|
||||
#include "UpdateMessage.h"
|
||||
|
||||
#include "wincore.h"
|
||||
#include "controls.h"
|
||||
#include "stdcontrols.h"
|
||||
|
||||
class UpdateDialogWin32 : public UpdateDialog
|
||||
{
|
||||
public:
|
||||
UpdateDialogWin32();
|
||||
~UpdateDialogWin32();
|
||||
|
||||
// implements UpdateDialog
|
||||
virtual void init(int argc, char** argv);
|
||||
virtual void exec();
|
||||
virtual void quit();
|
||||
|
||||
// implements UpdateObserver
|
||||
virtual void updateError(const std::string& errorMessage);
|
||||
virtual void updateProgress(int percentage);
|
||||
virtual void updateFinished();
|
||||
|
||||
LRESULT WINAPI windowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
void installWindowProc(CWnd* window);
|
||||
|
||||
CWinApp m_app;
|
||||
CWnd m_window;
|
||||
CStatic m_progressLabel;
|
||||
CProgressBar m_progressBar;
|
||||
CButton m_finishButton;
|
||||
bool m_hadError;
|
||||
};
|
||||
|
426
mmc_updater/src/UpdateInstaller.cpp
Normal file
426
mmc_updater/src/UpdateInstaller.cpp
Normal file
@ -0,0 +1,426 @@
|
||||
#include "UpdateInstaller.h"
|
||||
|
||||
#include "AppInfo.h"
|
||||
#include "FileUtils.h"
|
||||
#include "Log.h"
|
||||
#include "ProcessUtils.h"
|
||||
#include "UpdateObserver.h"
|
||||
|
||||
UpdateInstaller::UpdateInstaller()
|
||||
: m_mode(Setup)
|
||||
, m_waitPid(0)
|
||||
, m_script(0)
|
||||
, m_observer(0)
|
||||
, m_forceElevated(false)
|
||||
, m_autoClose(false)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateInstaller::setWaitPid(PLATFORM_PID pid)
|
||||
{
|
||||
m_waitPid = pid;
|
||||
}
|
||||
|
||||
void UpdateInstaller::setInstallDir(const std::string& path)
|
||||
{
|
||||
m_installDir = path;
|
||||
}
|
||||
|
||||
void UpdateInstaller::setPackageDir(const std::string& path)
|
||||
{
|
||||
m_packageDir = path;
|
||||
}
|
||||
|
||||
void UpdateInstaller::setBackupDir(const std::string& path)
|
||||
{
|
||||
m_backupDir = path;
|
||||
}
|
||||
|
||||
void UpdateInstaller::setMode(Mode mode)
|
||||
{
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
void UpdateInstaller::setScript(UpdateScript* script)
|
||||
{
|
||||
m_script = script;
|
||||
}
|
||||
|
||||
void UpdateInstaller::setForceElevated(bool elevated)
|
||||
{
|
||||
m_forceElevated = elevated;
|
||||
}
|
||||
|
||||
void UpdateInstaller::setFinishCmd(const std::string& cmd)
|
||||
{
|
||||
m_finishCmd = cmd;
|
||||
}
|
||||
|
||||
std::list<std::string> UpdateInstaller::updaterArgs() const
|
||||
{
|
||||
std::list<std::string> args;
|
||||
args.push_back("--install-dir");
|
||||
args.push_back(m_installDir);
|
||||
args.push_back("--package-dir");
|
||||
args.push_back(m_packageDir);
|
||||
args.push_back("--script");
|
||||
args.push_back(m_script->path());
|
||||
if (m_autoClose)
|
||||
{
|
||||
args.push_back("--auto-close");
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
void UpdateInstaller::reportError(const std::string& error)
|
||||
{
|
||||
if (m_observer)
|
||||
{
|
||||
m_observer->updateError(error);
|
||||
m_observer->updateFinished();
|
||||
}
|
||||
}
|
||||
|
||||
std::string UpdateInstaller::friendlyErrorForError(const FileUtils::IOException& exception) const
|
||||
{
|
||||
std::string friendlyError;
|
||||
|
||||
switch (exception.type())
|
||||
{
|
||||
case FileUtils::IOException::ReadOnlyFileSystem:
|
||||
#ifdef PLATFORM_MAC
|
||||
friendlyError = AppInfo::appName() + " was started from a read-only location. "
|
||||
"Copy it to the Applications folder on your Mac and run "
|
||||
"it from there.";
|
||||
#else
|
||||
friendlyError = AppInfo::appName() + " was started from a read-only location. "
|
||||
"Re-install it to a location that can be updated and run it from there.";
|
||||
#endif
|
||||
break;
|
||||
case FileUtils::IOException::DiskFull:
|
||||
friendlyError = "The disk is full. Please free up some space and try again.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return friendlyError;
|
||||
}
|
||||
|
||||
void UpdateInstaller::run() throw ()
|
||||
{
|
||||
if (!m_script || !m_script->isValid())
|
||||
{
|
||||
reportError("Unable to read update script");
|
||||
return;
|
||||
}
|
||||
if (m_installDir.empty())
|
||||
{
|
||||
reportError("No installation directory specified");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string updaterPath;
|
||||
try
|
||||
{
|
||||
updaterPath = ProcessUtils::currentProcessPath();
|
||||
}
|
||||
catch (const FileUtils::IOException&)
|
||||
{
|
||||
LOG(Error,"error reading process path with mode " + intToStr(m_mode));
|
||||
reportError("Unable to determine path of updater");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_mode == Setup)
|
||||
{
|
||||
if (m_waitPid != 0)
|
||||
{
|
||||
LOG(Info,"Waiting for main app process to finish");
|
||||
ProcessUtils::waitForProcess(m_waitPid);
|
||||
}
|
||||
|
||||
std::list<std::string> args = updaterArgs();
|
||||
args.push_back("--mode");
|
||||
args.push_back("main");
|
||||
args.push_back("--wait");
|
||||
args.push_back(intToStr(ProcessUtils::currentProcessId()));
|
||||
|
||||
int installStatus = 0;
|
||||
if (m_forceElevated || !checkAccess())
|
||||
{
|
||||
LOG(Info,"Insufficient rights to install app to " + m_installDir + " requesting elevation");
|
||||
|
||||
// start a copy of the updater with admin rights
|
||||
installStatus = ProcessUtils::runElevated(updaterPath,args,AppInfo::name());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Info,"Sufficient rights to install app - restarting with same permissions");
|
||||
installStatus = ProcessUtils::runSync(updaterPath,args);
|
||||
}
|
||||
|
||||
if (installStatus == 0)
|
||||
{
|
||||
LOG(Info,"Update install completed");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Error,"Update install failed with status " + intToStr(installStatus));
|
||||
}
|
||||
|
||||
// restart the main application - this is currently done
|
||||
// regardless of whether the installation succeeds or not
|
||||
restartMainApp();
|
||||
|
||||
// clean up files created by the updater
|
||||
cleanup();
|
||||
}
|
||||
else if (m_mode == Main)
|
||||
{
|
||||
LOG(Info,"Starting update installation");
|
||||
|
||||
// the detailed error string returned by the OS
|
||||
std::string error;
|
||||
// the message to present to the user. This may be the same
|
||||
// as 'error' or may be different if a more helpful suggestion
|
||||
// can be made for a particular problem
|
||||
std::string friendlyError;
|
||||
|
||||
try
|
||||
{
|
||||
LOG(Info,"Installing new and updated files");
|
||||
installFiles();
|
||||
|
||||
LOG(Info,"Uninstalling removed files");
|
||||
uninstallFiles();
|
||||
|
||||
LOG(Info,"Removing backups");
|
||||
removeBackups();
|
||||
|
||||
postInstallUpdate();
|
||||
}
|
||||
catch (const FileUtils::IOException& exception)
|
||||
{
|
||||
error = exception.what();
|
||||
friendlyError = friendlyErrorForError(exception);
|
||||
}
|
||||
catch (const std::string& genericError)
|
||||
{
|
||||
error = genericError;
|
||||
}
|
||||
|
||||
if (!error.empty())
|
||||
{
|
||||
LOG(Error,std::string("Error installing update ") + error);
|
||||
|
||||
try
|
||||
{
|
||||
revert();
|
||||
}
|
||||
catch (const FileUtils::IOException& exception)
|
||||
{
|
||||
LOG(Error,"Error reverting partial update " + std::string(exception.what()));
|
||||
}
|
||||
|
||||
if (m_observer)
|
||||
{
|
||||
if (friendlyError.empty())
|
||||
{
|
||||
friendlyError = error;
|
||||
}
|
||||
m_observer->updateError(friendlyError);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_observer)
|
||||
{
|
||||
m_observer->updateFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInstaller::cleanup()
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtils::rmdirRecursive(m_packageDir.c_str());
|
||||
}
|
||||
catch (const FileUtils::IOException& ex)
|
||||
{
|
||||
LOG(Error,"Error cleaning up updater " + std::string(ex.what()));
|
||||
}
|
||||
LOG(Info,"Updater files removed");
|
||||
}
|
||||
|
||||
void UpdateInstaller::revert()
|
||||
{
|
||||
std::map<std::string,std::string>::const_iterator iter = m_backups.begin();
|
||||
for (;iter != m_backups.end();iter++)
|
||||
{
|
||||
const std::string& installedFile = iter->first;
|
||||
const std::string& backupFile = iter->second;
|
||||
|
||||
if (FileUtils::fileExists(installedFile.c_str()))
|
||||
{
|
||||
FileUtils::removeFile(installedFile.c_str());
|
||||
}
|
||||
FileUtils::moveFile(backupFile.c_str(),installedFile.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInstaller::installFile(const UpdateScriptFile& file)
|
||||
{
|
||||
std::string destPath = file.dest;
|
||||
std::string target = file.linkTarget;
|
||||
|
||||
// backup the existing file if any
|
||||
backupFile(destPath);
|
||||
|
||||
// create the target directory if it does not exist
|
||||
std::string destDir = FileUtils::dirname(destPath.c_str());
|
||||
if (!FileUtils::fileExists(destDir.c_str()))
|
||||
{
|
||||
FileUtils::mkpath(destDir.c_str());
|
||||
}
|
||||
|
||||
std::string sourceFile = file.source;
|
||||
if (!FileUtils::fileExists(sourceFile.c_str()))
|
||||
{
|
||||
throw "Source file does not exist: " + sourceFile;
|
||||
}
|
||||
FileUtils::copyFile(sourceFile.c_str(),destPath.c_str());
|
||||
|
||||
// set the permissions on the newly extracted file
|
||||
FileUtils::chmod(destPath.c_str(),file.permissions);
|
||||
}
|
||||
|
||||
void UpdateInstaller::installFiles()
|
||||
{
|
||||
std::vector<UpdateScriptFile>::const_iterator iter = m_script->filesToInstall().begin();
|
||||
int filesInstalled = 0;
|
||||
for (;iter != m_script->filesToInstall().end();iter++)
|
||||
{
|
||||
installFile(*iter);
|
||||
++filesInstalled;
|
||||
if (m_observer)
|
||||
{
|
||||
int toInstallCount = static_cast<int>(m_script->filesToInstall().size());
|
||||
double percentage = ((1.0 * filesInstalled) / toInstallCount) * 100.0;
|
||||
m_observer->updateProgress(static_cast<int>(percentage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInstaller::uninstallFiles()
|
||||
{
|
||||
std::vector<std::string>::const_iterator iter = m_script->filesToUninstall().begin();
|
||||
for (;iter != m_script->filesToUninstall().end();iter++)
|
||||
{
|
||||
std::string path = m_installDir + '/' + iter->c_str();
|
||||
if (FileUtils::fileExists(path.c_str()))
|
||||
{
|
||||
FileUtils::removeFile(path.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warn,"Unable to uninstall file " + path + " because it does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInstaller::backupFile(const std::string& path)
|
||||
{
|
||||
if (!FileUtils::fileExists(path.c_str()))
|
||||
{
|
||||
// no existing file to backup
|
||||
return;
|
||||
}
|
||||
|
||||
std::string backupPath = path + ".bak";
|
||||
FileUtils::removeFile(backupPath.c_str());
|
||||
FileUtils::moveFile(path.c_str(), backupPath.c_str());
|
||||
m_backups[path] = backupPath;
|
||||
}
|
||||
|
||||
void UpdateInstaller::removeBackups()
|
||||
{
|
||||
std::map<std::string,std::string>::const_iterator iter = m_backups.begin();
|
||||
for (;iter != m_backups.end();iter++)
|
||||
{
|
||||
const std::string& backupFile = iter->second;
|
||||
FileUtils::removeFile(backupFile.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool UpdateInstaller::checkAccess()
|
||||
{
|
||||
std::string testFile = m_installDir + "/update-installer-test-file";
|
||||
|
||||
try
|
||||
{
|
||||
FileUtils::removeFile(testFile.c_str());
|
||||
}
|
||||
catch (const FileUtils::IOException& error)
|
||||
{
|
||||
LOG(Info,"Removing existing access check file failed " + std::string(error.what()));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
FileUtils::touch(testFile.c_str());
|
||||
FileUtils::removeFile(testFile.c_str());
|
||||
return true;
|
||||
}
|
||||
catch (const FileUtils::IOException& error)
|
||||
{
|
||||
LOG(Info,"checkAccess() failed " + std::string(error.what()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInstaller::setObserver(UpdateObserver* observer)
|
||||
{
|
||||
m_observer = observer;
|
||||
}
|
||||
|
||||
void UpdateInstaller::restartMainApp()
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string command = m_finishCmd;
|
||||
std::list<std::string> args;
|
||||
|
||||
if (!command.empty())
|
||||
{
|
||||
LOG(Info,"Starting main application " + command);
|
||||
ProcessUtils::runAsync(command,args);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Error,"No main binary specified");
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
LOG(Error,"Unable to restart main app " + std::string(ex.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInstaller::postInstallUpdate()
|
||||
{
|
||||
// perform post-install actions
|
||||
|
||||
#ifdef PLATFORM_MAC
|
||||
// touch the application's bundle directory so that
|
||||
// OS X' Launch Services notices any changes in the application's
|
||||
// Info.plist file.
|
||||
FileUtils::touch(m_installDir.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpdateInstaller::setAutoClose(bool autoClose)
|
||||
{
|
||||
m_autoClose = autoClose;
|
||||
}
|
||||
|
72
mmc_updater/src/UpdateInstaller.h
Normal file
72
mmc_updater/src/UpdateInstaller.h
Normal file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform.h"
|
||||
#include "FileUtils.h"
|
||||
#include "UpdateScript.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class UpdateObserver;
|
||||
|
||||
/** Central class responsible for installing updates,
|
||||
* launching an elevated copy of the updater if required
|
||||
* and restarting the main application once the update
|
||||
* is installed.
|
||||
*/
|
||||
class UpdateInstaller
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
Setup,
|
||||
Main
|
||||
};
|
||||
|
||||
UpdateInstaller();
|
||||
void setInstallDir(const std::string& path);
|
||||
void setPackageDir(const std::string& path);
|
||||
void setBackupDir(const std::string& path);
|
||||
void setMode(Mode mode);
|
||||
void setScript(UpdateScript* script);
|
||||
void setWaitPid(PLATFORM_PID pid);
|
||||
void setForceElevated(bool elevated);
|
||||
void setAutoClose(bool autoClose);
|
||||
void setFinishCmd(const std::string& cmd);
|
||||
|
||||
void setObserver(UpdateObserver* observer);
|
||||
|
||||
void run() throw ();
|
||||
|
||||
void restartMainApp();
|
||||
|
||||
private:
|
||||
void cleanup();
|
||||
void revert();
|
||||
void removeBackups();
|
||||
bool checkAccess();
|
||||
|
||||
void installFiles();
|
||||
void uninstallFiles();
|
||||
void installFile(const UpdateScriptFile& file);
|
||||
void backupFile(const std::string& path);
|
||||
void reportError(const std::string& error);
|
||||
void postInstallUpdate();
|
||||
|
||||
std::list<std::string> updaterArgs() const;
|
||||
std::string friendlyErrorForError(const FileUtils::IOException& ex) const;
|
||||
|
||||
Mode m_mode;
|
||||
std::string m_installDir;
|
||||
std::string m_packageDir;
|
||||
std::string m_backupDir;
|
||||
std::string m_finishCmd;
|
||||
PLATFORM_PID m_waitPid;
|
||||
UpdateScript* m_script;
|
||||
UpdateObserver* m_observer;
|
||||
std::map<std::string,std::string> m_backups;
|
||||
bool m_forceElevated;
|
||||
bool m_autoClose;
|
||||
};
|
||||
|
42
mmc_updater/src/UpdateMessage.h
Normal file
42
mmc_updater/src/UpdateMessage.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
/** UpdateMessage stores information for a message
|
||||
* about the status of update installation sent
|
||||
* between threads.
|
||||
*/
|
||||
class UpdateMessage
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
UpdateFailed,
|
||||
UpdateProgress,
|
||||
UpdateFinished
|
||||
};
|
||||
|
||||
UpdateMessage(void* receiver, Type type)
|
||||
{
|
||||
init(receiver,type);
|
||||
}
|
||||
|
||||
UpdateMessage(Type type)
|
||||
{
|
||||
init(0,type);
|
||||
}
|
||||
|
||||
void* receiver;
|
||||
Type type;
|
||||
std::string message;
|
||||
int progress;
|
||||
|
||||
private:
|
||||
void init(void* receiver, Type type)
|
||||
{
|
||||
this->progress = 0;
|
||||
this->receiver = receiver;
|
||||
this->type = type;
|
||||
}
|
||||
};
|
||||
|
15
mmc_updater/src/UpdateObserver.h
Normal file
15
mmc_updater/src/UpdateObserver.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
/** Base class for observers of update installation status.
|
||||
* See UpdateInstaller::setObserver()
|
||||
*/
|
||||
class UpdateObserver
|
||||
{
|
||||
public:
|
||||
virtual void updateError(const std::string& errorMessage) = 0;
|
||||
virtual void updateProgress(int percentage) = 0;
|
||||
virtual void updateFinished() = 0;
|
||||
};
|
||||
|
99
mmc_updater/src/UpdateScript.cpp
Normal file
99
mmc_updater/src/UpdateScript.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "UpdateScript.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include "tinyxml/tinyxml.h"
|
||||
|
||||
std::string elementText(const TiXmlElement* element)
|
||||
{
|
||||
if (!element)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
return element->GetText();
|
||||
}
|
||||
|
||||
UpdateScript::UpdateScript()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateScript::parse(const std::string& path)
|
||||
{
|
||||
m_path.clear();
|
||||
|
||||
TiXmlDocument document(path);
|
||||
if (document.LoadFile())
|
||||
{
|
||||
m_path = path;
|
||||
|
||||
LOG(Info,"Loaded script from " + path);
|
||||
|
||||
const TiXmlElement* updateNode = document.RootElement();
|
||||
parseUpdate(updateNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Error,"Unable to load script " + path);
|
||||
}
|
||||
}
|
||||
|
||||
bool UpdateScript::isValid() const
|
||||
{
|
||||
return !m_path.empty();
|
||||
}
|
||||
|
||||
void UpdateScript::parseUpdate(const TiXmlElement* updateNode)
|
||||
{
|
||||
const TiXmlElement* installNode = updateNode->FirstChildElement("install");
|
||||
if (installNode)
|
||||
{
|
||||
const TiXmlElement* installFileNode = installNode->FirstChildElement("file");
|
||||
while (installFileNode)
|
||||
{
|
||||
m_filesToInstall.push_back(parseFile(installFileNode));
|
||||
installFileNode = installFileNode->NextSiblingElement("file");
|
||||
}
|
||||
}
|
||||
|
||||
const TiXmlElement* uninstallNode = updateNode->FirstChildElement("uninstall");
|
||||
if (uninstallNode)
|
||||
{
|
||||
const TiXmlElement* uninstallFileNode = uninstallNode->FirstChildElement("file");
|
||||
while (uninstallFileNode)
|
||||
{
|
||||
m_filesToUninstall.push_back(uninstallFileNode->GetText());
|
||||
uninstallFileNode = uninstallFileNode->NextSiblingElement("file");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateScriptFile UpdateScript::parseFile(const TiXmlElement* element)
|
||||
{
|
||||
UpdateScriptFile file;
|
||||
// The name within the update files folder.
|
||||
file.source = elementText(element->FirstChildElement("source"));
|
||||
// The path to install to.
|
||||
file.dest = elementText(element->FirstChildElement("dest"));
|
||||
|
||||
std::string modeString = elementText(element->FirstChildElement("mode"));
|
||||
sscanf(modeString.c_str(),"%i",&file.permissions);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
const std::vector<UpdateScriptFile>& UpdateScript::filesToInstall() const
|
||||
{
|
||||
return m_filesToInstall;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& UpdateScript::filesToUninstall() const
|
||||
{
|
||||
return m_filesToUninstall;
|
||||
}
|
||||
|
||||
const std::string UpdateScript::path() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
85
mmc_updater/src/UpdateScript.h
Normal file
85
mmc_updater/src/UpdateScript.h
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class TiXmlElement;
|
||||
|
||||
/** Represents a package containing one or more
|
||||
* files for an update.
|
||||
*/
|
||||
class UpdateScriptPackage
|
||||
{
|
||||
public:
|
||||
UpdateScriptPackage()
|
||||
: size(0)
|
||||
{}
|
||||
|
||||
std::string name;
|
||||
std::string sha1;
|
||||
std::string source;
|
||||
int size;
|
||||
|
||||
bool operator==(const UpdateScriptPackage& other) const
|
||||
{
|
||||
return name == other.name &&
|
||||
sha1 == other.sha1 &&
|
||||
source == other.source &&
|
||||
size == other.size;
|
||||
}
|
||||
};
|
||||
|
||||
/** Represents a file to be installed as part of an update. */
|
||||
class UpdateScriptFile
|
||||
{
|
||||
public:
|
||||
UpdateScriptFile()
|
||||
: permissions(0)
|
||||
{}
|
||||
|
||||
/// Path to copy from.
|
||||
std::string source;
|
||||
/// The path to copy to.
|
||||
std::string dest;
|
||||
std::string linkTarget;
|
||||
|
||||
/** The permissions for this file, specified
|
||||
* using the standard Unix mode_t values.
|
||||
*/
|
||||
int permissions;
|
||||
|
||||
bool operator==(const UpdateScriptFile& other) const
|
||||
{
|
||||
return source == other.source &&
|
||||
dest == other.dest &&
|
||||
permissions == other.permissions;
|
||||
}
|
||||
};
|
||||
|
||||
/** Stores information about the packages and files included
|
||||
* in an update, parsed from an XML file.
|
||||
*/
|
||||
class UpdateScript
|
||||
{
|
||||
public:
|
||||
UpdateScript();
|
||||
|
||||
/** Initialize this UpdateScript with the script stored
|
||||
* in the XML file at @p path.
|
||||
*/
|
||||
void parse(const std::string& path);
|
||||
|
||||
bool isValid() const;
|
||||
const std::string path() const;
|
||||
const std::vector<UpdateScriptFile>& filesToInstall() const;
|
||||
const std::vector<std::string>& filesToUninstall() const;
|
||||
|
||||
private:
|
||||
void parseUpdate(const TiXmlElement* element);
|
||||
UpdateScriptFile parseFile(const TiXmlElement* element);
|
||||
|
||||
std::string m_path;
|
||||
std::vector<UpdateScriptFile> m_filesToInstall;
|
||||
std::vector<std::string> m_filesToUninstall;
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user