Renew the updater branch

Now with some actual consensus on what the updater will do!
This commit is contained in:
Petr Mrázek 2013-12-02 00:55:24 +01:00
parent 613699b362
commit 6aa9bd0f77
118 changed files with 44913 additions and 45 deletions

View File

@ -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 ########
@ -129,10 +132,10 @@ ENDIF ()
MESSAGE(STATUS "MultiMC 5 version ${MultiMC_VERSION_STRING}")
# Custom target to just print the version.
#### 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 +143,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 +151,12 @@ 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}")
#### GoUpdate URL
SET(MultiMC_REPO_BASE_URL "invalid" CACHE STRING "Base URL for the updater.")
SET(MultiMC_VERSION_BRANCH "invalid" CACHE STRING "URL of the stable update repo.")
######## 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 +224,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
@ -383,7 +358,8 @@ logic/NagUtils.h
logic/NagUtils.cpp
logic/SkinUtils.h
logic/SkinUtils.cpp
logic/GoUpdate.h
logic/GoUpdate.cpp
)
@ -410,6 +386,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

View File

@ -20,6 +20,7 @@
#include "logic/net/HttpMetaCache.h"
#include "logic/JavaUtils.h"
#include "logic/GoUpdate.h"
#include "pathutils.h"
#include "cmdutils.h"
@ -138,6 +139,9 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv),
// load settings
initGlobalSettings();
// initialize the updater
m_go_update.reset(new GoUpdate());
// and instances
auto InstDirSetting = m_settings->getSetting("InstanceDir");
m_instances.reset(new InstanceList(InstDirSetting->get().toString(), this));

View File

@ -17,6 +17,7 @@ class IconList;
class QNetworkAccessManager;
class ForgeVersionList;
class JavaVersionList;
class GoUpdate;
#if defined(MMC)
#undef MMC
@ -84,6 +85,11 @@ public:
return m_metacache;
}
std::shared_ptr<GoUpdate> goupdate()
{
return m_go_update;
}
std::shared_ptr<LWJGLVersionList> lwjgllist();
std::shared_ptr<ForgeVersionList> forgelist();
@ -106,6 +112,7 @@ private:
std::shared_ptr<QTranslator> m_mmc_translator;
std::shared_ptr<SettingsObject> m_settings;
std::shared_ptr<InstanceList> m_instances;
std::shared_ptr<GoUpdate> m_go_update;
std::shared_ptr<MojangAccountList> m_accounts;
std::shared_ptr<IconList> m_icons;
std::shared_ptr<QNetworkAccessManager> m_qnam;

View File

@ -1,16 +1,20 @@
// Minor and major version, used to communicate changes to users.
#define VERSION_MAJOR @MultiMC_VERSION_MAJOR@
#define VERSION_MINOR @MultiMC_VERSION_MINOR@
// Build number and type -- numer is used by the updater, type is purely visual
#define VERSION_BUILD @MultiMC_VERSION_BUILD@
#define VERSION_BUILD_TYPE "@MultiMC_VERSION_BUILD_TYPE@"
#define GIT_COMMIT "@MultiMC_GIT_COMMIT@"
// URL base for the updater
#define VERSION_REPO "@MultiMC_REPO_BASE_URL@"
#define VERSION_STR "@MultiMC_VERSION_STRING@"
// The branch used for this build. User can switch between 'stable' and 'develop'
// if this is one of them. Otherwise, it pulls only from this one.
#define VERSION_BRANCH "@MultiMC_VERSION_BRANCH@"
#define x86 1
#define x64 2
#define ARCH @MultiMC_ARCH@
#define USE_HTTPS @MultiMC_USE_HTTPS@
// the commit hash of this build
#define GIT_COMMIT "@MultiMC_GIT_COMMIT@"
// This is printed on start to standard output
#define VERSION_STR "@MultiMC_VERSION_STRING@"

View File

@ -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"
@ -83,6 +84,7 @@
#include "logic/SkinUtils.h"
#include "logic/LegacyInstance.h"
#include <logic/GoUpdate.h>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
@ -236,6 +238,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
MMC->lwjgllist()->loadList();
}
// set up the updater object.
auto updater = MMC->goupdate();
connect(updater.get(), SIGNAL(updateAvailable()), SLOT(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()));
@ -417,6 +426,24 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
return QMainWindow::eventFilter(obj, ev);
}
void MainWindow::updateAvailable()
{
UpdateDialog dlg;
UpdateAction action = (UpdateAction) dlg.exec();
switch(action)
{
case UPDATE_LATER:
QLOG_INFO() << "Don't install update yet!";
break;
case UPDATE_NOW:
QLOG_INFO() << "Install update NOW!";
break;
case UPDATE_ONEXIT:
QLOG_INFO() << "Install update on exit!";
break;
}
}
void MainWindow::onCatToggled(bool state)
{
setCatBackground(state);
@ -604,6 +631,8 @@ void MainWindow::on_actionConfig_Folder_triggered()
void MainWindow::on_actionCheckUpdate_triggered()
{
auto updater = MMC->goupdate();
updater->checkForUpdate();
}
void MainWindow::on_actionSettings_triggered()

View File

@ -161,6 +161,8 @@ slots:
void startTask(Task *task);
void updateAvailable();
void activeAccountChanged();
void changeActiveAccount();

View 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);
}

