mirror of
https://github.com/jmarshall23/msword.git
synced 2026-08-11 23:50:53 +02:00
Added docx and pdf export support.
This commit is contained in:
@@ -721,6 +721,7 @@ add_library(opus_x64_runtime STATIC
|
|||||||
port/original/opus_asm_search.cpp
|
port/original/opus_asm_search.cpp
|
||||||
port/original/opus_sdm_cab.cpp
|
port/original/opus_sdm_cab.cpp
|
||||||
port/original/opus_sdm_runtime.cpp
|
port/original/opus_sdm_runtime.cpp
|
||||||
|
port/original/opus_modern_formats.cpp
|
||||||
)
|
)
|
||||||
target_compile_features(opus_x64_runtime PRIVATE cxx_std_20)
|
target_compile_features(opus_x64_runtime PRIVATE cxx_std_20)
|
||||||
target_compile_definitions(opus_x64_runtime PRIVATE
|
target_compile_definitions(opus_x64_runtime PRIVATE
|
||||||
@@ -732,6 +733,7 @@ target_compile_definitions(opus_x64_runtime PRIVATE
|
|||||||
NOMINMAX
|
NOMINMAX
|
||||||
)
|
)
|
||||||
target_include_directories(opus_x64_runtime PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS})
|
target_include_directories(opus_x64_runtime PRIVATE ${OPUS_ORIGINAL_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(opus_x64_runtime PUBLIC ole32 comdlg32 gdi32)
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# Opus was built with unsigned plain characters; the byte-oriented string
|
# Opus was built with unsigned plain characters; the byte-oriented string
|
||||||
# and international-character assembly routines depend on that behavior.
|
# and international-character assembly routines depend on that behavior.
|
||||||
@@ -943,6 +945,27 @@ foreach(config Debug Release RelWithDebInfo MinSizeRel)
|
|||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
add_executable(opus_modern_formats_test
|
||||||
|
port/original/opus_modern_formats_test.cpp
|
||||||
|
)
|
||||||
|
target_compile_features(opus_modern_formats_test PRIVATE cxx_std_20)
|
||||||
|
target_compile_definitions(opus_modern_formats_test PRIVATE NOMINMAX UNICODE _UNICODE)
|
||||||
|
target_link_libraries(opus_modern_formats_test PRIVATE opus_x64_runtime user32 gdi32)
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(opus_modern_formats_test PRIVATE /W4 /utf-8)
|
||||||
|
endif()
|
||||||
|
set_target_properties(opus_modern_formats_test PROPERTIES
|
||||||
|
FOLDER "Original Opus x64/tests"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tests"
|
||||||
|
VS_GLOBAL_VcpkgApplocalDeps "false"
|
||||||
|
)
|
||||||
|
foreach(config Debug Release RelWithDebInfo MinSizeRel)
|
||||||
|
string(TOUPPER "${config}" config_upper)
|
||||||
|
set_target_properties(opus_modern_formats_test PROPERTIES
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}"
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
add_executable(opus_word1_ui_test
|
add_executable(opus_word1_ui_test
|
||||||
port/original/opus_word1_ui_test.cpp
|
port/original/opus_word1_ui_test.cpp
|
||||||
)
|
)
|
||||||
@@ -968,6 +991,7 @@ endforeach()
|
|||||||
enable_testing()
|
enable_testing()
|
||||||
add_test(NAME opus_original_strtbl_test COMMAND $<TARGET_FILE:opus_original_strtbl_test>)
|
add_test(NAME opus_original_strtbl_test COMMAND $<TARGET_FILE:opus_original_strtbl_test>)
|
||||||
add_test(NAME opus_x64_runtime_test COMMAND $<TARGET_FILE:opus_x64_runtime_test>)
|
add_test(NAME opus_x64_runtime_test COMMAND $<TARGET_FILE:opus_x64_runtime_test>)
|
||||||
|
add_test(NAME opus_modern_formats_test COMMAND $<TARGET_FILE:opus_modern_formats_test>)
|
||||||
add_test(NAME opus_original_sttb_test COMMAND $<TARGET_FILE:opus_original_sttb_test>)
|
add_test(NAME opus_original_sttb_test COMMAND $<TARGET_FILE:opus_original_sttb_test>)
|
||||||
add_test(NAME opus_original_plc_test COMMAND $<TARGET_FILE:opus_original_plc_test>)
|
add_test(NAME opus_original_plc_test COMMAND $<TARGET_FILE:opus_original_plc_test>)
|
||||||
add_test(NAME opus_sdm_cab_test COMMAND $<TARGET_FILE:opus_sdm_cab_test>)
|
add_test(NAME opus_sdm_cab_test COMMAND $<TARGET_FILE:opus_sdm_cab_test>)
|
||||||
@@ -1005,3 +1029,7 @@ add_test(NAME opus_word1_save_as_test
|
|||||||
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --save-as
|
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --save-as
|
||||||
)
|
)
|
||||||
set_tests_properties(opus_word1_save_as_test PROPERTIES TIMEOUT 20)
|
set_tests_properties(opus_word1_save_as_test PROPERTIES TIMEOUT 20)
|
||||||
|
add_test(NAME opus_word1_pdf_export_test
|
||||||
|
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --pdf-export
|
||||||
|
)
|
||||||
|
set_tests_properties(opus_word1_pdf_export_test PROPERTIES TIMEOUT 25)
|
||||||
|
|||||||
+8
-1
@@ -83,6 +83,9 @@ extern int vfConversion;
|
|||||||
extern MUD ** vhmudUser;
|
extern MUD ** vhmudUser;
|
||||||
extern KMP ** hkmpCur;
|
extern KMP ** hkmpCur;
|
||||||
extern KMP ** vhkmpUser;
|
extern KMP ** vhkmpUser;
|
||||||
|
#ifdef OPUS_X64
|
||||||
|
extern int OpusWin95OpenAliasIsDocx();
|
||||||
|
#endif
|
||||||
|
|
||||||
struct DTTM DttmCur();
|
struct DTTM DttmCur();
|
||||||
|
|
||||||
@@ -484,7 +487,11 @@ CHAR *stConverter, **pstSubset;
|
|||||||
dff = dffOpenText;
|
dff = dffOpenText;
|
||||||
|
|
||||||
/* dff is our best guess of format */
|
/* dff is our best guess of format */
|
||||||
if (fInput)
|
if (fInput
|
||||||
|
#ifdef OPUS_X64
|
||||||
|
&& !OpusWin95OpenAliasIsDocx(PfcbFn(fn)->stFile)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
/* verify the format */
|
/* verify the format */
|
||||||
if ((dff = DffVerifyDff (dff, fn)) == dffNil)
|
if ((dff = DffVerifyDff (dff, fn)) == dffNil)
|
||||||
/* cancel operation */
|
/* cancel operation */
|
||||||
|
|||||||
+1
-1
@@ -833,7 +833,7 @@ int doc;
|
|||||||
*/
|
*/
|
||||||
/* %%Function: HWriteRTF %%Owner: bobz */
|
/* %%Function: HWriteRTF %%Owner: bobz */
|
||||||
|
|
||||||
HWriteRTF (doc, cpFirst, cpLim, cbInitial)
|
HANDLE HWriteRTF (doc, cpFirst, cpLim, cbInitial)
|
||||||
int doc;
|
int doc;
|
||||||
CP cpFirst, cpLim;
|
CP cpFirst, cpLim;
|
||||||
int cbInitial;
|
int cbInitial;
|
||||||
|
|||||||
@@ -103,6 +103,85 @@ static int vWin95ZoomPercent = 100;
|
|||||||
static int vWin95BaseDxsInch = 0;
|
static int vWin95BaseDxsInch = 0;
|
||||||
static int vWin95BaseDysInch = 0;
|
static int vWin95BaseDysInch = 0;
|
||||||
|
|
||||||
|
int OpusExportCurrentDocumentPdf()
|
||||||
|
{
|
||||||
|
int doc;
|
||||||
|
HANDLE hText;
|
||||||
|
LPCH lpch;
|
||||||
|
int result;
|
||||||
|
int cchText = 0;
|
||||||
|
int fAfterReturn = fFalse;
|
||||||
|
CP cp;
|
||||||
|
CP cpMac;
|
||||||
|
extern int vccpFetch;
|
||||||
|
extern CHAR HUGE *vhpchFetch;
|
||||||
|
extern int N_FetchCp();
|
||||||
|
extern int OpusExportTextToPdfDialog();
|
||||||
|
|
||||||
|
if (selCur.doc == docNil)
|
||||||
|
return fFalse;
|
||||||
|
doc = DocMother(selCur.doc);
|
||||||
|
cpMac = CpMacDocEdit(doc);
|
||||||
|
if (cpMac < cp0 || cpMac > 0x3fffffffL)
|
||||||
|
return fFalse;
|
||||||
|
hText = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(cpMac * 2L + 1L));
|
||||||
|
if (hText == hNil || (lpch = GlobalLockClip(hText)) == NULL)
|
||||||
|
{
|
||||||
|
if (hText != hNil)
|
||||||
|
GlobalFree(hText);
|
||||||
|
return fFalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cp = cp0; cp < cpMac; )
|
||||||
|
{
|
||||||
|
int ich;
|
||||||
|
int cch;
|
||||||
|
FetchCp(doc, cp, fcmChars);
|
||||||
|
if (vccpFetch <= 0 || vhpchFetch == NULL)
|
||||||
|
{
|
||||||
|
GlobalUnlock(hText);
|
||||||
|
GlobalFree(hText);
|
||||||
|
return fFalse;
|
||||||
|
}
|
||||||
|
cch = (int)CpMin((CP)vccpFetch, cpMac - cp);
|
||||||
|
for (ich = 0; ich < cch; ++ich)
|
||||||
|
{
|
||||||
|
int ch = (unsigned char)vhpchFetch[ich];
|
||||||
|
if (ch == chReturn)
|
||||||
|
{
|
||||||
|
lpch[cchText++] = '\r';
|
||||||
|
lpch[cchText++] = '\n';
|
||||||
|
fAfterReturn = fTrue;
|
||||||
|
}
|
||||||
|
else if (ch == chEop)
|
||||||
|
{
|
||||||
|
if (!fAfterReturn)
|
||||||
|
{
|
||||||
|
lpch[cchText++] = '\r';
|
||||||
|
lpch[cchText++] = '\n';
|
||||||
|
}
|
||||||
|
fAfterReturn = fFalse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fAfterReturn = fFalse;
|
||||||
|
if (ch == chTable || ch == chTab)
|
||||||
|
lpch[cchText++] = '\t';
|
||||||
|
else if (ch == chSect || ch == chColumnBreak)
|
||||||
|
lpch[cchText++] = '\f';
|
||||||
|
else if (ch >= chSpace || ch == chNonReqHyphen)
|
||||||
|
lpch[cchText++] = (char)ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cp += cch;
|
||||||
|
}
|
||||||
|
lpch[cchText] = '\0';
|
||||||
|
result = OpusExportTextToPdfDialog(vhwndApp, lpch, cchText);
|
||||||
|
GlobalUnlock(hText);
|
||||||
|
GlobalFree(hText);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* The Word 1.x Color command opens a keyboard prompt. The Win95 chrome
|
/* The Word 1.x Color command opens a keyboard prompt. The Win95 chrome
|
||||||
supplies a palette instead, but still applies the original character
|
supplies a palette instead, but still applies the original character
|
||||||
property so document storage and formatting behavior remain unchanged. */
|
property so document storage and formatting behavior remain unchanged. */
|
||||||
|
|||||||
+12
-1
@@ -89,6 +89,7 @@ DEBUGASSERTSZ /* WIN - bogus macro for assert string */
|
|||||||
#ifdef OPUS_X64
|
#ifdef OPUS_X64
|
||||||
extern int OpusWin95SaveAliasMatches();
|
extern int OpusWin95SaveAliasMatches();
|
||||||
extern int OpusFinishWin95SaveAlias();
|
extern int OpusFinishWin95SaveAlias();
|
||||||
|
extern int OpusWin95SaveAliasRequiresRtf();
|
||||||
#define FWin95SaveAliasMatches(st) OpusWin95SaveAliasMatches(st)
|
#define FWin95SaveAliasMatches(st) OpusWin95SaveAliasMatches(st)
|
||||||
#else
|
#else
|
||||||
#define FWin95SaveAliasMatches(st) fFalse
|
#define FWin95SaveAliasMatches(st) fFalse
|
||||||
@@ -661,7 +662,16 @@ LSaveAs:
|
|||||||
|
|
||||||
/* perform the actual save */
|
/* perform the actual save */
|
||||||
PdodDoc(doc)->dop.fLockAtn = (*hcab)->fLockAnnot;
|
PdodDoc(doc)->dop.fLockAtn = (*hcab)->fLockAnnot;
|
||||||
if (FSaveFile(stFile, doc, DffISaveFmt((*hcab)->iFmt),
|
{
|
||||||
|
int dffSave = DffISaveFmt((*hcab)->iFmt);
|
||||||
|
#ifdef OPUS_X64
|
||||||
|
if (OpusWin95SaveAliasRequiresRtf(stFile))
|
||||||
|
{
|
||||||
|
dffSave = dffSaveRTF;
|
||||||
|
(*hcab)->fQuicksave = fFalse;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (FSaveFile(stFile, doc, dffSave,
|
||||||
(*hcab)->fQuicksave, (*hcab)->fBackup, fTrue /* fReport */))
|
(*hcab)->fQuicksave, (*hcab)->fBackup, fTrue /* fReport */))
|
||||||
{
|
{
|
||||||
/* display number of characters written in prompt */
|
/* display number of characters written in prompt */
|
||||||
@@ -682,6 +692,7 @@ LSaveAs:
|
|||||||
cmd = cmdError;
|
cmd = cmdError;
|
||||||
StopProgressReport(hNil, pdcRestoreImmed);
|
StopProgressReport(hNil, pdcRestoreImmed);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vhpprSave = hNil;
|
vhpprSave = hNil;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,9 @@ extern HWND vhWndMsgBoxParent;
|
|||||||
void GetCabSz(void**, char*, std::uint16_t, std::uint16_t);
|
void GetCabSz(void**, char*, std::uint16_t, std::uint16_t);
|
||||||
int FSetCabSz(void**, const char*, std::uint16_t);
|
int FSetCabSz(void**, const char*, std::uint16_t);
|
||||||
void OpusX64TraceRibbon(const char*, int, int, int, int, long, long, int);
|
void OpusX64TraceRibbon(const char*, int, int, int, int, long, long, int);
|
||||||
|
int OpusModernPathIsDocx(const char*);
|
||||||
|
int OpusModernDocxToTextFile(const char*, const char*);
|
||||||
|
int OpusModernRtfFileToDocx(const char*, const char*);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -151,7 +154,8 @@ std::string win95_alias_key(std::string path) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool make_win95_staging_path(std::string& path) {
|
bool make_win95_staging_path(std::string& path,
|
||||||
|
const char* desired_extension = ".DOC") {
|
||||||
char module_path[32768]{};
|
char module_path[32768]{};
|
||||||
const DWORD module_length = GetModuleFileNameA(
|
const DWORD module_length = GetModuleFileNameA(
|
||||||
nullptr, module_path, static_cast<DWORD>(std::size(module_path)));
|
nullptr, module_path, static_cast<DWORD>(std::size(module_path)));
|
||||||
@@ -174,9 +178,9 @@ bool make_win95_staging_path(std::string& path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DeleteFileA(temporary);
|
DeleteFileA(temporary);
|
||||||
char* extension = std::strrchr(temporary, '.');
|
char* existing_extension = std::strrchr(temporary, '.');
|
||||||
if (extension != nullptr) {
|
if (existing_extension != nullptr) {
|
||||||
lstrcpyA(extension, ".DOC");
|
lstrcpyA(existing_extension, desired_extension);
|
||||||
}
|
}
|
||||||
if (GetFileAttributesA(temporary) == INVALID_FILE_ATTRIBUTES &&
|
if (GetFileAttributesA(temporary) == INVALID_FILE_ATTRIBUTES &&
|
||||||
std::strlen(temporary) < 120) {
|
std::strlen(temporary) < 120) {
|
||||||
@@ -260,6 +264,7 @@ constexpr Tmc kTmcSaveDirectoryList = kTmcUserMin + 3;
|
|||||||
constexpr Tmc kTmcSaveDirectory = kTmcUserMin + 4;
|
constexpr Tmc kTmcSaveDirectory = kTmcUserMin + 4;
|
||||||
constexpr Tmc kTmcSaveFormatPrompt = kTmcUserMin + 5;
|
constexpr Tmc kTmcSaveFormatPrompt = kTmcUserMin + 5;
|
||||||
constexpr Tmc kTmcSaveFormat = kTmcUserMin + 6;
|
constexpr Tmc kTmcSaveFormat = kTmcUserMin + 6;
|
||||||
|
constexpr int kSaveFormatRtf = 6;
|
||||||
constexpr Tmc kTmcSaveQuick = kTmcUserMin + 7;
|
constexpr Tmc kTmcSaveQuick = kTmcUserMin + 7;
|
||||||
constexpr Tmc kTmcSaveBackup = kTmcUserMin + 8;
|
constexpr Tmc kTmcSaveBackup = kTmcUserMin + 8;
|
||||||
constexpr Tmc kTmcSaveLockAnnotations = kTmcUserMin + 9;
|
constexpr Tmc kTmcSaveLockAnnotations = kTmcUserMin + 9;
|
||||||
@@ -2146,12 +2151,13 @@ Tmc run_word95_common_file_dialog(DialogState& dialog) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char open_filter[] =
|
static const char open_filter[] =
|
||||||
"Word Documents (*.doc;*.dot)\0*.doc;*.dot\0"
|
"Word Documents (*.doc;*.docx;*.dot)\0*.doc;*.docx;*.dot\0"
|
||||||
"Rich Text Format (*.rtf)\0*.rtf\0"
|
"Rich Text Format (*.rtf)\0*.rtf\0"
|
||||||
"Text Files (*.txt)\0*.txt\0"
|
"Text Files (*.txt)\0*.txt\0"
|
||||||
"All Files (*.*)\0*.*\0\0";
|
"All Files (*.*)\0*.*\0\0";
|
||||||
static const char save_filter[] =
|
static const char save_filter[] =
|
||||||
"Word Documents (*.doc)\0*.doc\0"
|
"Word Documents (*.doc)\0*.doc\0"
|
||||||
|
"Word 2007-2024 Documents (*.docx)\0*.docx\0"
|
||||||
"Document Templates (*.dot)\0*.dot\0"
|
"Document Templates (*.dot)\0*.dot\0"
|
||||||
"All Files (*.*)\0*.*\0\0";
|
"All Files (*.*)\0*.*\0\0";
|
||||||
|
|
||||||
@@ -2180,8 +2186,23 @@ Tmc run_word95_common_file_dialog(DialogState& dialog) {
|
|||||||
OFN_OVERWRITEPROMPT;
|
OFN_OVERWRITEPROMPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BOOL accepted = opening ?
|
char test_path[32768]{};
|
||||||
GetOpenFileNameA(&file_dialog) : GetSaveFileNameA(&file_dialog);
|
const DWORD test_path_length = GetEnvironmentVariableA(
|
||||||
|
"WORD1_TEST_FILE_DIALOG_PATH", test_path,
|
||||||
|
static_cast<DWORD>(std::size(test_path)));
|
||||||
|
BOOL accepted = FALSE;
|
||||||
|
if (test_path_length > 0 && test_path_length < std::size(test_path)) {
|
||||||
|
lstrcpynA(file_buffer.data(), test_path,
|
||||||
|
static_cast<int>(file_buffer.size()));
|
||||||
|
if (saving && OpusModernPathIsDocx(test_path)) {
|
||||||
|
file_dialog.nFilterIndex = 2;
|
||||||
|
}
|
||||||
|
SetEnvironmentVariableA("WORD1_TEST_FILE_DIALOG_PATH", nullptr);
|
||||||
|
accepted = TRUE;
|
||||||
|
} else {
|
||||||
|
accepted = opening ? GetOpenFileNameA(&file_dialog) :
|
||||||
|
GetSaveFileNameA(&file_dialog);
|
||||||
|
}
|
||||||
if (!accepted) {
|
if (!accepted) {
|
||||||
if (CommDlgExtendedError() != 0) {
|
if (CommDlgExtendedError() != 0) {
|
||||||
MessageBoxA(owner,
|
MessageBoxA(owner,
|
||||||
@@ -2196,18 +2217,41 @@ Tmc run_word95_common_file_dialog(DialogState& dialog) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string selected_path = file_buffer.data();
|
std::string selected_path = file_buffer.data();
|
||||||
|
if (saving && file_dialog.nFilterIndex == 2) {
|
||||||
|
const std::size_t selected_slash =
|
||||||
|
selected_path.find_last_of("\\/");
|
||||||
|
const std::size_t selected_dot = selected_path.find_last_of('.');
|
||||||
|
if (selected_dot == std::string::npos ||
|
||||||
|
(selected_slash != std::string::npos &&
|
||||||
|
selected_dot < selected_slash)) {
|
||||||
|
selected_path += ".docx";
|
||||||
|
} else if (_stricmp(selected_path.c_str() + selected_dot,
|
||||||
|
".doc") == 0) {
|
||||||
|
selected_path.replace(selected_dot, std::string::npos,
|
||||||
|
".docx");
|
||||||
|
}
|
||||||
|
}
|
||||||
std::string legacy_path;
|
std::string legacy_path;
|
||||||
if (!make_win95_staging_path(legacy_path)) {
|
const bool docx = OpusModernPathIsDocx(selected_path.c_str()) != 0;
|
||||||
|
if (!make_win95_staging_path(legacy_path,
|
||||||
|
docx ? ".TXT" : ".DOC")) {
|
||||||
MessageBoxA(owner,
|
MessageBoxA(owner,
|
||||||
"Word could not prepare a temporary document file.",
|
"Word could not prepare a temporary document file.",
|
||||||
opening ? "Open" : "Save As",
|
opening ? "Open" : "Save As",
|
||||||
MB_OK | MB_ICONEXCLAMATION);
|
MB_OK | MB_ICONEXCLAMATION);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (opening &&
|
const bool staged_open = !opening ||
|
||||||
!CopyFileA(selected_path.c_str(), legacy_path.c_str(), FALSE)) {
|
(docx ?
|
||||||
MessageBoxA(owner, "Word could not open the selected file.",
|
OpusModernDocxToTextFile(selected_path.c_str(),
|
||||||
|
legacy_path.c_str()) != 0 :
|
||||||
|
CopyFileA(selected_path.c_str(), legacy_path.c_str(), FALSE) != 0);
|
||||||
|
if (!staged_open) {
|
||||||
|
MessageBoxA(owner,
|
||||||
|
docx ?
|
||||||
|
"Word could not read this DOCX document." :
|
||||||
|
"Word could not open the selected file.",
|
||||||
"Open", MB_OK | MB_ICONEXCLAMATION);
|
"Open", MB_OK | MB_ICONEXCLAMATION);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2240,6 +2284,11 @@ Tmc run_word95_common_file_dialog(DialogState& dialog) {
|
|||||||
SetWindowTextA(edit.window, edit.text.c_str());
|
SetWindowTextA(edit.window, edit.text.c_str());
|
||||||
}
|
}
|
||||||
sync_save_cab(dialog);
|
sync_save_cab(dialog);
|
||||||
|
if (auto* cab = save_cab(dialog);
|
||||||
|
cab != nullptr && docx) {
|
||||||
|
cab->format = kSaveFormatRtf;
|
||||||
|
cab->quick_save = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoke_dialog_proc(dialog, kDlmTerm, kTmcOk)) {
|
if (invoke_dialog_proc(dialog, kDlmTerm, kTmcOk)) {
|
||||||
@@ -2374,10 +2423,13 @@ int OpusFinishWin95SaveAlias(const unsigned char* st_file,
|
|||||||
g_win95_save_alias.legacy_path.c_str()) == 0) {
|
g_win95_save_alias.legacy_path.c_str()) == 0) {
|
||||||
bool copied = success != 0;
|
bool copied = success != 0;
|
||||||
if (copied) {
|
if (copied) {
|
||||||
copied = CopyFileA(
|
copied = OpusModernPathIsDocx(
|
||||||
|
g_win95_save_alias.selected_path.c_str()) ?
|
||||||
|
OpusModernRtfFileToDocx(
|
||||||
g_win95_save_alias.legacy_path.c_str(),
|
g_win95_save_alias.legacy_path.c_str(),
|
||||||
g_win95_save_alias.selected_path.c_str(),
|
g_win95_save_alias.selected_path.c_str()) != 0 :
|
||||||
FALSE) != 0;
|
CopyFileA(g_win95_save_alias.legacy_path.c_str(),
|
||||||
|
g_win95_save_alias.selected_path.c_str(), FALSE) != 0;
|
||||||
}
|
}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
DeleteFileA(g_win95_save_alias.legacy_path.c_str());
|
DeleteFileA(g_win95_save_alias.legacy_path.c_str());
|
||||||
@@ -2396,7 +2448,28 @@ int OpusFinishWin95SaveAlias(const unsigned char* st_file,
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return CopyFileA(path.c_str(), saved->second.c_str(), FALSE) != 0;
|
return OpusModernPathIsDocx(saved->second.c_str()) ?
|
||||||
|
OpusModernRtfFileToDocx(path.c_str(), saved->second.c_str()) != 0 :
|
||||||
|
CopyFileA(path.c_str(), saved->second.c_str(), FALSE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OpusWin95SaveAliasRequiresRtf(const unsigned char* st_file) {
|
||||||
|
const std::string path = counted_path(st_file);
|
||||||
|
if (path.empty()) return false;
|
||||||
|
if (g_win95_save_alias.active &&
|
||||||
|
_stricmp(path.c_str(), g_win95_save_alias.legacy_path.c_str()) == 0)
|
||||||
|
return OpusModernPathIsDocx(g_win95_save_alias.selected_path.c_str());
|
||||||
|
const auto saved = g_win95_saved_aliases.find(win95_alias_key(path));
|
||||||
|
return saved != g_win95_saved_aliases.end() &&
|
||||||
|
OpusModernPathIsDocx(saved->second.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int OpusWin95OpenAliasIsDocx(const unsigned char* st_file) {
|
||||||
|
const std::string path = counted_path(st_file);
|
||||||
|
if (path.empty()) return false;
|
||||||
|
const auto saved = g_win95_saved_aliases.find(win95_alias_key(path));
|
||||||
|
return saved != g_win95_saved_aliases.end() &&
|
||||||
|
OpusModernPathIsDocx(saved->second.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OpusSdsCompat {
|
struct OpusSdsCompat {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ extern "C" int OpusGetWin95HorizontalPageMargins(
|
|||||||
extern "C" int OpusAdjustWin95HorizontalMargin(
|
extern "C" int OpusAdjustWin95HorizontalMargin(
|
||||||
HWND ruler, int left_margin, int delta_pixels);
|
HWND ruler, int left_margin, int delta_pixels);
|
||||||
extern "C" void OpusDrawWin95HorizontalRuler(HWND ruler);
|
extern "C" void OpusDrawWin95HorizontalRuler(HWND ruler);
|
||||||
|
extern "C" int OpusExportCurrentDocumentPdf(void);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ constexpr UINT kComboSize = 0x7503;
|
|||||||
constexpr UINT kComboZoom = 0x7504;
|
constexpr UINT kComboZoom = 0x7504;
|
||||||
constexpr UINT kCmdToggleStandardToolbar = 0x7101;
|
constexpr UINT kCmdToggleStandardToolbar = 0x7101;
|
||||||
constexpr UINT kCmdToggleFormattingToolbar = 0x7102;
|
constexpr UINT kCmdToggleFormattingToolbar = 0x7102;
|
||||||
|
constexpr UINT kCmdExportPdf = 0x7103;
|
||||||
constexpr UINT kCmdTextColorBase = 0x7200;
|
constexpr UINT kCmdTextColorBase = 0x7200;
|
||||||
constexpr UINT_PTR kSyncTimer = 0x951;
|
constexpr UINT_PTR kSyncTimer = 0x951;
|
||||||
constexpr wchar_t kOriginalPaneProcProperty[] = L"OpusWord95OriginalPaneProc";
|
constexpr wchar_t kOriginalPaneProcProperty[] = L"OpusWord95OriginalPaneProc";
|
||||||
@@ -326,6 +328,17 @@ void configure_word95_menus(HWND window) {
|
|||||||
reinterpret_cast<UINT_PTR>(format), L"F&ormat");
|
reinterpret_cast<UINT_PTR>(format), L"F&ormat");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
HMENU file_menu = file_index >= 0 ? GetSubMenu(root, file_index) : nullptr;
|
||||||
|
if (file_menu != nullptr &&
|
||||||
|
GetMenuState(file_menu, kCmdExportPdf, MF_BYCOMMAND) ==
|
||||||
|
static_cast<UINT>(-1)) {
|
||||||
|
int exit_position = find_named_in(file_menu, L"Exit");
|
||||||
|
if (exit_position < 0) exit_position = GetMenuItemCount(file_menu);
|
||||||
|
InsertMenuW(file_menu, exit_position, MF_BYPOSITION | MF_SEPARATOR,
|
||||||
|
0, nullptr);
|
||||||
|
InsertMenuW(file_menu, exit_position, MF_BYPOSITION | MF_STRING,
|
||||||
|
kCmdExportPdf, L"E&xport as PDF...");
|
||||||
|
}
|
||||||
const int utilities_index = find_named(L"Utilities");
|
const int utilities_index = find_named(L"Utilities");
|
||||||
if (utilities_index >= 0) {
|
if (utilities_index >= 0) {
|
||||||
HMENU tools = GetSubMenu(root, utilities_index);
|
HMENU tools = GetSubMenu(root, utilities_index);
|
||||||
@@ -2504,6 +2517,10 @@ LRESULT CALLBACK app_window_proc(HWND app, UINT message,
|
|||||||
show_text_color_palette(app, toolbar);
|
show_text_color_palette(app, toolbar);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (command == kCmdExportPdf) {
|
||||||
|
OpusExportCurrentDocumentPdf();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (command == kCmdToggleStandardToolbar) {
|
if (command == kCmdToggleStandardToolbar) {
|
||||||
toggle_toolbar_row(app, toolbar, true);
|
toggle_toolbar_row(app, toolbar, true);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -12,10 +13,12 @@ namespace {
|
|||||||
|
|
||||||
constexpr UINT kWmCommand = 0x0111;
|
constexpr UINT kWmCommand = 0x0111;
|
||||||
constexpr WPARAM kFileNew = 1813;
|
constexpr WPARAM kFileNew = 1813;
|
||||||
|
constexpr WPARAM kFileOpen = 1843;
|
||||||
constexpr WPARAM kFileSaveAs = 1897;
|
constexpr WPARAM kFileSaveAs = 1897;
|
||||||
constexpr WPARAM kFileExit = 2095;
|
constexpr WPARAM kFileExit = 2095;
|
||||||
constexpr WPARAM kHelpAbout = 182;
|
constexpr WPARAM kHelpAbout = 182;
|
||||||
constexpr WPARAM kParaCenter = 1355;
|
constexpr WPARAM kParaCenter = 1355;
|
||||||
|
constexpr WPARAM kExportPdf = 0x7103;
|
||||||
constexpr UINT kWmOpusX64QuerySelection = WM_APP + 0x351;
|
constexpr UINT kWmOpusX64QuerySelection = WM_APP + 0x351;
|
||||||
constexpr int kKcControl = 0x100;
|
constexpr int kKcControl = 0x100;
|
||||||
constexpr LRESULT kEditUndo = 2229;
|
constexpr LRESULT kEditUndo = 2229;
|
||||||
@@ -100,6 +103,26 @@ HWND find_descendant_by_class(const HWND parent,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HWND find_visible_descendant_by_class(const HWND parent,
|
||||||
|
const wchar_t* expected_class) {
|
||||||
|
for (HWND child = GetWindow(parent, GW_CHILD); child != nullptr;
|
||||||
|
child = GetWindow(child, GW_HWNDNEXT)) {
|
||||||
|
wchar_t class_name[128] = {};
|
||||||
|
if (GetClassNameW(child, class_name,
|
||||||
|
static_cast<int>(std::size(class_name))) != 0 &&
|
||||||
|
_wcsicmp(class_name, expected_class) == 0 &&
|
||||||
|
IsWindowVisible(child)) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
if (const HWND descendant =
|
||||||
|
find_visible_descendant_by_class(child, expected_class);
|
||||||
|
descendant != nullptr) {
|
||||||
|
return descendant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void collect_descendants_by_class(const HWND parent,
|
void collect_descendants_by_class(const HWND parent,
|
||||||
const wchar_t* expected_class,
|
const wchar_t* expected_class,
|
||||||
std::vector<HWND>& matches) {
|
std::vector<HWND>& matches) {
|
||||||
@@ -568,11 +591,12 @@ int fail(PROCESS_INFORMATION& process, const int code,
|
|||||||
int wmain(const int argument_count, wchar_t** arguments) {
|
int wmain(const int argument_count, wchar_t** arguments) {
|
||||||
SetProcessDpiAwarenessContext(
|
SetProcessDpiAwarenessContext(
|
||||||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||||
if (argument_count < 2 || argument_count > 3) {
|
if (argument_count < 2 || argument_count > 4) {
|
||||||
std::cerr <<
|
std::cerr <<
|
||||||
"usage: opus_word1_ui_test WORD1.exe "
|
"usage: opus_word1_ui_test WORD1.exe "
|
||||||
"[--typing|--interaction|--selection|--caret|--formatting|--color|"
|
"[--typing|--interaction|--selection|--caret|--formatting|--color|"
|
||||||
"--font-typing|--clipboard|--about|--save-as]\n";
|
"--font-typing|--clipboard|--about|--save-as|--pdf-export|"
|
||||||
|
"--docx-open FILE]\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const bool typing_mode =
|
const bool typing_mode =
|
||||||
@@ -604,23 +628,78 @@ int wmain(const int argument_count, wchar_t** arguments) {
|
|||||||
const bool save_as_mode =
|
const bool save_as_mode =
|
||||||
argument_count == 3 &&
|
argument_count == 3 &&
|
||||||
std::wcscmp(arguments[2], L"--save-as") == 0;
|
std::wcscmp(arguments[2], L"--save-as") == 0;
|
||||||
|
const bool pdf_export_mode =
|
||||||
|
argument_count == 3 &&
|
||||||
|
std::wcscmp(arguments[2], L"--pdf-export") == 0;
|
||||||
|
const bool docx_open_mode =
|
||||||
|
argument_count == 4 &&
|
||||||
|
std::wcscmp(arguments[2], L"--docx-open") == 0;
|
||||||
if (argument_count == 3 && !typing_mode && !interaction_mode &&
|
if (argument_count == 3 && !typing_mode && !interaction_mode &&
|
||||||
!selection_mode && !caret_mode && !formatting_mode && !color_mode &&
|
!selection_mode && !caret_mode && !formatting_mode && !color_mode &&
|
||||||
!font_typing_mode && !clipboard_mode && !about_mode &&
|
!font_typing_mode && !clipboard_mode && !about_mode &&
|
||||||
!save_as_mode) {
|
!save_as_mode && !pdf_export_mode) {
|
||||||
std::cerr << "unknown test mode\n";
|
std::cerr << "unknown test mode\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (argument_count == 4 && !docx_open_mode) {
|
||||||
|
std::cerr << "unknown test mode\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string docx_path;
|
||||||
|
std::string pdf_path;
|
||||||
|
if (docx_open_mode) {
|
||||||
|
const int path_size = WideCharToMultiByte(
|
||||||
|
CP_ACP, 0, arguments[3], -1, nullptr, 0, nullptr, nullptr);
|
||||||
|
if (path_size <= 1) {
|
||||||
|
std::cerr << "DOCX open test received an invalid path\n";
|
||||||
|
return 83;
|
||||||
|
}
|
||||||
|
docx_path.resize(static_cast<std::size_t>(path_size));
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, arguments[3], -1, docx_path.data(),
|
||||||
|
path_size, nullptr, nullptr);
|
||||||
|
docx_path.pop_back();
|
||||||
|
if (GetFileAttributesA(docx_path.c_str()) == INVALID_FILE_ATTRIBUTES) {
|
||||||
|
std::cerr << "DOCX open test file does not exist\n";
|
||||||
|
return 83;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (docx_open_mode) {
|
||||||
|
SetEnvironmentVariableA("WORD1_TEST_FILE_DIALOG_PATH",
|
||||||
|
docx_path.c_str());
|
||||||
|
}
|
||||||
|
if (pdf_export_mode) {
|
||||||
|
char temporary_directory[MAX_PATH]{};
|
||||||
|
char temporary_seed[MAX_PATH]{};
|
||||||
|
if (GetTempPathA(static_cast<DWORD>(std::size(temporary_directory)),
|
||||||
|
temporary_directory) == 0 ||
|
||||||
|
GetTempFileNameA(temporary_directory, "OWP", 0,
|
||||||
|
temporary_seed) == 0) {
|
||||||
|
std::cerr << "PDF export test could not reserve a path\n";
|
||||||
|
return 85;
|
||||||
|
}
|
||||||
|
DeleteFileA(temporary_seed);
|
||||||
|
pdf_path = std::string(temporary_seed) + ".pdf";
|
||||||
|
SetEnvironmentVariableA("WORD1_TEST_PDF_PATH", pdf_path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
std::wstring command_line = L"\"" + std::wstring(arguments[1]) + L"\"";
|
std::wstring command_line = L"\"" + std::wstring(arguments[1]) + L"\"";
|
||||||
STARTUPINFOW startup{};
|
STARTUPINFOW startup{};
|
||||||
startup.cb = sizeof(startup);
|
startup.cb = sizeof(startup);
|
||||||
PROCESS_INFORMATION process{};
|
PROCESS_INFORMATION process{};
|
||||||
|
LPWCH environment = GetEnvironmentStringsW();
|
||||||
if (!CreateProcessW(arguments[1], command_line.data(), nullptr, nullptr,
|
if (!CreateProcessW(arguments[1], command_line.data(), nullptr, nullptr,
|
||||||
FALSE, 0, nullptr, nullptr, &startup, &process)) {
|
FALSE, CREATE_UNICODE_ENVIRONMENT, environment,
|
||||||
|
nullptr, &startup, &process)) {
|
||||||
|
if (environment != nullptr) FreeEnvironmentStringsW(environment);
|
||||||
|
SetEnvironmentVariableA("WORD1_TEST_FILE_DIALOG_PATH", nullptr);
|
||||||
|
SetEnvironmentVariableA("WORD1_TEST_PDF_PATH", nullptr);
|
||||||
std::cerr << "CreateProcessW failed: " << GetLastError() << '\n';
|
std::cerr << "CreateProcessW failed: " << GetLastError() << '\n';
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
if (environment != nullptr) FreeEnvironmentStringsW(environment);
|
||||||
|
SetEnvironmentVariableA("WORD1_TEST_FILE_DIALOG_PATH", nullptr);
|
||||||
|
SetEnvironmentVariableA("WORD1_TEST_PDF_PATH", nullptr);
|
||||||
|
|
||||||
const HWND main_window = wait_for_window(
|
const HWND main_window = wait_for_window(
|
||||||
process.hProcess, process.dwProcessId, nullptr,
|
process.hProcess, process.dwProcessId, nullptr,
|
||||||
@@ -628,13 +707,75 @@ int wmain(const int argument_count, wchar_t** arguments) {
|
|||||||
if (main_window == nullptr) {
|
if (main_window == nullptr) {
|
||||||
return fail(process, 3, "WORD1 main window did not appear");
|
return fail(process, 3, "WORD1 main window did not appear");
|
||||||
}
|
}
|
||||||
|
if (pdf_export_mode) {
|
||||||
|
const HWND pane = find_descendant_by_class(main_window, L"OpusWwd");
|
||||||
|
DWORD ignored_process_id = 0;
|
||||||
|
const DWORD thread_id =
|
||||||
|
GetWindowThreadProcessId(main_window, &ignored_process_id);
|
||||||
|
const LRESULT initial_length = pane != nullptr ?
|
||||||
|
SendMessageW(pane, kWmOpusX64QuerySelection, 41, 0) : 0;
|
||||||
|
const bool focused = pane != nullptr &&
|
||||||
|
(make_foreground_and_focus(main_window, pane, thread_id) ||
|
||||||
|
wait_for_focus(process.hProcess, thread_id, pane, 500));
|
||||||
|
bool typed = focused;
|
||||||
|
for (const wchar_t character : std::wstring(L"pdf export text")) {
|
||||||
|
typed = typed && post_keyboard_character(pane, character);
|
||||||
|
}
|
||||||
|
Sleep(750);
|
||||||
|
const bool committed = typed &&
|
||||||
|
SendMessageW(pane, kWmOpusX64QuerySelection, 41, 0) >
|
||||||
|
initial_length;
|
||||||
|
if (!committed ||
|
||||||
|
!PostMessageW(main_window, kWmCommand, kExportPdf, 0)) {
|
||||||
|
std::cerr << "PDF preparation: focused=" << focused
|
||||||
|
<< " typed=" << typed << " committed=" << committed
|
||||||
|
<< " length=" << initial_length << "->"
|
||||||
|
<< (pane != nullptr ? SendMessageW(
|
||||||
|
pane, kWmOpusX64QuerySelection, 41, 0) : 0)
|
||||||
|
<< '\n';
|
||||||
|
DeleteFileA(pdf_path.c_str());
|
||||||
|
return fail(process, 85,
|
||||||
|
"PDF export test could not prepare its document");
|
||||||
|
}
|
||||||
|
const ULONGLONG deadline = GetTickCount64() + 15000;
|
||||||
|
bool pdf_written = false;
|
||||||
|
while (!pdf_written && GetTickCount64() < deadline &&
|
||||||
|
WaitForSingleObject(process.hProcess, 0) != WAIT_OBJECT_0) {
|
||||||
|
HANDLE pdf = CreateFileA(pdf_path.c_str(), GENERIC_READ,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
nullptr, OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
if (pdf != INVALID_HANDLE_VALUE) {
|
||||||
|
char header[5]{};
|
||||||
|
DWORD read = 0;
|
||||||
|
pdf_written = ReadFile(pdf, header, sizeof(header), &read,
|
||||||
|
nullptr) && read == sizeof(header) &&
|
||||||
|
std::memcmp(header, "%PDF-", sizeof(header)) == 0;
|
||||||
|
CloseHandle(pdf);
|
||||||
|
}
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
DWORD exit_code = STILL_ACTIVE;
|
||||||
|
GetExitCodeProcess(process.hProcess, &exit_code);
|
||||||
|
TerminateProcess(process.hProcess, 0);
|
||||||
|
WaitForSingleObject(process.hProcess, 2000);
|
||||||
|
CloseHandle(process.hThread);
|
||||||
|
CloseHandle(process.hProcess);
|
||||||
|
DeleteFileA(pdf_path.c_str());
|
||||||
|
if (!pdf_written) {
|
||||||
|
std::cerr << "PDF export failed or crashed: exit=0x" << std::hex
|
||||||
|
<< exit_code << std::dec << '\n';
|
||||||
|
return 86;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (save_as_mode) {
|
if (save_as_mode) {
|
||||||
Sleep(1000);
|
Sleep(1000);
|
||||||
if (!PostMessageW(main_window, kWmCommand, kFileSaveAs, 0)) {
|
if (!PostMessageW(main_window, kWmCommand, kFileSaveAs, 0)) {
|
||||||
return fail(process, 69, "could not send File Save As");
|
return fail(process, 69, "could not send File Save As");
|
||||||
}
|
}
|
||||||
const HWND save_as_dialog = wait_for_window(
|
const HWND save_as_dialog = wait_for_window(
|
||||||
process.hProcess, process.dwProcessId, L"OpusSdmDialog",
|
process.hProcess, process.dwProcessId, L"#32770",
|
||||||
L"Save As", 5000);
|
L"Save As", 5000);
|
||||||
if (save_as_dialog == nullptr) {
|
if (save_as_dialog == nullptr) {
|
||||||
std::cerr << "Save As stage="
|
std::cerr << "Save As stage="
|
||||||
@@ -642,17 +783,32 @@ int wmain(const int argument_count, wchar_t** arguments) {
|
|||||||
main_window, "OpusX64SaveAsStage"))
|
main_window, "OpusX64SaveAsStage"))
|
||||||
<< '\n';
|
<< '\n';
|
||||||
log_process_windows(process.dwProcessId);
|
log_process_windows(process.dwProcessId);
|
||||||
return fail(process, 70, "File Save As dialog did not appear");
|
return fail(process, 70,
|
||||||
|
"Windows 95 File Save As dialog did not appear");
|
||||||
}
|
}
|
||||||
if (!control_has_class(save_as_dialog, 2, L"Button") ||
|
if (!control_has_class(save_as_dialog, 2, L"Button") ||
|
||||||
!window_is_responsive(process.hProcess, save_as_dialog)) {
|
!window_is_responsive(process.hProcess, save_as_dialog)) {
|
||||||
return fail(process, 71,
|
return fail(process, 71,
|
||||||
"File Save As dialog did not finish initializing");
|
"File Save As dialog did not finish initializing");
|
||||||
}
|
}
|
||||||
if (!PostMessageW(save_as_dialog, kWmCommand, 2, 0) ||
|
const bool cancel_posted =
|
||||||
!wait_for_window_to_close(process.hProcess, process.dwProcessId,
|
PostMessageW(save_as_dialog, kWmCommand, 2, 0) != FALSE;
|
||||||
L"OpusSdmDialog", 5000) ||
|
const bool dialog_closed = cancel_posted &&
|
||||||
!window_is_responsive(process.hProcess, main_window)) {
|
wait_for_window_to_close(process.hProcess, process.dwProcessId,
|
||||||
|
L"#32770", 5000) &&
|
||||||
|
wait_for_window_to_close(process.hProcess, process.dwProcessId,
|
||||||
|
L"OpusSdmDialog", 5000);
|
||||||
|
const bool app_responsive = dialog_closed &&
|
||||||
|
window_is_responsive(process.hProcess, main_window);
|
||||||
|
if (!cancel_posted || !dialog_closed || !app_responsive) {
|
||||||
|
DWORD exit_code = STILL_ACTIVE;
|
||||||
|
GetExitCodeProcess(process.hProcess, &exit_code);
|
||||||
|
std::cerr << "Save As cancel state: posted=" << cancel_posted
|
||||||
|
<< " closed=" << dialog_closed
|
||||||
|
<< " responsive=" << app_responsive
|
||||||
|
<< " exit=0x" << std::hex << exit_code << std::dec
|
||||||
|
<< '\n';
|
||||||
|
log_process_windows(process.dwProcessId);
|
||||||
return fail(process, 72,
|
return fail(process, 72,
|
||||||
"File Save As dialog did not cancel cleanly");
|
"File Save As dialog did not cancel cleanly");
|
||||||
}
|
}
|
||||||
@@ -662,6 +818,45 @@ int wmain(const int argument_count, wchar_t** arguments) {
|
|||||||
CloseHandle(process.hProcess);
|
CloseHandle(process.hProcess);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (docx_open_mode) {
|
||||||
|
HWND pane = find_descendant_by_class(main_window, L"OpusWwd");
|
||||||
|
if (pane == nullptr ||
|
||||||
|
!PostMessageW(main_window, kWmCommand, kFileOpen, 0)) {
|
||||||
|
return fail(process, 78, "DOCX open test could not open its document");
|
||||||
|
}
|
||||||
|
const ULONGLONG open_deadline = GetTickCount64() + 10000;
|
||||||
|
wchar_t document_caption[512]{};
|
||||||
|
do {
|
||||||
|
GetWindowTextW(main_window, document_caption,
|
||||||
|
static_cast<int>(std::size(document_caption)));
|
||||||
|
if (std::wcsstr(document_caption, L"Document1") == nullptr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Sleep(100);
|
||||||
|
} while (GetTickCount64() < open_deadline &&
|
||||||
|
WaitForSingleObject(process.hProcess, 0) != WAIT_OBJECT_0);
|
||||||
|
// The legacy open command updates the caption before it has finished
|
||||||
|
// activating the replacement MDI child and document pane.
|
||||||
|
Sleep(750);
|
||||||
|
pane = find_visible_descendant_by_class(main_window, L"OpusWwd");
|
||||||
|
const bool reopened =
|
||||||
|
std::wcsstr(document_caption, L"Document1") == nullptr;
|
||||||
|
const LRESULT imported_length = pane != nullptr ?
|
||||||
|
SendMessageW(pane, kWmOpusX64QuerySelection, 41, 0) : 0;
|
||||||
|
const LRESULT displayed_lines = pane != nullptr ?
|
||||||
|
SendMessageW(pane, kWmOpusX64QuerySelection, 30, 0) : 0;
|
||||||
|
TerminateProcess(process.hProcess, 0);
|
||||||
|
WaitForSingleObject(process.hProcess, 2000);
|
||||||
|
CloseHandle(process.hThread);
|
||||||
|
CloseHandle(process.hProcess);
|
||||||
|
if (!reopened || pane == nullptr || imported_length < 100 ||
|
||||||
|
displayed_lines < 1) {
|
||||||
|
std::cerr << "DOCX open state: length=" << imported_length
|
||||||
|
<< " displayedLines=" << displayed_lines << '\n';
|
||||||
|
return 84;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (about_mode) {
|
if (about_mode) {
|
||||||
Sleep(1000);
|
Sleep(1000);
|
||||||
if (!PostMessageW(main_window, kWmCommand, kHelpAbout, 0)) {
|
if (!PostMessageW(main_window, kWmCommand, kHelpAbout, 0)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user