mirror of
https://github.com/jmarshall23/msword.git
synced 2026-08-11 23:50:53 +02:00
Crash fixes for saveas/about dialog.
This commit is contained in:
@@ -992,3 +992,11 @@ add_test(NAME opus_word1_font_typing_test
|
||||
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --font-typing
|
||||
)
|
||||
set_tests_properties(opus_word1_font_typing_test PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME opus_word1_about_test
|
||||
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --about
|
||||
)
|
||||
set_tests_properties(opus_word1_about_test PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME opus_word1_save_as_test
|
||||
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --save-as
|
||||
)
|
||||
set_tests_properties(opus_word1_save_as_test PROPERTIES TIMEOUT 20)
|
||||
|
||||
+37
-1
@@ -955,12 +955,17 @@ CMB *pcmb;
|
||||
CMD CmdAbout(pcmb)
|
||||
CMB *pcmb;
|
||||
{
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64AboutStage", (HANDLE)(INT_PTR)1);
|
||||
#endif
|
||||
if (FCmdFillCab())
|
||||
{
|
||||
extern BOOL f8087;
|
||||
long l;
|
||||
char st[cchMaxSz];
|
||||
#ifndef OPUS_X64
|
||||
long (FAR PASCAL *lpfn)();
|
||||
#endif
|
||||
|
||||
/* values come from version.h */
|
||||
FSetCabSz(pcmb->hcab, szApp,
|
||||
@@ -969,8 +974,27 @@ CMB *pcmb;
|
||||
Iag(CABABOUT, hszAboutVersion));
|
||||
FSetCabSz(pcmb->hcab, SzShared(szCopyrightDef),
|
||||
Iag(CABABOUT, hszAboutCopyright));
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64AboutStage", (HANDLE)(INT_PTR)2);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OPUS_X64
|
||||
/* Win16 KERNEL ordinal 169 was GetFreeSpace. It does not exist on
|
||||
* Win64; use the native system-memory API for the same About field. */
|
||||
{
|
||||
MEMORYSTATUSEX memoryStatus;
|
||||
ULONGLONG freeKb;
|
||||
memoryStatus.dwLength = sizeof(memoryStatus);
|
||||
if (GlobalMemoryStatusEx(&memoryStatus))
|
||||
{
|
||||
freeKb = memoryStatus.ullAvailPhys >> 10;
|
||||
l = (long) min(freeKb, 0x7fffffffULL);
|
||||
}
|
||||
else
|
||||
l = GlobalCompact(0L) >> 10;
|
||||
}
|
||||
#else
|
||||
if (vwWinVersion >= 0x0300 &&
|
||||
(lpfn = GetProcAddress(GetModuleHandle(SzFrame("KERNEL")),
|
||||
MAKEINTRESOURCE(idoGetFreeSpace))) != NULL)
|
||||
@@ -978,6 +1002,7 @@ CMB *pcmb;
|
||||
l = (*lpfn)(0) >> 10;
|
||||
else
|
||||
l = GlobalCompact(0L) >> 10;
|
||||
#endif
|
||||
|
||||
BuildStMstRgw(mstAboutKB, &l, st, cchMaxSz, hNil);
|
||||
FSetCabSt(pcmb->hcab, st, Iag(CABABOUT, hszAboutMem));
|
||||
@@ -998,6 +1023,9 @@ CMB *pcmb;
|
||||
if (!fInitialized)
|
||||
InitMath();
|
||||
}
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64AboutStage", (HANDLE)(INT_PTR)3);
|
||||
#endif
|
||||
|
||||
FSetCabSz(pcmb->hcab, f8087 ? SzSharedKey("Present", Present) :
|
||||
szNone, Iag(CABABOUT, hszAboutMath));
|
||||
@@ -1013,9 +1041,17 @@ CMB *pcmb;
|
||||
if (pcmb->fDialog || pcmb->fAction)
|
||||
{
|
||||
char dlt[sizeof(dltAbout)];
|
||||
TMC tmc;
|
||||
|
||||
BltDlt(dltAbout, dlt);
|
||||
if (TmcOurDoDlg(dlt, pcmb) == tmcError)
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64AboutStage", (HANDLE)(INT_PTR)4);
|
||||
#endif
|
||||
tmc = TmcOurDoDlg(dlt, pcmb);
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64AboutStage", (HANDLE)(INT_PTR)(100 + tmc));
|
||||
#endif
|
||||
if (tmc == tmcError)
|
||||
{
|
||||
return cmdError;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,11 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#ifdef OPUS_X64
|
||||
SHORT w1, w2;
|
||||
#else
|
||||
int w1, w2;
|
||||
#endif
|
||||
} CMPNUMRET;
|
||||
|
||||
/* really CmpNum returns a long */
|
||||
@@ -82,8 +86,13 @@ typedef union
|
||||
/* temporary simulation stuff until we get the real mathpack */
|
||||
typedef union {
|
||||
struct {
|
||||
#ifdef OPUS_X64
|
||||
WORD w1;
|
||||
SHORT w0;
|
||||
#else
|
||||
unsigned w1;
|
||||
int w0;
|
||||
#endif
|
||||
};
|
||||
LONG l;
|
||||
} NUMCVT;
|
||||
|
||||
+19
-3
@@ -253,9 +253,13 @@ LRet:
|
||||
/* C M D S A V E A S */
|
||||
/* %%Function:CmdSaveAs %%Owner:peterj */
|
||||
CMD CmdSaveAs(pcmb)
|
||||
CMB * pcmb;
|
||||
{
|
||||
CMD cmd;
|
||||
BOOL fDirty;
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64SaveAsStage", (HANDLE)(INT_PTR)1);
|
||||
#endif
|
||||
|
||||
if (selCur.doc == docNil)
|
||||
{
|
||||
@@ -272,6 +276,9 @@ CMD CmdSaveAs(pcmb)
|
||||
{
|
||||
DoPostSaveDoc(pcmb, fDirty);
|
||||
}
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64SaveAsStage", (HANDLE)(INT_PTR)(100 + cmd));
|
||||
#endif
|
||||
LRet:
|
||||
/* at all costs, avoid telling the user to save his work when giving an
|
||||
error message for save! */
|
||||
@@ -795,8 +802,16 @@ CMB * pcmb;
|
||||
pcab = *pcmb->hcab;
|
||||
pcab->sab = 0;
|
||||
pcab->fOptions = fFalse;
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64SaveAsStage", (HANDLE)(INT_PTR)2);
|
||||
#endif
|
||||
|
||||
switch (TmcOurDoDlg(dlt, pcmb))
|
||||
{
|
||||
TMC tmc = TmcOurDoDlg(dlt, pcmb);
|
||||
#ifdef OPUS_X64
|
||||
SetPropA(vhwndApp, "OpusX64SaveAsStage", (HANDLE)(INT_PTR)(200 + tmc));
|
||||
#endif
|
||||
switch (tmc)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
default:
|
||||
@@ -812,9 +827,10 @@ CMB * pcmb;
|
||||
cmd = cmdCancelled;
|
||||
break;
|
||||
|
||||
case tmcOK:
|
||||
cmd = cmdOK;
|
||||
case tmcOK:
|
||||
cmd = cmdOK;
|
||||
}
|
||||
}
|
||||
|
||||
pcmb->bcm = bcmSav;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/*
|
||||
* Compile-only template boundary for Opus/dlg/about.des. The full template
|
||||
* must be regenerated by the ported historical dialog compiler before the
|
||||
* About dialog is runtime-active.
|
||||
*/
|
||||
DLG_CONST DLT dltAbout = { 0 };
|
||||
#pragma once
|
||||
|
||||
/* Regenerated from Opus/dlg/about.des. The x64 SDM compatibility layer
|
||||
materializes the archived controls as native Win32 controls. */
|
||||
extern BOOL FDlgAbout(DLM, TMC, WORD, WORD, WORD);
|
||||
DLG_CONST DLT dltAbout = {
|
||||
{ 85, 55, 205, 115 }, IDDAbout, tmcOK, FDlgAbout,
|
||||
13, bdrSysMenu, { 0 }
|
||||
};
|
||||
|
||||
@@ -131,9 +131,11 @@ constexpr Word kDlmDialogClick = 0x0012;
|
||||
constexpr UINT kWmCommitRibbonSelection = WM_APP + 0x352;
|
||||
constexpr Word kIddNewDoc = 2;
|
||||
constexpr Word kIddOpen = 3;
|
||||
constexpr Word kIddSaveAs = 4;
|
||||
constexpr Word kIddCharacter = 16;
|
||||
constexpr Word kIddApplyStyle = 23;
|
||||
constexpr Word kIddDefineStyle = 24;
|
||||
constexpr Word kIddAbout = 44;
|
||||
constexpr Word kCxtRibbonIconBar = 0x8005;
|
||||
constexpr Word kCxtRulerIconBar = 0x8006;
|
||||
constexpr Tmc kTmcOk = 1;
|
||||
@@ -173,6 +175,16 @@ constexpr Tmc kTmcOpenFileList = 0x0401;
|
||||
constexpr Tmc kTmcOpenFileDir = 0x0402;
|
||||
constexpr Tmc kTmcOpenCatalog = 0x0403;
|
||||
constexpr Tmc kTmcOpenReadOnly = 0x0404;
|
||||
constexpr Tmc kTmcSaveFile = kTmcUserMin;
|
||||
constexpr Tmc kTmcSaveOptions = kTmcUserMin + 1;
|
||||
constexpr Tmc kTmcSaveDirectoryText = kTmcUserMin + 2;
|
||||
constexpr Tmc kTmcSaveDirectoryList = kTmcUserMin + 3;
|
||||
constexpr Tmc kTmcSaveDirectory = kTmcUserMin + 4;
|
||||
constexpr Tmc kTmcSaveFormatPrompt = kTmcUserMin + 5;
|
||||
constexpr Tmc kTmcSaveFormat = kTmcUserMin + 6;
|
||||
constexpr Tmc kTmcSaveQuick = kTmcUserMin + 7;
|
||||
constexpr Tmc kTmcSaveBackup = kTmcUserMin + 8;
|
||||
constexpr Tmc kTmcSaveLockAnnotations = kTmcUserMin + 9;
|
||||
constexpr Word kOpenFileNameIag = 1;
|
||||
constexpr std::size_t kOpenCabBytes = 24;
|
||||
constexpr std::size_t kOpenReadOnlyOffset = 20;
|
||||
@@ -246,6 +258,7 @@ ATOM ensure_native_dialog_class() {
|
||||
HWND create_dialog_host(const DialogState& dialog, const Dli* initializer) {
|
||||
if (dialog.modal &&
|
||||
(dialog.hid == kIddOpen || dialog.hid == kIddNewDoc ||
|
||||
dialog.hid == kIddSaveAs || dialog.hid == kIddAbout ||
|
||||
dialog.hid == kIddCharacter || dialog.hid == kIddApplyStyle ||
|
||||
dialog.hid == kIddDefineStyle)) {
|
||||
if (ensure_native_dialog_class() == 0) {
|
||||
@@ -291,6 +304,9 @@ HWND create_dialog_host(const DialogState& dialog, const Dli* initializer) {
|
||||
case kIddNewDoc:
|
||||
caption = "New";
|
||||
break;
|
||||
case kIddSaveAs:
|
||||
caption = "Save As";
|
||||
break;
|
||||
case kIddCharacter:
|
||||
caption = "Character";
|
||||
break;
|
||||
@@ -300,6 +316,9 @@ HWND create_dialog_host(const DialogState& dialog, const Dli* initializer) {
|
||||
case kIddDefineStyle:
|
||||
caption = "Define Style";
|
||||
break;
|
||||
case kIddAbout:
|
||||
caption = "About Microsoft Word";
|
||||
break;
|
||||
}
|
||||
return CreateWindowExA(
|
||||
extended_style, "OpusSdmDialog", caption, style, x, y, width,
|
||||
@@ -783,6 +802,247 @@ void materialize_open_template(DialogState& dialog) {
|
||||
read_open_cab(dialog);
|
||||
}
|
||||
|
||||
std::string read_cab_string(const DialogState& dialog, const Word iag) {
|
||||
char buffer[1024] = {};
|
||||
if (dialog.cab != nullptr) {
|
||||
GetCabSz(dialog.cab, buffer, static_cast<Word>(sizeof(buffer)), iag);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void materialize_about_template(DialogState& dialog) {
|
||||
if (dialog.hid != kIddAbout || dialog.window == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto static_from_cab = [&dialog](const Word iag, const Rec& rec,
|
||||
const DWORD alignment) {
|
||||
const std::string text = read_cab_string(dialog, iag);
|
||||
create_untracked_control(dialog, "STATIC", text.c_str(), rec,
|
||||
alignment);
|
||||
};
|
||||
static_from_cab(1, {4, 5, 192, 9}, SS_CENTER);
|
||||
static_from_cab(2, {4, 22, 192, 9}, SS_CENTER);
|
||||
static_from_cab(3, {4, 34, 192, 9}, SS_CENTER);
|
||||
create_native_control(dialog, kTmcOk, "BUTTON", "OK",
|
||||
{84, 48, 34, 14},
|
||||
WS_TABSTOP | BS_DEFPUSHBUTTON);
|
||||
create_untracked_control(dialog, "STATIC", "", {0, 64, 205, 4},
|
||||
SS_ETCHEDHORZ);
|
||||
create_untracked_control(dialog, "STATIC", "Conventional Memory:",
|
||||
{5, 74, 110, 9}, SS_RIGHT);
|
||||
create_untracked_control(dialog, "STATIC", "Expanded Memory:",
|
||||
{5, 83, 110, 9}, SS_RIGHT);
|
||||
create_untracked_control(dialog, "STATIC", "Math Co-processor:",
|
||||
{5, 92, 110, 9}, SS_RIGHT);
|
||||
create_untracked_control(dialog, "STATIC", "Disk Space:",
|
||||
{5, 101, 110, 9}, SS_RIGHT);
|
||||
static_from_cab(4, {120, 74, 76, 9}, SS_LEFT);
|
||||
static_from_cab(5, {120, 83, 76, 9}, SS_LEFT);
|
||||
static_from_cab(6, {120, 92, 76, 9}, SS_LEFT);
|
||||
static_from_cab(7, {120, 101, 76, 9}, SS_LEFT);
|
||||
dialog.caption = "About Microsoft Word";
|
||||
dialog.native_modal = true;
|
||||
}
|
||||
|
||||
struct CabSaveNative {
|
||||
Word simple_words;
|
||||
Word handle_words;
|
||||
Word sab;
|
||||
Word alignment;
|
||||
char** file_name;
|
||||
int directory_list;
|
||||
int format;
|
||||
int quick_save;
|
||||
int backup;
|
||||
int lock_annotations;
|
||||
int options;
|
||||
};
|
||||
|
||||
CabSaveNative* save_cab(DialogState& dialog) {
|
||||
if (dialog.cab == nullptr || *dialog.cab == nullptr ||
|
||||
OpusCbOfH(dialog.cab) < sizeof(CabSaveNative)) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<CabSaveNative*>(*dialog.cab);
|
||||
}
|
||||
|
||||
void set_save_check(DialogState& dialog, const Tmc tmc, const bool checked) {
|
||||
auto& state = dialog.controls[tmc];
|
||||
state.value = checked;
|
||||
if (state.window != nullptr && IsWindow(state.window)) {
|
||||
SendMessageA(state.window, BM_SETCHECK,
|
||||
checked ? BST_CHECKED : BST_UNCHECKED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void populate_save_directories(DialogState& dialog) {
|
||||
char directory[32768] = {};
|
||||
if (dialog.current_directory.empty()) {
|
||||
GetCurrentDirectoryA(static_cast<DWORD>(sizeof(directory)), directory);
|
||||
dialog.current_directory = directory;
|
||||
}
|
||||
|
||||
auto& list = dialog.controls[kTmcSaveDirectoryList];
|
||||
list.entries.clear();
|
||||
if (list.window != nullptr) {
|
||||
SendMessageA(list.window, LB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
|
||||
char parent[32768] = {};
|
||||
const std::string parent_spec = join_path(dialog.current_directory, "..");
|
||||
if (GetFullPathNameA(parent_spec.c_str(),
|
||||
static_cast<DWORD>(sizeof(parent)), parent,
|
||||
nullptr) != 0 &&
|
||||
_stricmp(parent, dialog.current_directory.c_str()) != 0) {
|
||||
add_native_list_entry(dialog, kTmcSaveDirectoryList, "[..]");
|
||||
}
|
||||
|
||||
WIN32_FIND_DATAA find_data{};
|
||||
HANDLE find = FindFirstFileA(
|
||||
join_path(dialog.current_directory, "*.*").c_str(), &find_data);
|
||||
if (find != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 &&
|
||||
std::strcmp(find_data.cFileName, ".") != 0 &&
|
||||
std::strcmp(find_data.cFileName, "..") != 0) {
|
||||
add_native_list_entry(
|
||||
dialog, kTmcSaveDirectoryList,
|
||||
"[" + std::string(find_data.cFileName) + "]");
|
||||
}
|
||||
} while (FindNextFileA(find, &find_data));
|
||||
FindClose(find);
|
||||
}
|
||||
|
||||
auto& label = dialog.controls[kTmcSaveDirectory];
|
||||
label.text = dialog.current_directory;
|
||||
if (label.window != nullptr) {
|
||||
SetWindowTextA(label.window, label.text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void set_save_options_visible(DialogState& dialog, const bool visible) {
|
||||
const Tmc option_controls[] = {
|
||||
kTmcSaveFormatPrompt, kTmcSaveFormat, kTmcSaveQuick,
|
||||
kTmcSaveBackup, kTmcSaveLockAnnotations};
|
||||
for (const Tmc tmc : option_controls) {
|
||||
auto found = dialog.controls.find(tmc);
|
||||
if (found == dialog.controls.end()) {
|
||||
continue;
|
||||
}
|
||||
found->second.visible = visible;
|
||||
if (found->second.window != nullptr) {
|
||||
ShowWindow(found->second.window, visible ? SW_SHOWNA : SW_HIDE);
|
||||
}
|
||||
}
|
||||
if (dialog.window == nullptr || !IsWindow(dialog.window)) {
|
||||
return;
|
||||
}
|
||||
RECT client{0, 0, scaled_x(150), scaled_y(visible ? 157 : 102)};
|
||||
const DWORD style = static_cast<DWORD>(GetWindowLongPtrA(
|
||||
dialog.window, GWL_STYLE));
|
||||
const DWORD extended_style = static_cast<DWORD>(GetWindowLongPtrA(
|
||||
dialog.window, GWL_EXSTYLE));
|
||||
AdjustWindowRectEx(&client, style, false, extended_style);
|
||||
SetWindowPos(dialog.window, nullptr, 0, 0,
|
||||
client.right - client.left, client.bottom - client.top,
|
||||
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
void read_save_cab(DialogState& dialog) {
|
||||
auto& edit = dialog.controls[kTmcSaveFile];
|
||||
edit.text = read_cab_string(dialog, 1);
|
||||
if (edit.window != nullptr) {
|
||||
SetWindowTextA(edit.window, edit.text.c_str());
|
||||
}
|
||||
|
||||
if (auto* cab = save_cab(dialog); cab != nullptr) {
|
||||
set_save_check(dialog, kTmcSaveQuick, cab->quick_save != 0);
|
||||
set_save_check(dialog, kTmcSaveBackup, cab->backup != 0);
|
||||
set_save_check(dialog, kTmcSaveLockAnnotations,
|
||||
cab->lock_annotations != 0);
|
||||
auto& format = dialog.controls[kTmcSaveFormat];
|
||||
format.value = static_cast<Word>(cab->format);
|
||||
const std::string entry = "Current document format";
|
||||
format.entries = {entry};
|
||||
add_entry_to_native_control(format, entry);
|
||||
if (format.window != nullptr) {
|
||||
SendMessageA(format.window, CB_SETCURSEL, 0, 0);
|
||||
}
|
||||
}
|
||||
populate_save_directories(dialog);
|
||||
}
|
||||
|
||||
void sync_save_cab(DialogState& dialog) {
|
||||
auto& edit = dialog.controls[kTmcSaveFile];
|
||||
if (edit.window != nullptr && IsWindow(edit.window)) {
|
||||
const int length = GetWindowTextLengthA(edit.window);
|
||||
std::vector<char> buffer(static_cast<std::size_t>(length) + 1);
|
||||
GetWindowTextA(edit.window, buffer.data(),
|
||||
static_cast<int>(buffer.size()));
|
||||
edit.text = buffer.data();
|
||||
}
|
||||
if (dialog.cab != nullptr) {
|
||||
FSetCabSz(dialog.cab, edit.text.c_str(), 1);
|
||||
}
|
||||
if (auto* cab = save_cab(dialog); cab != nullptr) {
|
||||
const auto checked = [&dialog](const Tmc tmc) {
|
||||
const auto found = dialog.controls.find(tmc);
|
||||
return found != dialog.controls.end() &&
|
||||
found->second.window != nullptr &&
|
||||
SendMessageA(found->second.window, BM_GETCHECK, 0, 0) ==
|
||||
BST_CHECKED;
|
||||
};
|
||||
cab->quick_save = checked(kTmcSaveQuick);
|
||||
cab->backup = checked(kTmcSaveBackup);
|
||||
cab->lock_annotations = checked(kTmcSaveLockAnnotations);
|
||||
cab->options = dialog.sab == 0 &&
|
||||
dialog.controls[kTmcSaveFormat].visible;
|
||||
}
|
||||
}
|
||||
|
||||
void materialize_save_as_template(DialogState& dialog) {
|
||||
if (dialog.hid != kIddSaveAs || dialog.window == nullptr) {
|
||||
return;
|
||||
}
|
||||
create_static_text(dialog, "Save File &Name:", {4, 2, 60, 9});
|
||||
create_native_control(dialog, kTmcSaveFile, "EDIT", "",
|
||||
{4, 13, 81, 12},
|
||||
WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL);
|
||||
create_native_control(dialog, kTmcOk, "BUTTON", "OK", {97, 6, 47, 14},
|
||||
WS_TABSTOP | BS_DEFPUSHBUTTON);
|
||||
create_native_control(dialog, kTmcCancel, "BUTTON", "Cancel",
|
||||
{97, 25, 47, 14}, WS_TABSTOP | BS_PUSHBUTTON);
|
||||
create_native_control(dialog, kTmcSaveOptions, "BUTTON", "&Options >>",
|
||||
{97, 42, 47, 14}, WS_TABSTOP | BS_PUSHBUTTON);
|
||||
create_native_control(dialog, kTmcSaveDirectoryText, "STATIC",
|
||||
"&Directories:", {4, 38, 73, 9}, SS_LEFT);
|
||||
create_native_control(dialog, kTmcSaveDirectoryList, "LISTBOX", "",
|
||||
{4, 50, 89, 48},
|
||||
WS_TABSTOP | WS_BORDER | WS_VSCROLL | LBS_NOTIFY |
|
||||
LBS_SORT | LBS_NOINTEGRALHEIGHT);
|
||||
create_native_control(dialog, kTmcSaveDirectory, "STATIC", "",
|
||||
{4, 27, 90, 9}, SS_LEFT);
|
||||
create_native_control(dialog, kTmcSaveFormatPrompt, "STATIC",
|
||||
"&File Format:", {4, 105, 50, 9}, SS_LEFT);
|
||||
create_native_control(dialog, kTmcSaveFormat, "COMBOBOX", "",
|
||||
{55, 103, 91, 72},
|
||||
WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST);
|
||||
create_native_control(dialog, kTmcSaveQuick, "BUTTON", "Fast &Save",
|
||||
{4, 116, 46, 12},
|
||||
WS_TABSTOP | BS_AUTOCHECKBOX);
|
||||
create_native_control(dialog, kTmcSaveBackup, "BUTTON", "Create &Backup",
|
||||
{4, 128, 62, 12},
|
||||
WS_TABSTOP | BS_AUTOCHECKBOX);
|
||||
create_native_control(dialog, kTmcSaveLockAnnotations, "BUTTON",
|
||||
"&Lock for Annotations", {4, 140, 92, 12},
|
||||
WS_TABSTOP | BS_AUTOCHECKBOX);
|
||||
dialog.caption = "Save As";
|
||||
dialog.native_modal = true;
|
||||
read_save_cab(dialog);
|
||||
set_save_options_visible(dialog, false);
|
||||
}
|
||||
|
||||
bool is_font_name_control(const DialogState& dialog, const Tmc tmc) {
|
||||
return (dialog.hid == kCxtRibbonIconBar && tmc == kTmcUserMin) ||
|
||||
(dialog.hid == kIddCharacter && tmc == kTmcCharacterName);
|
||||
@@ -1546,6 +1806,8 @@ void enter_open_directory(DialogState& dialog) {
|
||||
void finish_native_dialog(DialogState& dialog, const Tmc result) {
|
||||
if (dialog.hid == kIddOpen) {
|
||||
sync_open_cab(dialog);
|
||||
} else if (dialog.hid == kIddSaveAs) {
|
||||
sync_save_cab(dialog);
|
||||
} else if (dialog.hid == kIddNewDoc) {
|
||||
sync_new_cab(dialog);
|
||||
} else if (dialog.hid == kIddApplyStyle) {
|
||||
@@ -1593,6 +1855,17 @@ void handle_dialog_command(const Hdlg handle, const WPARAM w_param,
|
||||
GetWindowTextA(found->second.window, text.data(),
|
||||
static_cast<int>(text.size()));
|
||||
found->second.text = text.data();
|
||||
} else if (tmc == kTmcSaveFile && dialog->hid == kIddSaveAs) {
|
||||
const int length = GetWindowTextLengthA(found->second.window);
|
||||
std::vector<char> text(static_cast<std::size_t>(length) + 1);
|
||||
GetWindowTextA(found->second.window, text.data(),
|
||||
static_cast<int>(text.size()));
|
||||
found->second.text = text.data();
|
||||
} else if (dialog->hid == kIddSaveAs &&
|
||||
(tmc == kTmcSaveQuick || tmc == kTmcSaveBackup ||
|
||||
tmc == kTmcSaveLockAnnotations)) {
|
||||
found->second.value = static_cast<Word>(SendMessageA(
|
||||
found->second.window, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
||||
}
|
||||
}
|
||||
g_current_dialog = handle;
|
||||
@@ -1685,6 +1958,24 @@ void handle_dialog_command(const Hdlg handle, const WPARAM w_param,
|
||||
invoke_dialog_proc(*dialog, kDlmChange, tmc);
|
||||
return;
|
||||
}
|
||||
if (dialog->hid == kIddSaveAs && tmc == kTmcSaveFile &&
|
||||
notification == EN_CHANGE) {
|
||||
invoke_dialog_proc(*dialog, kDlmChange, tmc);
|
||||
return;
|
||||
}
|
||||
if (dialog->hid == kIddSaveAs && tmc == kTmcSaveDirectoryList &&
|
||||
(notification == LBN_SELCHANGE || notification == LBN_DBLCLK)) {
|
||||
const LRESULT selection = SendMessageA(
|
||||
found->second.window, LB_GETCURSEL, 0, 0);
|
||||
if (selection != LB_ERR) {
|
||||
found->second.value = static_cast<Word>(selection);
|
||||
}
|
||||
invoke_dialog_proc(*dialog,
|
||||
notification == LBN_DBLCLK ? kDlmDblClk
|
||||
: kDlmClick,
|
||||
tmc, found->second.value);
|
||||
return;
|
||||
}
|
||||
if (dialog->hid == kIddOpen && tmc == kTmcOpenFileList &&
|
||||
(notification == LBN_SELCHANGE || notification == LBN_DBLCLK)) {
|
||||
select_open_file(*dialog);
|
||||
@@ -1723,7 +2014,10 @@ void handle_dialog_command(const Hdlg handle, const WPARAM w_param,
|
||||
tmc == kTmcSummary)) {
|
||||
finish_native_dialog(*dialog, tmc);
|
||||
} else {
|
||||
invoke_dialog_proc(*dialog, kDlmClick, tmc);
|
||||
const Word new_value = found == dialog->controls.end()
|
||||
? 0
|
||||
: found->second.value;
|
||||
invoke_dialog_proc(*dialog, kDlmClick, tmc, new_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1868,6 +2162,8 @@ Hdlg HdlgStartDlg(DltHeader** dialog_template, Hcab cab, Dli* initializer) {
|
||||
materialize_icon_bar_template(g_dialogs.at(handle));
|
||||
materialize_new_template(g_dialogs.at(handle));
|
||||
materialize_open_template(g_dialogs.at(handle));
|
||||
materialize_save_as_template(g_dialogs.at(handle));
|
||||
materialize_about_template(g_dialogs.at(handle));
|
||||
materialize_character_template(g_dialogs.at(handle));
|
||||
materialize_apply_style_template(g_dialogs.at(handle));
|
||||
materialize_define_style_template(g_dialogs.at(handle));
|
||||
@@ -2063,6 +2359,9 @@ void SdmScaleRec(Rec*) {}
|
||||
|
||||
int FSetDlgSab(Word sab) {
|
||||
g_dialog.sab = sab;
|
||||
if (g_dialog.hid == kIddSaveAs) {
|
||||
set_save_options_visible(g_dialog, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Word SabGetDlg() { return g_dialog.sab; }
|
||||
@@ -2071,7 +2370,14 @@ void SetTmcVal_sdm21(Tmc tmc, Word value) {
|
||||
auto& state = control(tmc);
|
||||
state.value = value;
|
||||
if (state.window != nullptr && IsWindow(state.window)) {
|
||||
SendMessageA(state.window, CB_SETCURSEL, value, 0);
|
||||
if (window_is_class(state.window, "BUTTON")) {
|
||||
SendMessageA(state.window, BM_SETCHECK,
|
||||
value ? BST_CHECKED : BST_UNCHECKED, 0);
|
||||
} else if (window_is_class(state.window, "LISTBOX")) {
|
||||
SendMessageA(state.window, LB_SETCURSEL, value, 0);
|
||||
} else {
|
||||
SendMessageA(state.window, CB_SETCURSEL, value, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Word ValGetTmc(Tmc tmc) {
|
||||
@@ -2080,6 +2386,18 @@ Word ValGetTmc(Tmc tmc) {
|
||||
if (found == g_dialog.controls.end()) {
|
||||
return 0;
|
||||
}
|
||||
if (found->second.window != nullptr &&
|
||||
window_is_class(found->second.window, "BUTTON")) {
|
||||
found->second.value = static_cast<Word>(SendMessageA(
|
||||
found->second.window, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
||||
} else if (found->second.window != nullptr &&
|
||||
window_is_class(found->second.window, "LISTBOX")) {
|
||||
const LRESULT selection = SendMessageA(
|
||||
found->second.window, LB_GETCURSEL, 0, 0);
|
||||
if (selection != LB_ERR) {
|
||||
found->second.value = static_cast<Word>(selection);
|
||||
}
|
||||
}
|
||||
refresh_font_control_value(g_dialog, value_tmc, found->second, true);
|
||||
return found->second.value;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,16 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
/* A null Win16 module handle made GetProcAddress fail. On current Windows,
|
||||
* passing that invalid handle can instead search the process image. Opus
|
||||
* probes retired modules such as KERNEL, GDI, and USER by ordinal, so an
|
||||
* unsuccessful probe must not be allowed to resolve an unrelated WORD1
|
||||
* export with the same ordinal. */
|
||||
static __inline FARPROC OpusGetProcAddress(HMODULE module, LPCSTR name) {
|
||||
return module != NULL ? GetProcAddress(module, name) : NULL;
|
||||
}
|
||||
#define GetProcAddress OpusGetProcAddress
|
||||
|
||||
/* The SDK retains ChangeMenu only for source compatibility, with its Win16
|
||||
* UINT submenu parameter. That truncates HMENU on Win64. */
|
||||
#ifdef ChangeMenu
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/*
|
||||
* Placeholder template boundary for the checked-in saveas.des description.
|
||||
* It lets the original save algorithms compile while the missing historical
|
||||
* dialog compiler is being ported. This template must be regenerated before
|
||||
* the Save As dialog is made runtime-active.
|
||||
*/
|
||||
DLG_CONST DLT dltSaveAs = { 0 };
|
||||
#pragma once
|
||||
|
||||
/* Regenerated from Opus/dlg/saveas.des. The x64 SDM compatibility layer
|
||||
materializes the archived controls as native Win32 controls. */
|
||||
extern BOOL FDlgSaveAs(DLM, TMC, WORD, WORD, WORD);
|
||||
DLG_CONST DLT dltSaveAs = {
|
||||
{ 14, 18, 150, 102 }, IDDSaveAs, tmcSavFile, FDlgSaveAs,
|
||||
13, bdrSysMenu, { 0 }
|
||||
};
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
#include "opus_x64_compat.h"
|
||||
|
||||
#undef native
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#ifndef NEAR
|
||||
#define NEAR
|
||||
#endif
|
||||
extern "C" {
|
||||
#include "sdmver.h"
|
||||
#include "sdm.h"
|
||||
}
|
||||
|
||||
/* Reconstructed outputs of Microsoft's missing Dialog Editor compiler. The
|
||||
original MKCMD parser consumes only each header's numeric cabi definition;
|
||||
compiling the contracts here lets sizeof reflect the native pointer width
|
||||
and alignment used by the x64 source modules. */
|
||||
#include "about.hs"
|
||||
#include "abspos.hs"
|
||||
#include "apprun.hs"
|
||||
#include "asgn2key.hs"
|
||||
#include "asgn2mnu.hs"
|
||||
#include "autosave.hs"
|
||||
#include "bookmark.hs"
|
||||
#include "catalog.hs"
|
||||
#include "catprog.hs"
|
||||
#include "catsrch.hs"
|
||||
#include "char.hs"
|
||||
#include "chgpr.hs"
|
||||
#include "cmpfile.hs"
|
||||
#include "confirmr.hs"
|
||||
#include "cust.hs"
|
||||
#include "doc.hs"
|
||||
#include "docstat.hs"
|
||||
#include "docsum.hs"
|
||||
#include "edmacro.hs"
|
||||
#include "edstyle.hs"
|
||||
#include "footnote.hs"
|
||||
#include "glsy.hs"
|
||||
#include "goto.hs"
|
||||
#include "header.hs"
|
||||
#include "hyphen.hs"
|
||||
#include "index.hs"
|
||||
#include "indexent.hs"
|
||||
#include "insbreak.hs"
|
||||
#include "insfield.hs"
|
||||
#include "insfile.hs"
|
||||
#include "inspgnum.hs"
|
||||
#include "inspic.hs"
|
||||
#include "mrgstyle.hs"
|
||||
#include "new.hs"
|
||||
#include "newopen.hs"
|
||||
#include "open.hs"
|
||||
#include "para.hs"
|
||||
#include "password.hs"
|
||||
#include "pastelnk.hs"
|
||||
#include "pict.hs"
|
||||
#include "print.hs"
|
||||
#include "printmrg.hs"
|
||||
#include "prompt.hs"
|
||||
#include "recorder.hs"
|
||||
#include "renmacro.hs"
|
||||
#include "renstyle.hs"
|
||||
#include "renum.hs"
|
||||
#include "replace.hs"
|
||||
#include "revmark.hs"
|
||||
#include "ribbon.hs"
|
||||
#include "ribbon3.hs"
|
||||
#include "ruler.hs"
|
||||
#include "ruler3.hs"
|
||||
#include "runmacro.hs"
|
||||
#include "saveas.hs"
|
||||
#include "search.hs"
|
||||
#include "sect.hs"
|
||||
#include "showvars.hs"
|
||||
#include "sort.hs"
|
||||
#include "spell.hs"
|
||||
#include "spellmm.hs"
|
||||
#include "style.hs"
|
||||
#include "tablecmd.hs"
|
||||
#include "tablefmt.hs"
|
||||
#include "tableins.hs"
|
||||
#include "tabletxt.hs"
|
||||
#include "tabs.hs"
|
||||
#include "thesaur.hs"
|
||||
#include "toc.hs"
|
||||
#include "username.hs"
|
||||
#include "usrdlg.hs"
|
||||
#include "viewpref.hs"
|
||||
#include "vrfcnvtr.hs"
|
||||
|
||||
namespace {
|
||||
|
||||
bool WriteCabi(const std::filesystem::path& directory, const char* file_name,
|
||||
const char* macro_name, const unsigned value) {
|
||||
std::ofstream output(directory / file_name, std::ios::trunc);
|
||||
if (!output) {
|
||||
return false;
|
||||
}
|
||||
output << "#define " << macro_name << ' ' << value << '\n';
|
||||
return output.good();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#define WRITE_CABI(file_name, macro_name) \
|
||||
success = WriteCabi(output_directory, file_name, #macro_name, \
|
||||
static_cast<unsigned>(macro_name)) && \
|
||||
success
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
return 2;
|
||||
}
|
||||
const std::filesystem::path output_directory(argv[1]);
|
||||
std::error_code error;
|
||||
std::filesystem::create_directories(output_directory, error);
|
||||
if (error) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
WRITE_CABI("about.hs", cabiCABABOUT);
|
||||
WRITE_CABI("abspos.hs", cabiCABABSPOS);
|
||||
WRITE_CABI("apprun.hs", cabiCABAPPRUN);
|
||||
WRITE_CABI("asgn2key.hs", cabiCABCHANGEKEYS);
|
||||
WRITE_CABI("asgn2mnu.hs", cabiCABASSIGNTOMENU);
|
||||
WRITE_CABI("autosave.hs", cabiCABAUTOSAVE);
|
||||
WRITE_CABI("bookmark.hs", cabiCABINSBOOKMARK);
|
||||
WRITE_CABI("catalog.hs", cabiCABCATALOG);
|
||||
WRITE_CABI("catprog.hs", cabiCABCATSRHPROG);
|
||||
WRITE_CABI("catsrch.hs", cabiCABCATSEARCH);
|
||||
WRITE_CABI("char.hs", cabiCABCHARACTER);
|
||||
WRITE_CABI("chgpr.hs", cabiCABCHGPR);
|
||||
WRITE_CABI("cmpfile.hs", cabiCABCMPFILE);
|
||||
WRITE_CABI("confirmr.hs", cabiCABCONFIRMREPL);
|
||||
WRITE_CABI("cust.hs", cabiCABCUSTOMIZE);
|
||||
WRITE_CABI("doc.hs", cabiCABDOCUMENT);
|
||||
WRITE_CABI("docstat.hs", cabiCABDOCSTAT);
|
||||
WRITE_CABI("docsum.hs", cabiCABDOCSUM);
|
||||
WRITE_CABI("edmacro.hs", cabiCABEDMACRO);
|
||||
WRITE_CABI("edstyle.hs", cabiCABDEFINESTYLE);
|
||||
WRITE_CABI("footnote.hs", cabiCABINSERTFTN);
|
||||
WRITE_CABI("glsy.hs", cabiCABGLOSSARY);
|
||||
WRITE_CABI("goto.hs", cabiCABGOTO);
|
||||
WRITE_CABI("header.hs", cabiCABHEADER);
|
||||
WRITE_CABI("hyphen.hs", cabiCABHYPHEN);
|
||||
WRITE_CABI("index.hs", cabiCABINDEX);
|
||||
WRITE_CABI("indexent.hs", cabiCABINDEXENTRY);
|
||||
WRITE_CABI("insbreak.hs", cabiCABINSBREAK);
|
||||
WRITE_CABI("insfield.hs", cabiCABINSFIELD);
|
||||
WRITE_CABI("insfile.hs", cabiCABINSFILE);
|
||||
WRITE_CABI("inspgnum.hs", cabiCABINSPGNUM);
|
||||
WRITE_CABI("inspic.hs", cabiCABINSPIC);
|
||||
WRITE_CABI("mrgstyle.hs", cabiCABMERGESTYLE);
|
||||
WRITE_CABI("new.hs", cabiCABNEWDOC);
|
||||
WRITE_CABI("newopen.hs", cabiCABNEWOPEN);
|
||||
WRITE_CABI("open.hs", cabiCABOPEN);
|
||||
WRITE_CABI("para.hs", cabiCABPARALOOKS);
|
||||
WRITE_CABI("password.hs", cabiCABFILEPSWD);
|
||||
WRITE_CABI("pastelnk.hs", cabiCABPASTELINK);
|
||||
WRITE_CABI("pict.hs", cabiCABFORMATPIC);
|
||||
WRITE_CABI("print.hs", cabiCABPRINT);
|
||||
WRITE_CABI("printmrg.hs", cabiCABPRINTMERGE);
|
||||
WRITE_CABI("prompt.hs", cabiCABPROMPT);
|
||||
WRITE_CABI("recorder.hs", cabiCABRECORDER);
|
||||
WRITE_CABI("renmacro.hs", cabiCABRENMACRO);
|
||||
WRITE_CABI("renstyle.hs", cabiCABRENAMESTYLE);
|
||||
WRITE_CABI("renum.hs", cabiCABRENUMPARAS);
|
||||
WRITE_CABI("replace.hs", cabiCABREPLACE);
|
||||
WRITE_CABI("revmark.hs", cabiCABREVMARKING);
|
||||
WRITE_CABI("ribbon.hs", cabiCABRIBBON);
|
||||
WRITE_CABI("ribbon3.hs", cabiCABRIBBON3);
|
||||
WRITE_CABI("ruler.hs", cabiCABRULER);
|
||||
WRITE_CABI("ruler3.hs", cabiCABRULER3);
|
||||
WRITE_CABI("runmacro.hs", cabiCABRUNMACRO);
|
||||
WRITE_CABI("saveas.hs", cabiCABSAVE);
|
||||
WRITE_CABI("search.hs", cabiCABSEARCH);
|
||||
WRITE_CABI("sect.hs", cabiCABSECTION);
|
||||
WRITE_CABI("showvars.hs", cabiCABSHOWVARS);
|
||||
WRITE_CABI("sort.hs", cabiCABSORT);
|
||||
WRITE_CABI("spell.hs", cabiCABSPELLER);
|
||||
WRITE_CABI("spellmm.hs", cabiCABSPELLERMM);
|
||||
WRITE_CABI("style.hs", cabiCABAPPLYSTYLE);
|
||||
WRITE_CABI("tablecmd.hs", cabiCABEDITTABLE);
|
||||
WRITE_CABI("tablefmt.hs", cabiCABFORMATTABLE);
|
||||
WRITE_CABI("tableins.hs", cabiCABINSERTTABLE);
|
||||
WRITE_CABI("tabletxt.hs", cabiCABTABLETOTEXT);
|
||||
WRITE_CABI("tabs.hs", cabiCABTABS);
|
||||
WRITE_CABI("thesaur.hs", cabiCABTHESAURUS);
|
||||
WRITE_CABI("toc.hs", cabiCABTOC);
|
||||
WRITE_CABI("username.hs", cabiCABUSERNAME);
|
||||
WRITE_CABI("usrdlg.hs", cabiCABUSRDLG);
|
||||
WRITE_CABI("viewpref.hs", cabiCABVIEWPREF);
|
||||
WRITE_CABI("vrfcnvtr.hs", cabiCABEXCR);
|
||||
return success ? 0 : 4;
|
||||
}
|
||||
Reference in New Issue
Block a user