View 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();
};

View File

@ -0,0 +1,63 @@
<?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="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>

99
logic/GoUpdate.cpp Normal file
View File

@ -0,0 +1,99 @@
#include "GoUpdate.h"
#include "config.h"
#include "logger/QsLog.h"
GoUpdate::GoUpdate()
{
currentBuildIndex = VERSION_BUILD;
builderName = VERSION_BUILD_TYPE;
repoUrlBase = VERSION_REPO;
}
void GoUpdate::updateCheckFailed()
{
// TODO: log errors better
QLOG_ERROR() << "Update check failed for reasons unknown.";
}
void GoUpdate::updateCheckFinished()
{
QJsonParseError jsonError;
QByteArray data;
{
ByteArrayDownloadPtr dl =
std::dynamic_pointer_cast<ByteArrayDownload>(index_job->first());
data = dl->m_data;
index_job.reset();
}
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
if (jsonError.error != QJsonParseError::NoError || !jsonDoc.isObject())
{
return;
}
QVariant doc = jsonDoc.toVariant();
auto stuff = doc.toMap();
// check api version (or later, branch?)
int ApiVersion = stuff["ApiVersion"].toInt();
if (ApiVersion != 0)
return;
// parse and store the channel list
auto parsedChannels = stuff["Channels"].toList();
for (auto channel : parsedChannels)
{
auto chanMap = channel.toMap();
channels.append({chanMap["Id"].toString(), chanMap["Name"].toString(),
chanMap["CurrentVersion"].toInt()});
}
// parse and store the version list
auto parsedVersions = stuff["Versions"].toList();
for (auto version : parsedVersions)
{
auto verMap = version.toMap();
int versionId = verMap["Id"].toInt();
versions.append({versionId, verMap["Name"].toString()});
if (currentBuildIndex < versionId)
{
newBuildIndex = versionId;
}
}
if (newBuildIndex != -1)
{
QLOG_INFO() << "Update is available.";
emit updateAvailable();
}
else
{
QLOG_INFO() << "Update check finished.";
}
}
void GoUpdate::checkForUpdate()
{
if (repoUrlBase == "invalid")
{
return;
}
auto job = new NetJob("Assets index");
job->addNetAction(
ByteArrayDownload::make(QUrl(repoUrlBase + "/" + VERSION_BRANCH + "/index.json")));
connect(job, SIGNAL(succeeded()), SLOT(updateCheckFinished()));
connect(job, SIGNAL(failed()), SLOT(updateCheckFailed()));
index_job.reset(job);
job->start();
}
/*
<Forkk> files.multimc.org/lin64/
<manmaed> Hi Forkkie
<Forkk> files.multimc.org/win32/
<Forkk> files.multimc.org/lin32/
*/

43
logic/GoUpdate.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include "net/NetJob.h"
class GoUpdate : public QObject
{
Q_OBJECT
public:
struct version_channel
{
QString id;
QString name;
int latestVersion;
};
struct version_summary
{
int id;
QString name;
};
signals:
void updateAvailable();
private slots:
void updateCheckFinished();
void updateCheckFailed();
public:
GoUpdate();
void checkForUpdate();
private:
NetJobPtr index_job;
NetJobPtr fromto_job;
QString repoUrlBase;
QString builderName;
int currentBuildIndex;
int newBuildIndex = -1;
QList<version_summary> versions;
QList<version_channel> channels;
};

View 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/include)
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
View 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
View 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.

View 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()

View File

@ -0,0 +1,9 @@
project(AnyOption)
cmake_minimum_required(VERSION 2.6)
add_library(anyoption
anyoption.cpp
anyoption.h
)

View 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.

File diff suppressed because it is too large Load Diff

View 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 */

View 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}
)

View 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
&amp; &
&lt; <
&gt; >
&quot; "
&apos; '
@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 &amp; 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 "&#xA0;" or "&#160;" 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
*/

View 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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.",
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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.

View 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_

View 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++.

View 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

View 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_

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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++.

View 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_

View 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_

View 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_

View 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_

View 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_

View 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.

View 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_

View 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_

View 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_

View 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_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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_

View 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_

File diff suppressed because it is too large Load Diff

View 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_

View 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_

View 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

View 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_

File diff suppressed because it is too large Load Diff

View 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_

View 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
View 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";
}

View 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()

View 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
}

View 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
};

View 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
View 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
View 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
View 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)

View 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;
}

View 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;
};

View File

@ -0,0 +1,30 @@
#pragma once
// basic platform defines
#ifdef __linux__
#define PLATFORM_LINUX
#endif
#ifdef WIN32
#define PLATFORM_WINDOWS
#include <windows.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

View 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

View 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);
};

View 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
}

View 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
};

View 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();
}

View 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

View 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;
}

View 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();
}
}

View 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;
};

View 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()
{
}

View 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;
};

View 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;
};

View 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];
}

View 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();
}

View 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();
}

View 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());
}

View 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();
};

View 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;
}

View 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;
};

View File

@ -0,0 +1,439 @@
#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;
}
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 = m_installDir + '/' + file.path;
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());
}
if (target.empty())
{
std::string sourceFile = m_packageDir + '/' + FileUtils::fileName(file.path.c_str());
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);
}
else
{
// create the symlink
FileUtils::createSymLink(destPath.c_str(),target.c_str());
}
}
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;
std::list<std::string> args;
for (std::vector<UpdateScriptFile>::const_iterator iter = m_script->filesToInstall().begin();
iter != m_script->filesToInstall().end();
iter++)
{
if (iter->isMainBinary)
{
command = m_installDir + '/' + iter->path;
}
}
if (!command.empty())
{
LOG(Info,"Starting main application " + command);
ProcessUtils::runAsync(command,args);
}
else
{
LOG(Error,"No main binary specified in update script");
}
}
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;
}

View File

@ -0,0 +1,70 @@
#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 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;
PLATFORM_PID m_waitPid;
UpdateScript* m_script;
UpdateObserver* m_observer;
std::map<std::string,std::string> m_backups;
bool m_forceElevated;
bool m_autoClose;
};

View 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;
}
};

View 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;
};

View File

@ -0,0 +1,98 @@
#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;
file.path = elementText(element->FirstChildElement("name"));
std::string modeString = elementText(element->FirstChildElement("permissions"));
sscanf(modeString.c_str(),"%i",&file.permissions);
file.linkTarget = elementText(element->FirstChildElement("target"));
file.isMainBinary = strToBool(elementText(element->FirstChildElement("is-main-binary")));
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;
}

View File

@ -0,0 +1,86 @@
#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)
, isMainBinary(false)
{}
std::string path;
std::string linkTarget;
/** The permissions for this file, specified
* using the standard Unix mode_t values.
*/
int permissions;
bool isMainBinary;
bool operator==(const UpdateScriptFile& other) const
{
return path == other.path &&
permissions == other.permissions &&
linkTarget == other.linkTarget &&
isMainBinary == other.isMainBinary;
}
};
/** 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;
};

View File

@ -0,0 +1,156 @@
#include "UpdaterOptions.h"
#include "Log.h"
#include "AnyOption/anyoption.h"
#include "FileUtils.h"
#include "Platform.h"
#include "StringUtils.h"
#include <cstdlib>
#include <iostream>
#ifdef PLATFORM_WINDOWS
long long atoll(const char* string)
{
return _atoi64(string);
}
#endif
UpdaterOptions::UpdaterOptions()
: mode(UpdateInstaller::Setup)
, waitPid(0)
, showVersion(false)
, forceElevated(false)
, autoClose(false)
{
}
UpdateInstaller::Mode stringToMode(const std::string& modeStr)
{
if (modeStr == "main")
{
return UpdateInstaller::Main;
}
else
{
if (!modeStr.empty())
{
LOG(Error,"Unknown mode " + modeStr);
}
return UpdateInstaller::Setup;
}
}
void UpdaterOptions::parseOldFormatArg(const std::string& arg, std::string* key, std::string* value)
{
size_t pos = arg.find('=');
if (pos != std::string::npos)
{
*key = arg.substr(0,pos);
*value = arg.substr(pos+1);
}
}
// this is a compatibility function to allow the updater binary
// to be involved by legacy versions of Mendeley Desktop
// which used a different syntax for the updater's command-line
// arguments
void UpdaterOptions::parseOldFormatArgs(int argc, char** argv)
{
for (int i=0; i < argc; i++)
{
std::string key;
std::string value;
parseOldFormatArg(argv[i],&key,&value);
if (key == "CurrentDir")
{
// CurrentDir is the directory containing the main application
// binary. On Mac and Linux this differs from the root of
// the installation directory
#ifdef PLATFORM_LINUX
// the main binary is in lib/mendeleydesktop/libexec,
// go up 3 levels
installDir = FileUtils::canonicalPath((value + "/../../../").c_str());
#elif defined(PLATFORM_MAC)
// the main binary is in Contents/MacOS,
// go up 2 levels
installDir = FileUtils::canonicalPath((value + "/../../").c_str());
#elif defined(PLATFORM_WINDOWS)
// the main binary is in the root of the install directory
installDir = value;
#endif
}
else if (key == "TempDir")
{
packageDir = value;
}
else if (key == "UpdateScriptFileName")
{
scriptPath = value;
}
else if (key == "AppFileName")
{
// TODO - Store app file name
}
else if (key == "PID")
{
waitPid = static_cast<PLATFORM_PID>(atoll(value.c_str()));
}
else if (key == "--main")
{
mode = UpdateInstaller::Main;
}
}
}
void UpdaterOptions::parse(int argc, char** argv)
{
AnyOption parser;
parser.setOption("install-dir");
parser.setOption("package-dir");
parser.setOption("script");
parser.setOption("wait");
parser.setOption("mode");
parser.setFlag("version");
parser.setFlag("force-elevated");
parser.setFlag("auto-close");
parser.processCommandArgs(argc,argv);
if (parser.getValue("mode"))
{
mode = stringToMode(parser.getValue("mode"));
}
if (parser.getValue("install-dir"))
{
installDir = parser.getValue("install-dir");
}
if (parser.getValue("package-dir"))
{
packageDir = parser.getValue("package-dir");
}
if (parser.getValue("script"))
{
scriptPath = parser.getValue("script");
}
if (parser.getValue("wait"))
{
waitPid = static_cast<PLATFORM_PID>(atoll(parser.getValue("wait")));
}
showVersion = parser.getFlag("version");
forceElevated = parser.getFlag("force-elevated");
autoClose = parser.getFlag("auto-close");
if (installDir.empty())
{
// if no --install-dir argument is present, try parsing
// the command-line arguments in the old format (which uses
// a list of 'Key=Value' args)
parseOldFormatArgs(argc,argv);
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "UpdateInstaller.h"
/** Parses the command-line options to the updater binary. */
class UpdaterOptions
{
public:
UpdaterOptions();
void parse(int argc, char** argv);
UpdateInstaller::Mode mode;
std::string installDir;
std::string packageDir;
std::string scriptPath;
PLATFORM_PID waitPid;
std::string logFile;
bool showVersion;
bool forceElevated;
bool autoClose;
private:
void parseOldFormatArgs(int argc, char** argv);
static void parseOldFormatArg(const std::string& arg, std::string* key, std::string* value);
};

201
mmc_updater/src/main.cpp Normal file
View File

@ -0,0 +1,201 @@
#include "AppInfo.h"
#include "FileUtils.h"
#include "Log.h"
#include "Platform.h"
#include "ProcessUtils.h"
#include "StringUtils.h"
#include "UpdateScript.h"
#include "UpdaterOptions.h"
#include <thread>
#if defined(PLATFORM_LINUX)
#include "UpdateDialogGtkFactory.h"
#include "UpdateDialogAscii.h"
#endif
#if defined(PLATFORM_MAC)
#include "MacBundle.h"
#include "UpdateDialogCocoa.h"
#endif
#if defined(PLATFORM_WINDOWS)
#include "UpdateDialogWin32.h"
#endif
#include <iostream>
#include <memory>
#define UPDATER_VERSION "0.16"
UpdateDialog* createUpdateDialog();
void runUpdaterThread(void* arg)
{
#ifdef PLATFORM_MAC
// create an autorelease pool to free any temporary objects
// created by Cocoa whilst handling notifications from the UpdateInstaller
void* pool = UpdateDialogCocoa::createAutoreleasePool();
#endif
try
{
UpdateInstaller* installer = static_cast<UpdateInstaller*>(arg);
installer->run();
}
catch (const std::exception& ex)
{
LOG(Error,"Unexpected exception " + std::string(ex.what()));
}
#ifdef PLATFORM_MAC
UpdateDialogCocoa::releaseAutoreleasePool(pool);
#endif
}
#ifdef PLATFORM_MAC
extern unsigned char Info_plist[];
extern unsigned int Info_plist_len;
extern unsigned char mac_icns[];
extern unsigned int mac_icns_len;
bool unpackBundle(int argc, char** argv)
{
MacBundle bundle(FileUtils::tempPath(),AppInfo::name());
std::string currentExePath = ProcessUtils::currentProcessPath();
if (currentExePath.find(bundle.bundlePath()) != std::string::npos)
{
// already running from a bundle
return false;
}
LOG(Info,"Creating bundle " + bundle.bundlePath());
// create a Mac app bundle
std::string plistContent(reinterpret_cast<const char*>(Info_plist),Info_plist_len);
std::string iconContent(reinterpret_cast<const char*>(mac_icns),mac_icns_len);
bundle.create(plistContent,iconContent,ProcessUtils::currentProcessPath());
std::list<std::string> args;
for (int i = 1; i < argc; i++)
{
args.push_back(argv[i]);
}
ProcessUtils::runSync(bundle.executablePath(),args);
return true;
}
#endif
void setupConsole()
{
#ifdef PLATFORM_WINDOWS
// see http://stackoverflow.com/questions/587767/how-to-output-to-console-in-c-windows
// and http://www.libsdl.org/cgi/docwiki.cgi/FAQ_Console
AttachConsole(ATTACH_PARENT_PROCESS);
freopen( "CON", "w", stdout );
freopen( "CON", "w", stderr );
#endif
}
int main(int argc, char** argv)
{
#ifdef PLATFORM_MAC
void* pool = UpdateDialogCocoa::createAutoreleasePool();
#endif
Log::instance()->open(AppInfo::logFilePath());
#ifdef PLATFORM_MAC
// when the updater is run for the first time, create a Mac app bundle
// and re-launch the application from the bundle. This permits
// setting up bundle properties (such as application icon)
if (unpackBundle(argc,argv))
{
return 0;
}
#endif
UpdaterOptions options;
options.parse(argc,argv);
if (options.showVersion)
{
setupConsole();
std::cout << "Update installer version " << UPDATER_VERSION << std::endl;
return 0;
}
UpdateInstaller installer;
UpdateScript script;
if (!options.scriptPath.empty())
{
script.parse(FileUtils::makeAbsolute(options.scriptPath.c_str(),options.packageDir.c_str()));
}
LOG(Info,"started updater. install-dir: " + options.installDir
+ ", package-dir: " + options.packageDir
+ ", wait-pid: " + intToStr(options.waitPid)
+ ", script-path: " + options.scriptPath
+ ", mode: " + intToStr(options.mode));
installer.setMode(options.mode);
installer.setInstallDir(options.installDir);
installer.setPackageDir(options.packageDir);
installer.setScript(&script);
installer.setWaitPid(options.waitPid);
installer.setForceElevated(options.forceElevated);
installer.setAutoClose(options.autoClose);
if (options.mode == UpdateInstaller::Main)
{
LOG(Info, "Showing updater UI - auto close? " + intToStr(options.autoClose));
std::auto_ptr<UpdateDialog> dialog(createUpdateDialog());
dialog->setAutoClose(options.autoClose);
dialog->init(argc, argv);
installer.setObserver(dialog.get());
std::thread updaterThread(runUpdaterThread, &installer);
dialog->exec();
updaterThread.join();
}
else
{
installer.run();
}
#ifdef PLATFORM_MAC
UpdateDialogCocoa::releaseAutoreleasePool(pool);
#endif
return 0;
}
UpdateDialog* createUpdateDialog()
{
#if defined(PLATFORM_WINDOWS)
return new UpdateDialogWin32();
#elif defined(PLATFORM_MAC)
return new UpdateDialogCocoa();
#elif defined(PLATFORM_LINUX)
UpdateDialog* dialog = UpdateDialogGtkFactory::createDialog();
if (!dialog)
{
dialog = new UpdateDialogAscii();
}
return dialog;
#endif
}
#ifdef PLATFORM_WINDOWS
// application entry point under Windows
int CALLBACK WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
int argc = 0;
char** argv;
ProcessUtils::convertWindowsCommandLine(GetCommandLineW(),argc,argv);
return main(argc,argv);
}
#endif

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Note - The name of the application specified here must match the value
returned by AppInfo::name()
!-->
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>MultiMC Updater</string>
<key>CFBundleIconFile</key>
<string>MultiMC Updater.icns</string>
<key>CFBundleIdentifier</key>
<string>org.multimc.MultiMCUpdater</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>LSMinimumSystemVersion</key>
<string>10.5</string>
<key>LSMinimumSystemVersionByArchitecture</key>
<dict>
<key>i386</key>
<string>10.5.0</string>
<key>x86_64</key>
<string>10.5.0</string>
</dict>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show More