Fixed memory alignment bugs.

Fixed numerous display issues.
Fixed numerous windows messaging issues.
This commit is contained in:
Justin Marshall
2026-08-06 10:50:51 -07:00
parent a1c4a1f9ee
commit 8932607951
94 changed files with 1594 additions and 1513 deletions
+88 -72
View File
@@ -34,62 +34,6 @@ foreach(config Debug Release RelWithDebInfo MinSizeRel)
set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/pdb/${config}") set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/pdb/${config}")
endforeach() endforeach()
set(MSWORD_BOOTSTRAP_SOURCES
port/winword_x64.cpp
port/legacy_asm_port.cpp
port/legacy_asm_port.h
port/winword_x64.rc
port/winword.manifest
)
# This is a migration aid only. It is deliberately excluded from the default
# build and may never claim the final WORD1.exe product name: that name is
# reserved for the executable linked from the original Opus source graph.
add_executable(WINWORD_BOOTSTRAP WIN32 EXCLUDE_FROM_ALL ${MSWORD_BOOTSTRAP_SOURCES})
target_compile_features(WINWORD_BOOTSTRAP PRIVATE cxx_std_20)
target_compile_definitions(WINWORD_BOOTSTRAP PRIVATE UNICODE _UNICODE WIN32_LEAN_AND_MEAN NOMINMAX)
target_include_directories(WINWORD_BOOTSTRAP PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/port")
target_link_libraries(WINWORD_BOOTSTRAP PRIVATE
comctl32
comdlg32
gdi32
ole32
shell32
user32
)
if(MSVC)
target_compile_options(WINWORD_BOOTSTRAP PRIVATE /W4 /permissive- /utf-8 /EHsc /guard:cf)
# The application manifest is compiled as resource 1; disable MSVC's
# second auto-generated manifest to avoid a duplicate RT_MANIFEST entry.
target_link_options(WINWORD_BOOTSTRAP PRIVATE /DYNAMICBASE /HIGHENTROPYVA /NXCOMPAT /MANIFEST:NO)
set_property(TARGET WINWORD_BOOTSTRAP PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
endif()
set_target_properties(WINWORD_BOOTSTRAP PROPERTIES
OUTPUT_NAME "WINWORD_BOOTSTRAP"
RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/bootstrap"
VS_GLOBAL_ROOTNAMESPACE "MicrosoftWordX64Port"
# The target uses only Windows system libraries. Disable Visual Studio's
# global vcpkg app-local hook so it does not invoke an unrelated pwsh.exe.
VS_GLOBAL_VcpkgApplocalDeps "false"
)
foreach(config Debug Release RelWithDebInfo MinSizeRel)
string(TOUPPER "${config}" config_upper)
set_target_properties(WINWORD_BOOTSTRAP PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/bootstrap/${config}"
)
endforeach()
# The original assembly remains in the repository for behavioral reference,
# but no .asm file is permitted to enter the native target.
get_target_property(winword_sources WINWORD_BOOTSTRAP SOURCES)
foreach(source IN LISTS winword_sources)
if(source MATCHES "\\.[aA][sS][mM]$")
message(FATAL_ERROR "Legacy assembly leaked into the x64 target: ${source}")
endif()
endforeach()
file(GLOB_RECURSE LEGACY_ASSEMBLY CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.asm") file(GLOB_RECURSE LEGACY_ASSEMBLY CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.asm")
set(LEGACY_ASSEMBLY_RELATIVE) set(LEGACY_ASSEMBLY_RELATIVE)
foreach(assembly_file IN LISTS LEGACY_ASSEMBLY) foreach(assembly_file IN LISTS LEGACY_ASSEMBLY)
@@ -99,23 +43,11 @@ foreach(assembly_file IN LISTS LEGACY_ASSEMBLY)
endforeach() endforeach()
list(SORT LEGACY_ASSEMBLY_RELATIVE) list(SORT LEGACY_ASSEMBLY_RELATIVE)
# Extract the explicit source paths from the C++ disposition table and compare
# names, not merely counts. Removing one module and adding another cannot pass.
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/port/legacy_asm_port.cpp" ASM_PORT_SOURCE)
string(REGEX MATCHALL "AssemblyPortEntry\\{\"[^\"]+\\.asm\"" ASM_PORT_ROWS "${ASM_PORT_SOURCE}")
set(ASM_PORT_PATHS)
foreach(port_row IN LISTS ASM_PORT_ROWS)
string(REGEX REPLACE "AssemblyPortEntry\\{\"([^\"]+)\"" "\\1" port_path "${port_row}")
list(APPEND ASM_PORT_PATHS "${port_path}")
endforeach()
list(SORT ASM_PORT_PATHS)
list(LENGTH LEGACY_ASSEMBLY_RELATIVE LEGACY_ASSEMBLY_COUNT) list(LENGTH LEGACY_ASSEMBLY_RELATIVE LEGACY_ASSEMBLY_COUNT)
if(NOT LEGACY_ASSEMBLY_COUNT EQUAL 59 OR if(NOT LEGACY_ASSEMBLY_COUNT EQUAL 59)
NOT "${LEGACY_ASSEMBLY_RELATIVE}" STREQUAL "${ASM_PORT_PATHS}")
message(FATAL_ERROR message(FATAL_ERROR
"The assembly-port manifest does not exactly match the legacy source tree " "The original assembly reference tree changed "
"(${LEGACY_ASSEMBLY_COUNT} modules found). Update port/legacy_asm_port.cpp." "(${LEGACY_ASSEMBLY_COUNT} modules found; expected 59). Review the x64 translations."
) )
endif() endif()
@@ -185,6 +117,35 @@ foreach(config Debug Release RelWithDebInfo MinSizeRel)
) )
endforeach() endforeach()
add_executable(opus_cabi_tool EXCLUDE_FROM_ALL
port/tools/opus_cabi_tool.cpp
)
target_compile_features(opus_cabi_tool PRIVATE cxx_std_20)
target_compile_definitions(opus_cabi_tool PRIVATE
WIN WIN23 CRLF NONATIVE OPUS_X64 NOMINMAX
)
target_include_directories(opus_cabi_tool PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/generated/original"
"${CMAKE_CURRENT_SOURCE_DIR}/port/original"
"${CMAKE_CURRENT_SOURCE_DIR}/Opus/lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Opus"
)
if(MSVC)
target_compile_options(opus_cabi_tool PRIVATE
/J /W3 /wd4005 /permissive-)
endif()
set_target_properties(opus_cabi_tool PROPERTIES
FOLDER "Original Opus x64/build tools"
RUNTIME_OUTPUT_DIRECTORY "${MSWORD_BUILD_ROOT}/tools"
VS_GLOBAL_VcpkgApplocalDeps "false"
)
foreach(config Debug Release RelWithDebInfo MinSizeRel)
string(TOUPPER "${config}" config_upper)
set_target_properties(opus_cabi_tool PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tools/${config}"
)
endforeach()
# Preserve Microsoft's original BITAPP resource conversion step. These # Preserve Microsoft's original BITAPP resource conversion step. These
# native x64 tool builds consume the checked-in Win16 .cur files and emit the # native x64 tool builds consume the checked-in Win16 .cur files and emit the
# same byte initializers that SCREEN2.C historically included. # same byte initializers that SCREEN2.C historically included.
@@ -353,6 +314,18 @@ set(OPUS_GENERATED_COMMAND_FILES
"${OPUS_GENERATED_COMMAND_DIR}/opuscmd.asm" "${OPUS_GENERATED_COMMAND_DIR}/opuscmd.asm"
"${OPUS_GENERATED_COMMAND_DIR}/opuscmd_native.inc" "${OPUS_GENERATED_COMMAND_DIR}/opuscmd_native.inc"
) )
file(GLOB OPUS_RECONSTRUCTED_DIALOG_HEADERS CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/port/original/*.hs")
set(OPUS_GENERATED_CABI_DIR "${OPUS_GENERATED_COMMAND_DIR}/cabi")
set(OPUS_GENERATED_CABI_OPEN "${OPUS_GENERATED_CABI_DIR}/open.hs")
add_custom_command(
OUTPUT "${OPUS_GENERATED_CABI_OPEN}"
COMMAND "${CMAKE_COMMAND}" -E make_directory "${OPUS_GENERATED_CABI_DIR}"
COMMAND "$<TARGET_FILE:opus_cabi_tool>" "${OPUS_GENERATED_CABI_DIR}"
DEPENDS opus_cabi_tool ${OPUS_RECONSTRUCTED_DIALOG_HEADERS}
COMMENT "Computing native SDM CAB initializers"
VERBATIM
)
add_custom_command( add_custom_command(
OUTPUT ${OPUS_GENERATED_COMMAND_FILES} OUTPUT ${OPUS_GENERATED_COMMAND_FILES}
COMMAND "${CMAKE_COMMAND}" -E copy_if_different COMMAND "${CMAKE_COMMAND}" -E copy_if_different
@@ -368,7 +341,8 @@ add_custom_command(
"${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/ibcm.rel" "${CMAKE_CURRENT_SOURCE_DIR}/Opus/resource/ibcm.rel"
"${OPUS_GENERATED_COMMAND_DIR}/IBCM.H" "${OPUS_GENERATED_COMMAND_DIR}/IBCM.H"
COMMAND "$<TARGET_FILE:opus_mkcmd_tool>" COMMAND "$<TARGET_FILE:opus_mkcmd_tool>"
-T@13 -s../../../src/Opus/dlg/ opuscmd keys menus -T@13 -s../../../src/Opus/dlg/ -bcabi/
opuscmd keys menus
COMMAND "${CMAKE_COMMAND}" COMMAND "${CMAKE_COMMAND}"
-DINPUT=${OPUS_GENERATED_COMMAND_DIR}/MENUHELP.TXT -DINPUT=${OPUS_GENERATED_COMMAND_DIR}/MENUHELP.TXT
-DOUTPUT=${OPUS_GENERATED_COMMAND_DIR}/menuhelp.h -DOUTPUT=${OPUS_GENERATED_COMMAND_DIR}/menuhelp.h
@@ -380,6 +354,8 @@ add_custom_command(
Opus/resource/menus.cmd Opus/resource/menus.cmd
Opus/resource/ibcm.rel Opus/resource/ibcm.rel
Opus/dlg/elx.txt Opus/dlg/elx.txt
"${OPUS_GENERATED_CABI_OPEN}"
${OPUS_RECONSTRUCTED_DIALOG_HEADERS}
cmake/GenerateMenuHelpHeader.cmake cmake/GenerateMenuHelpHeader.cmake
WORKING_DIRECTORY "${OPUS_GENERATED_COMMAND_DIR}" WORKING_DIRECTORY "${OPUS_GENERATED_COMMAND_DIR}"
COMMENT "Regenerating original Opus command tables with MKCMD" COMMENT "Regenerating original Opus command tables with MKCMD"
@@ -893,6 +869,7 @@ endif()
set_target_properties(WORD1 PROPERTIES set_target_properties(WORD1 PROPERTIES
FOLDER "Original Opus x64/product" FOLDER "Original Opus x64/product"
OUTPUT_NAME "${MSWORD_PRODUCT_OUTPUT_NAME}" OUTPUT_NAME "${MSWORD_PRODUCT_OUTPUT_NAME}"
VS_DEBUGGER_WORKING_DIRECTORY "${MSWORD_BIN_ROOT}"
VS_GLOBAL_VcpkgApplocalDeps "false" VS_GLOBAL_VcpkgApplocalDeps "false"
) )
@@ -965,10 +942,49 @@ foreach(config Debug Release RelWithDebInfo MinSizeRel)
) )
endforeach() endforeach()
add_executable(opus_word1_ui_test
port/original/opus_word1_ui_test.cpp
)
add_dependencies(opus_word1_ui_test WORD1)
target_compile_features(opus_word1_ui_test PRIVATE cxx_std_20)
target_compile_definitions(opus_word1_ui_test PRIVATE NOMINMAX UNICODE _UNICODE)
target_link_libraries(opus_word1_ui_test PRIVATE user32 gdi32)
if(MSVC)
target_compile_options(opus_word1_ui_test PRIVATE /W4 /utf-8)
endif()
set_target_properties(opus_word1_ui_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_word1_ui_test PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${MSWORD_BUILD_ROOT}/tests/${config}"
)
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_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_original_command_test COMMAND $<TARGET_FILE:opus_original_command_test>) add_test(NAME opus_original_command_test COMMAND $<TARGET_FILE:opus_original_command_test>)
add_test(NAME word1_port_smoke_test COMMAND $<TARGET_FILE:WORD1> --self-test) add_test(NAME word1_port_smoke_test COMMAND $<TARGET_FILE:WORD1> --self-test)
add_test(NAME opus_word1_ui_test
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1>
)
set_tests_properties(opus_word1_ui_test PROPERTIES TIMEOUT 20)
add_test(NAME opus_word1_typing_test
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --typing
)
set_tests_properties(opus_word1_typing_test PROPERTIES TIMEOUT 20)
add_test(NAME opus_word1_interaction_test
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --interaction
)
set_tests_properties(opus_word1_interaction_test PROPERTIES TIMEOUT 25)
add_test(NAME opus_word1_selection_test
COMMAND $<TARGET_FILE:opus_word1_ui_test> $<TARGET_FILE:WORD1> --selection
)
set_tests_properties(opus_word1_selection_test PROPERTIES TIMEOUT 20)
+1 -1
View File
@@ -374,7 +374,7 @@ DumpGrpchr()
return; return;
} }
CommSz( SzShared( "\r\n" ) ); CommSz( SzShared( "\r\n" ) );
pchr = ((char *)pchr) + pchr->chrm; pchr = ((char *)pchr) + CbFromChrm(pchr->chrm);
} }
} }
+1 -1
View File
@@ -1719,7 +1719,7 @@ CMB *pcmb;
CommSz("\n\r"); CommSz("\n\r");
pch = rgch; pch = rgch;
} }
(char *)pchr += chrm; (char *)pchr += CbFromChrm(chrm);
} }
return cmdOK; return cmdOK;
} }
+1 -1
View File
@@ -1117,7 +1117,7 @@ NATIVE CkVfli() /* makes CkVfli visible to hand NATIVE */
iAssert = 0; iAssert = 0;
/* = because chrmVanish may preceed ichMac */ /* = because chrmVanish may preceed ichMac */
Assert (vfli.fSplatBreak || pchr->ich <= vfli.ichMac); Assert (vfli.fSplatBreak || pchr->ich <= vfli.ichMac);
(char *)pchr += pchr->chrm; (char *)pchr += CbFromChrm(pchr->chrm);
} }
iAssert = 1; iAssert = 1;
Assert (vfli.doc >= 0 && vfli.doc < docMac); Assert (vfli.doc >= 0 && vfli.doc < docMac);
+10
View File
@@ -155,7 +155,11 @@ CMB * pcmb;
SetBytes(&dli, 0, sizeof (DLI)); SetBytes(&dli, 0, sizeof (DLI));
dli.fdlg = fdlgModal | fdlgFedt; dli.fdlg = fdlgModal | fdlgFedt;
#ifdef OPUS_X64
dli.wRef = (UINT_PTR)pcmb;
#else
dli.wRef = (WORD) pcmb; dli.wRef = (WORD) pcmb;
#endif
/* this returns from this func if there is not enough stack for AllocA below */ /* this returns from this func if there is not enough stack for AllocA below */
ReturnOnNoStack(cb, tmcError, fTrue); ReturnOnNoStack(cb, tmcError, fTrue);
@@ -771,7 +775,13 @@ SuccessCCP:
return(1L); return(1L);
case EM_SETSEL: case EM_SETSEL:
#ifdef OPUS_X64
/* Win32 and later pass the start in wParam and the end in lParam.
* The Win16 edit message packed both 16-bit values into lParam. */
FedtSetSel(hfedt, (int) wParam, (int) lParam);
#else
FedtSetSel(hfedt, LOWORD(lParam), HIWORD(lParam)); FedtSetSel(hfedt, LOWORD(lParam), HIWORD(lParam));
#endif
FedtReleaseDC(hfedt); FedtReleaseDC(hfedt);
break; break;
+4 -4
View File
@@ -956,7 +956,7 @@ int dxpToXw, ywLine;
ptPen.xp = xpNew; ptPen.xp = xpNew;
ptPen.yp = ypNew; ptPen.yp = ypNew;
fNoSkip = vfli.fPrint; fNoSkip = vfli.fPrint;
(char *) pchr += chrmFormula; (char *) pchr += cbCHRF;
} }
else if (chrm == chrmFormatGroup) else if (chrm == chrmFormatGroup)
{ {
@@ -971,7 +971,7 @@ int dxpToXw, ywLine;
} }
/* note that rcOpaque and rcErase will no /* note that rcOpaque and rcErase will no
longer change (rcErase not used) */ longer change (rcErase not used) */
(char *) pchr += chrmFormatGroup; (char *) pchr += cbCHRFG;
} }
else /*if (chrm == chrmEnd)*/ else /*if (chrm == chrmEnd)*/
@@ -1718,8 +1718,8 @@ struct RC *prcwClip;
else if (chrm == chrmEnd) else if (chrm == chrmEnd)
break; break;
bchrCur += chrm; bchrCur += CbFromChrm(chrm);
(char *)pchr += chrm; (char *)pchr += CbFromChrm(chrm);
} }
/* draw CRJ symbol if needed */ /* draw CRJ symbol if needed */
+15 -14
View File
@@ -141,8 +141,9 @@ int *pbchr;
{ {
struct CHR *pchr; struct CHR *pchr;
int bchr = vbchrMac; int bchr = vbchrMac;
if ((vbchrMac += chrm) > vbchrMax) int cb = CbFromChrm(chrm);
if (!FExpandGrpchr(chrm)) if ((vbchrMac += cb) > vbchrMax)
if (!FExpandGrpchr(cb))
return 0; return 0;
pchr = &((**vhgrpchr)[*pbchr = bchr]); pchr = &((**vhgrpchr)[*pbchr = bchr]);
pchr->ich = ich; pchr->ich = ich;
@@ -887,12 +888,12 @@ fraction line is dypFract above the base line (func of hps of *f command)
if (vprsu.prid == pridLaser && vfli.fPrint) if (vprsu.prid == pridLaser && vfli.fPrint)
dypChSym = dypChSym * 9 / 8; dypChSym = dypChSym * 9 / 8;
#endif /* MAC */ #endif /* MAC */
PchpSetChrDyp(pfma1->bchr - chrmChp, PchpSetChrDyp(pfma1->bchr - cbCHR,
dypChSym, dypChSym,
chRootExt, fTrue)->fSpec = fTrue; chRootExt, fTrue)->fSpec = fTrue;
FFormatChSpecSymbol( FFormatChSpecSymbol(
PchpSetChrDyp((bchr = pfma1->bchr - chrmChp - chrmFormula - chrmChp), PchpSetChrDyp((bchr = pfma1->bchr - cbCHR - cbCHRF - cbCHR),
dypChSym, dypChSym,
chRoot, fTrue), chRoot, fTrue),
chRoot, &dxpChSym, &dxtChSym, chRoot, &dxpChSym, &dxtChSym,
@@ -915,7 +916,7 @@ fraction line is dypFract above the base line (func of hps of *f command)
dytAscent = dytAscentCh1 - dyt2; dytAscent = dytAscentCh1 - dyt2;
/* update CHRF to goto start of root symbol */ /* update CHRF to goto start of root symbol */
SetChrf(bchr - chrmFormula, dxp3 - dxpChSym, SetChrf(bchr - cbCHRF, dxp3 - dxpChSym,
dyp2, dyp2,
fFalse); fFalse);
#ifdef MAC /* win does not have prid */ #ifdef MAC /* win does not have prid */
@@ -924,7 +925,7 @@ same place as the root symbol and also ends up there.
On other printers, extension is drawn with width dxp2 after the root symbol */ On other printers, extension is drawn with width dxp2 after the root symbol */
if (vprsu.prid == pridLaser && vfli.fPrint) if (vprsu.prid == pridLaser && vfli.fPrint)
{ {
SetChrf(bchr + chrmChp, - dxpChSym, SetChrf(bchr + cbCHR, - dxpChSym,
0, fFalse); 0, fFalse);
dxpLarger = dxpChSym; /* move right from ext to operand */ dxpLarger = dxpChSym; /* move right from ext to operand */
} }
@@ -1033,7 +1034,7 @@ On other printers, extension is drawn with width dxp2 after the root symbol */
Assert(pchrf->chrm == chrmFormula); Assert(pchrf->chrm == chrmFormula);
/* for fixing up bounding symbols */ /* for fixing up bounding symbols */
bchr -= chrmChp + chrmFormula; bchr -= cbCHR + cbCHRF;
ich = pfma1->ich - 1; ich = pfma1->ich - 1;
ch1 = pfma1->chLeft; ch1 = pfma1->chLeft;
@@ -1049,11 +1050,11 @@ On other printers, extension is drawn with width dxp2 after the root symbol */
{ {
if (ch2 != 0) if (ch2 != 0)
{ {
bchr -= chrmChp + chrmFormula; bchr -= cbCHR + cbCHRF;
ich--; ich--;
} }
FFormatChSpecSymbol( FFormatChSpecSymbol(
PchpSetChrDyp(bchr + chrmFormula, dyp1, ch1, fTrue), PchpSetChrDyp(bchr + cbCHRF, dyp1, ch1, fTrue),
ch1, &dxp2, &dxt2, ch1, &dxp2, &dxt2,
&dypAscentCh1, &dypDescentCh1, &dytAscentCh1, &dytDescentCh1); &dypAscentCh1, &dypDescentCh1, &dytAscentCh1, &dytDescentCh1);
SetChrf(bchr, 0, dyp2 = SetChrf(bchr, 0, dyp2 =
@@ -1065,7 +1066,7 @@ On other printers, extension is drawn with width dxp2 after the root symbol */
(dytDescentCh1 + dytAscentCh1 - dyt1) / 2; (dytDescentCh1 + dytAscentCh1 - dyt1) / 2;
vfli.rgdxp[ich++] = dxp2; vfli.rgdxp[ich++] = dxp2;
bchr += chrmChp + chrmFormula; bchr += cbCHR + cbCHRF;
} }
/* right symbol */ /* right symbol */
@@ -1078,7 +1079,7 @@ On other printers, extension is drawn with width dxp2 after the root symbol */
else else
{ {
FFormatChSpecSymbol( FFormatChSpecSymbol(
PchpSetChrDyp(bchr + chrmFormula, dyp1, ch2, fTrue), PchpSetChrDyp(bchr + cbCHRF, dyp1, ch2, fTrue),
ch2, &dxp3, &dxt3, ch2, &dxp3, &dxt3,
&dypAscentCh2, &dypDescentCh2, &dytAscentCh2, &dytDescentCh2); &dypAscentCh2, &dypDescentCh2, &dytAscentCh2, &dytDescentCh2);
SetChrf(bchr, dxp1, -dyp2 + (dyp3 = SetChrf(bchr, dxp1, -dyp2 + (dyp3 =
@@ -1142,7 +1143,7 @@ On other printers, extension is drawn with width dxp2 after the root symbol */
dyt3 = pfmaEnd->dytAscent + pfmaEnd->dytDescent; dyt3 = pfmaEnd->dytAscent + pfmaEnd->dytDescent;
/* calculate size of symbol */ /* calculate size of symbol */
bchr = pfma1->bchr - chrmChp; bchr = pfma1->bchr - cbCHR;
ch1 = pfma1->chLeft; ch1 = pfma1->chLeft;
FFormatChSpecSymbol( FFormatChSpecSymbol(
@@ -1211,7 +1212,7 @@ On other printers, extension is drawn with width dxp2 after the root symbol */
dxtLarger = max(dxt1, dxt2); dxtLarger = max(dxt1, dxt2);
/* goto start of symbol */ /* goto start of symbol */
SetChrf(bchr - chrmFormula, 0, SetChrf(bchr - cbCHRF, 0,
dyp3, dyp3,
fFalse); fFalse);
@@ -1255,7 +1256,7 @@ On other printers, extension is drawn with width dxp2 after the root symbol */
dxt1 / 2 )) - dxtChSym / 2; dxt1 / 2 )) - dxtChSym / 2;
/* goto start of symbol */ /* goto start of symbol */
SetChrf(bchr - chrmFormula, SetChrf(bchr - cbCHRF,
dxpLarger, dxpLarger,
dyp3, dyp3,
fFalse); fFalse);
+47
View File
@@ -108,8 +108,13 @@ extern int vwWinVersion;
extern CHAR szNone[]; extern CHAR szNone[];
extern struct PREF vpref; extern struct PREF vpref;
extern long vcmsecHelp; extern long vcmsecHelp;
#ifdef OPUS_X64
extern WPARAM vwParamHelp;
extern LPARAM vlParamHelp;
#else
extern WORD vwParamHelp; extern WORD vwParamHelp;
extern LONG vlParamHelp; extern LONG vlParamHelp;
#endif
extern int wwCur; extern int wwCur;
extern int mwCur; extern int mwCur;
extern int vlm; extern int vlm;
@@ -137,12 +142,21 @@ extern struct FB vfbReplace;
extern int far pascal initwin_q(); extern int far pascal initwin_q();
#ifdef OPUS_X64
int ImnuFromHMenu(HMENU, UINT_PTR);
#endif
/* G L O B A L S */ /* G L O B A L S */
long vcmsecHelp = 0L; /* Time (in msec) to invalidate */ long vcmsecHelp = 0L; /* Time (in msec) to invalidate */
/* double-clicking for help mode. */ /* double-clicking for help mode. */
#ifdef OPUS_X64
WPARAM vwParamHelp; /* Saved native WM_MENUSELECT parameters */
LPARAM vlParamHelp = 0;
#else
WORD vwParamHelp; /* Saved for cxt computation */ WORD vwParamHelp; /* Saved for cxt computation */
LONG vlParamHelp = 0; /* Saved for cxt computation */ LONG vlParamHelp = 0; /* Saved for cxt computation */
#endif
HWND vhwndCBT = NULL; /* CBT application window */ HWND vhwndCBT = NULL; /* CBT application window */
BOOL vfHelp = fFalse; /* whether we're in Help mode */ BOOL vfHelp = fFalse; /* whether we're in Help mode */
int vcxtHelp = cxtNil; /* current context */ int vcxtHelp = cxtNil; /* current context */
@@ -581,17 +595,30 @@ HWND hwnd;
one of the drop-downs). It is cxtDocMenuSelect if we have hilighted one of the drop-downs). It is cxtDocMenuSelect if we have hilighted
something in the Doc system menu. something in the Doc system menu.
*/ */
#ifdef OPUS_X64
int CxtMenuSelect(WPARAM wParam, LPARAM lParam, int cxt)
#else
int CxtMenuSelect(wParam, lParam, cxt) int CxtMenuSelect(wParam, lParam, cxt)
WORD wParam; WORD wParam;
LONG lParam; LONG lParam;
int cxt; int cxt;
#endif
{ {
#ifdef OPUS_X64
int mf = HIWORD(wParam);
WORD item = LOWORD(wParam);
#else
int mf = LOWORD(lParam); int mf = LOWORD(lParam);
#endif
Assert(cxt == cxtAppMenuSelect || cxt == cxtDocMenuSelect); Assert(cxt == cxtAppMenuSelect || cxt == cxtDocMenuSelect);
/* this case should have been taken care of in SaveMenuHelpContext */ /* this case should have been taken care of in SaveMenuHelpContext */
#ifdef OPUS_X64
Assert(lParam != 0);
#else
Assert (HIWORD(lParam) != 0 && wParam != 0); Assert (HIWORD(lParam) != 0 && wParam != 0);
#endif
/* Application or Document system menu */ /* Application or Document system menu */
if (mf & MF_SYSMENU) if (mf & MF_SYSMENU)
@@ -605,8 +632,13 @@ int cxt;
the SC_ code of the menu item */ the SC_ code of the menu item */
{ {
return ((cxt == cxtAppMenuSelect) ? return ((cxt == cxtAppMenuSelect) ?
#ifdef OPUS_X64
CxtAppSysMenu(item) :
CxtDocSysMenu(item));
#else
CxtAppSysMenu(wParam) : CxtAppSysMenu(wParam) :
CxtDocSysMenu(wParam)); CxtDocSysMenu(wParam));
#endif
} }
} }
@@ -614,7 +646,13 @@ int cxt;
/* HIWORD is the main menu handle; wParam is the submenu handle */ /* HIWORD is the main menu handle; wParam is the submenu handle */
if (mf & MF_POPUP) if (mf & MF_POPUP)
{ {
#ifdef OPUS_X64
HMENU hMenu = (HMENU) lParam;
HMENU hPopup = GetSubMenu(hMenu, item);
int imnu = ImnuFromHMenu(hMenu, (UINT_PTR) hPopup);
#else
int imnu = ImnuFromHMenu(HIWORD(lParam), wParam); int imnu = ImnuFromHMenu(HIWORD(lParam), wParam);
#endif
#ifdef DEBUG #ifdef DEBUG
#define imnuHelp 11 /* stolen from menuhelp.c */ #define imnuHelp 11 /* stolen from menuhelp.c */
/* give the right context for Help menu in debug version (debug /* give the right context for Help menu in debug version (debug
@@ -631,7 +669,11 @@ int cxt;
{ {
/* MF_SYSMENU && !MF_POPUP case handled in CmdHelp */ /* MF_SYSMENU && !MF_POPUP case handled in CmdHelp */
Assert (!(mf & MF_SYSMENU)); Assert (!(mf & MF_SYSMENU));
#ifdef OPUS_X64
return (CxtFromBcm(item));
#else
return (CxtFromBcm(wParam)); return (CxtFromBcm(wParam));
#endif
} }
} }
@@ -748,8 +790,13 @@ CMD CmdHelp(pcmb)
CMB *pcmb; CMB *pcmb;
{ {
int cxt = vcxtHelp; /* because EndMenu can blow away vcxtHelp */ int cxt = vcxtHelp; /* because EndMenu can blow away vcxtHelp */
#ifdef OPUS_X64
WPARAM wParamSav = vwParamHelp; /* EndMenu resets these globals */
LPARAM lParamSav = vlParamHelp;
#else
WORD wParamSav = vwParamHelp; /* EndMenu resets these globals */ WORD wParamSav = vwParamHelp; /* EndMenu resets these globals */
LONG lParamSav = vlParamHelp; LONG lParamSav = vlParamHelp;
#endif
EndMenu(); /* end menu mode if we're in it */ EndMenu(); /* end menu mode if we're in it */
+12
View File
@@ -401,7 +401,11 @@ typedef struct _dli // DiaLog Initializer.
HWND hwnd; HWND hwnd;
int dx, dy; int dx, dy;
FDLG fdlg; FDLG fdlg;
#ifdef OPUS_X64
UINT_PTR wRef;
#else
WORD wRef; WORD wRef;
#endif
BYTE * rgb; // App-supplied rgtmw (in sbDlg). BYTE * rgb; // App-supplied rgtmw (in sbDlg).
#ifdef SDM_MULTI_SB #ifdef SDM_MULTI_SB
@@ -419,7 +423,11 @@ typedef struct _dli // DiaLog Initializer.
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Misc Functions . // Misc Functions .
#ifdef OPUS_X64
extern UINT_PTR PASCAL wRefDlgCur; // Cached pointer-sized value.
#else
extern WORD PASCAL wRefDlgCur; // Cached value. extern WORD PASCAL wRefDlgCur; // Cached value.
#endif
extern HCAB PASCAL hcabDlgCur; // Cached value. extern HCAB PASCAL hcabDlgCur; // Cached value.
#define WRefDlgCur() wRefDlgCur #define WRefDlgCur() wRefDlgCur
@@ -743,7 +751,11 @@ typedef struct _dlh
// of mess in the sdm .c files. // of mess in the sdm .c files.
#endif //!SDM_ENV_PM #endif //!SDM_ENV_PM
#ifdef OPUS_X64
UINT_PTR wRef; // User supplied Dialog pointer/value.
#else
WORD wRef; // User supplied Dialog word. WORD wRef; // User supplied Dialog word.
#endif
FDLG fdlg; // Dialog flags. FDLG fdlg; // Dialog flags.
WORD hid; // Help ID. WORD hid; // Help ID.
} DLH; // Public part of DLG structure. } DLH; // Public part of DLG structure.
+15 -3
View File
@@ -32,6 +32,10 @@ extern CHAR vstPrompt[];
extern int vfSysMenu; extern int vfSysMenu;
char *PchGetStr(); char *PchGetStr();
#ifdef OPUS_X64
int ImnuFromHMenu(HMENU, UINT_PTR);
#endif
/* This file is generated by a series of processes from OpusCmd.CMD /* This file is generated by a series of processes from OpusCmd.CMD
* it contains the help prompt strings in compressed form. * it contains the help prompt strings in compressed form.
*/ */
@@ -103,10 +107,14 @@ csconst char csrgstMenuBarHelp [] [] =
/* D R A W M E N U H E L P */ /* D R A W M E N U H E L P */
/* Called from WM_MENUSELECT handler... */ /* Called from WM_MENUSELECT handler... */
/* %%Function:DrawMenuHelp %%Owner:krishnam */ /* %%Function:DrawMenuHelp %%Owner:krishnam */
#ifdef OPUS_X64
void DrawMenuHelp(HMENU hMenu, UINT_PTR bcm, int mf)
#else
DrawMenuHelp(hMenu, bcm, mf) DrawMenuHelp(hMenu, bcm, mf)
HMENU hMenu; HMENU hMenu;
BCM bcm; BCM bcm;
int mf; int mf;
#endif
{ {
char FAR * lpst; char FAR * lpst;
int cch; int cch;
@@ -153,11 +161,11 @@ int mf;
goto LHaveString; goto LHaveString;
} }
else if (mf & MF_SYSMENU) else if (mf & MF_SYSMENU)
bcm = BcmFromSysMenu(bcm); bcm = BcmFromSysMenu((WORD) bcm);
{ {
CHAR szT[256]; CHAR szT[256];
GetMenuHelpSz(bcm, szT); GetMenuHelpSz((BCM) bcm, szT);
SzToStInPlace(szT); SzToStInPlace(szT);
*szT = min (*szT, cchPromptMax-1); *szT = min (*szT, cchPromptMax-1);
CopySt (szT, vstPrompt); CopySt (szT, vstPrompt);
@@ -169,8 +177,12 @@ LHaveString:
/* %%Function:ImnuFromMenu %%Owner:krishnam */ /* %%Function:ImnuFromMenu %%Owner:krishnam */
#ifdef OPUS_X64
int ImnuFromHMenu(HMENU hMenu, UINT_PTR bcm)
#else
int ImnuFromHMenu(hMenu, bcm) int ImnuFromHMenu(hMenu, bcm)
HMENU hMenu; HMENU hMenu;
#endif
{ {
int imnu = 0; int imnu = 0;
HMENU hMenuT; HMENU hMenuT;
@@ -180,7 +192,7 @@ HMENU hMenu;
while ((hMenuT = GetSubMenu(vhMenu, imnu++)) != NULL) while ((hMenuT = GetSubMenu(vhMenu, imnu++)) != NULL)
{ {
if (hMenuT == bcm) if ((UINT_PTR) hMenuT == (UINT_PTR) bcm)
{ {
if (!vfSysMenu) if (!vfSysMenu)
imnu++; imnu++;
+1 -1
View File
@@ -511,7 +511,7 @@ DYY *pdyyAscent, *pdyyDescent;
Profile( vpfi == pfiPictFmt ? StartProf( 30) : 0); Profile( vpfi == pfiPictFmt ? StartProf( 30) : 0);
/* find the CP for the picture, taking vanished text into account */ /* find the CP for the picture, taking vanished text into account */
for (vfmtss.cpRef = vfli.cpMin + ich; bchr < vbchrMac; bchr += pchr->chrm) for (vfmtss.cpRef = vfli.cpMin + ich; bchr < vbchrMac; bchr += CbFromChrm(pchr->chrm))
{ {
pchr = (char *) **vhgrpchr + bchr; pchr = (char *) **vhgrpchr + bchr;
if (pchr->ich > ich) if (pchr->ich > ich)
+14 -4
View File
@@ -477,6 +477,8 @@ LEndPaint:
case WM_VSCROLL: case WM_VSCROLL:
{ {
int sbMessage;
int posNew;
/* Deals with mouse activity in vertical scroll bar. /* Deals with mouse activity in vertical scroll bar.
Jumps by 1 or 2 pages (depending on vpvs.fFacing flag) Jumps by 1 or 2 pages (depending on vpvs.fFacing flag)
unless thumb is manually moved, in which case the unless thumb is manually moved, in which case the
@@ -491,10 +493,18 @@ LEndPaint:
goto LRet; goto LRet;
} }
switch (wParam) #ifdef OPUS_X64
sbMessage = LOWORD(wParam);
posNew = HIWORD(wParam);
#else
sbMessage = wParam;
posNew = LOWORD(lParam);
#endif
switch (sbMessage)
{ {
case SB_THUMBPOSITION: case SB_THUMBPOSITION:
fFail = !FGotoPagePrvw(hdc,LOWORD(lParam),dipgdRandom); fFail = !FGotoPagePrvw(hdc, posNew, dipgdRandom);
break; break;
case SB_THUMBTRACK: case SB_THUMBTRACK:
@@ -507,10 +517,10 @@ LEndPaint:
struct PLCPGD **hplcpgd = PdodDoc(vpvs.docPrvw)->hplcpgd; struct PLCPGD **hplcpgd = PdodDoc(vpvs.docPrvw)->hplcpgd;
CP cpThumb; CP cpThumb;
if (LOWORD(lParam) == vpvs.ypLastScrlBar) if (posNew == vpvs.ypLastScrlBar)
cpThumb= cpMac-1; cpThumb= cpMac-1;
else else
cpThumb = (cpMac*LOWORD(lParam))/(vpvs.ypLastScrlBar); cpThumb = (cpMac*posNew)/(vpvs.ypLastScrlBar);
if (hplcpgd == hNil || (ipgd=IInPlcCheck(hplcpgd,cpThumb)) < 0) if (hplcpgd == hNil || (ipgd=IInPlcCheck(hplcpgd,cpThumb)) < 0)
ipgd = 0; ipgd = 0;
if (ipgd != ipgdLast) if (ipgd != ipgdLast)
+1 -1
View File
@@ -1868,7 +1868,7 @@ struct RC *prc;
pdxp = &vfli.rgdxp[0]; pdxp = &vfli.rgdxp[0];
ich = 0; ich = 0;
FreezeHp(); FreezeHp();
for (pchr = &(**vhgrpchr)[0]; ; (char *)pchr += chrm) for (pchr = &(**vhgrpchr)[0]; ; (char *)pchr += CbFromChrm(chrm))
{ {
for (ichNext = pchr->ich; cpT < cpPic && ich < ichNext; ich++, cpT++) for (ichNext = pchr->ich; cpT < cpPic && ich < ichNext; ich++, cpT++)
xp += *pdxp++; xp += *pdxp++;
+16
View File
@@ -227,11 +227,15 @@ int n1, n2;
/* %%Function:AppWndProcRare %%Owner:chic */ /* %%Function:AppWndProcRare %%Owner:chic */
#ifdef OPUS_X64
LRESULT AppWndProcRare(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
#else
long AppWndProcRare(hwnd, message, wParam, lParam) long AppWndProcRare(hwnd, message, wParam, lParam)
HWND hwnd; HWND hwnd;
int message; int message;
WORD wParam; WORD wParam;
LONG lParam; LONG lParam;
#endif
{ {
HDLG hdlg; HDLG hdlg;
LPPOINT rgpt; LPPOINT rgpt;
@@ -328,7 +332,11 @@ LONG lParam;
EnsureFocusInPane(); EnsureFocusInPane();
if (vfRecording && fRecordMove) if (vfRecording && fRecordMove)
#ifdef OPUS_X64
RecordAppMove((short) LOWORD(lParam), (short) HIWORD(lParam));
#else
RecordAppMove(LOWORD(lParam), HIWORD(lParam)); RecordAppMove(LOWORD(lParam), HIWORD(lParam));
#endif
fRecordMove = fFalse; fRecordMove = fFalse;
defproc: defproc:
@@ -449,7 +457,11 @@ defproc:
InvalidateRect(wParam, (LPRECT) NULL, fTrue); InvalidateRect(wParam, (LPRECT) NULL, fTrue);
break; break;
} }
#ifdef OPUS_X64
PaintClipboard((HWND) wParam, (HANDLE) lParam);
#else
PaintClipboard( wParam, LOWORD(lParam) ); PaintClipboard( wParam, LOWORD(lParam) );
#endif
break; break;
case WM_VSCROLLCLIPBOARD: case WM_VSCROLLCLIPBOARD:
@@ -484,7 +496,11 @@ defproc:
if (vrf.fInDisplayFli) if (vrf.fInDisplayFli)
break; break;
#ifdef OPUS_X64
SizeClipboard((HWND) wParam, (HANDLE) lParam);
#else
SizeClipboard( wParam, LOWORD(lParam) ); SizeClipboard( wParam, LOWORD(lParam) );
#endif
break; break;
case WM_ASKCBFORMATNAME: case WM_ASKCBFORMATNAME:
+2 -2
View File
@@ -706,8 +706,8 @@ long lParam;
"FSplitBoxMouse"); "FSplitBoxMouse");
break; break;
} }
pt.xp = LOWORD(lParam); pt.xp = (short) LOWORD(lParam);
pt.yp = HIWORD(lParam); pt.yp = (short) HIWORD(lParam);
ClientToScreen(hwnd, (LPPOINT) &pt ); ClientToScreen(hwnd, (LPPOINT) &pt );
TrackSplitBar( pt, wk ); TrackSplitBar( pt, wk );
if ((wk == wkFtn || wk == wkAtn) && PwwdWw(wwCur)->wk == wk) if ((wk == wkFtn || wk == wkAtn) && PwwdWw(wwCur)->wk == wk)
+24
View File
@@ -17,6 +17,19 @@ struct EDL
union { union {
int grpfEdl; int grpfEdl;
struct { struct {
#ifdef OPUS_X64
/* Win16 packed dcpDepend and the EDL flags into one word. A
* byte followed by int bitfields starts a second allocation unit
* under MSVC x64, so grpfEdl = 0 did not clear dlk and the other
* flags. Keep the original four-byte overlay explicitly. */
unsigned int dcpDepend : 8;
unsigned int dlk : 3;
unsigned int fDirty : 1;
unsigned int fHasBitmap : 1;
unsigned int fTableDirty : 1;
unsigned int fColorMFP : 1;
unsigned int fNeedEnhance : 1;
#else
unsigned char dcpDepend; unsigned char dcpDepend;
int dlk : 3; int dlk : 3;
int fDirty : 1; int fDirty : 1;
@@ -24,8 +37,18 @@ struct EDL
int fTableDirty : 1; int fTableDirty : 1;
int fColorMFP: 1; /* color metafile (WIN) */ int fColorMFP: 1; /* color metafile (WIN) */
int fNeedEnhance: 1; /* postponed display (WIN) */ int fNeedEnhance: 1; /* postponed display (WIN) */
#endif
}; };
struct { struct {
#ifdef OPUS_X64
unsigned int : 8;
unsigned int fEnd : 1;
unsigned int fEndPage : 1;
unsigned int fEndDr : 1;
unsigned int : 1;
unsigned int fRMark : 1;
unsigned int : 3;
#else
int : 8; int : 8;
/* set iff edl is the endmark. Other fields are then: /* set iff edl is the endmark. Other fields are then:
cp = cpMac of doc, dcpMac = 0 */ cp = cpMac of doc, dcpMac = 0 */
@@ -39,6 +62,7 @@ cp = cpMac of doc, dcpMac = 0 */
/**/ /**/
int fRMark : 1; int fRMark : 1;
int : 3; int : 3;
#endif
}; };
}; };
struct { struct {
+2 -2
View File
@@ -2883,7 +2883,7 @@ LEndWord:
cpChr = cpT; cpChr = cpT;
} }
ichChr = pchr->ich; ichChr = pchr->ich;
*pbchrBreak += chrm; *pbchrBreak += CbFromChrm(chrm);
} }
/* now ichLim is in the "break" run */ /* now ichLim is in the "break" run */
vfli.cpMac = cpChr + ichLim - ichChr; vfli.cpMac = cpChr + ichLim - ichChr;
@@ -3010,7 +3010,7 @@ else if (chrm == chrmFormula)
#endif #endif
if (chrm == chrmEnd) break; if (chrm == chrmEnd) break;
(char *)pchr += chrm; (char *)pchr += CbFromChrm(chrm);
} }
if ((CP) ich >= dcp) if ((CP) ich >= dcp)
{ {
+27 -1
View File
@@ -335,10 +335,30 @@ struct CHRFG
#define cbCHRFG sizeof(struct CHRFG) #define cbCHRFG sizeof(struct CHRFG)
/* The original 16-bit layout used each structure's byte length as its type
tag, which made grpchr records self-scanning. Native x64 alignment makes
some otherwise unrelated records the same size (CHR and CHRDF are both 32
bytes), so the x64 port uses explicit unique tags and maps them back to their
storage lengths while scanning. */
#ifdef OPUS_X64
#define chrmEnd 1
#define chrmChp 2
#define chrmTab 3
#define chrmVanish 4
#define chrmFormula 5
#define chrmDisplayField 6
#define chrmFormatGroup 7
#define CbFromChrm(chrm) \
((chrm) == chrmChp ? cbCHR : \
(chrm) == chrmTab ? cbCHRT : \
(chrm) == chrmVanish ? cbCHRV : \
(chrm) == chrmFormula ? cbCHRF : \
(chrm) == chrmDisplayField ? cbCHRDF : \
(chrm) == chrmFormatGroup ? cbCHRFG : cbCHRE)
#else
/* chrm's are also used as the lengths of the structures so that grpchr /* chrm's are also used as the lengths of the structures so that grpchr
can be scanned easily. Note that in case of cbCHRT = cbCHRV we fudge the can be scanned easily. Note that in case of cbCHRT = cbCHRV we fudge the
numbers so that they come out all different */ numbers so that they come out all different */
#define chrmChp cbCHR /* 14(mac) 18(win) */ #define chrmChp cbCHR /* 14(mac) 18(win) */
#define chrmTab cbCHRT /* 4 */ #define chrmTab cbCHRT /* 4 */
#define chrmVanish cbCHRV /* 6 */ #define chrmVanish cbCHRV /* 6 */
@@ -348,6 +368,8 @@ numbers so that they come out all different */
/* the chrmEnd type chr has no separate definition, we just use the first /* the chrmEnd type chr has no separate definition, we just use the first
two bytes of a chr */ two bytes of a chr */
#define chrmEnd cbCHRE /* 2 */ #define chrmEnd cbCHRE /* 2 */
#define CbFromChrm(chrm) (chrm)
#endif
#ifdef MAC #ifdef MAC
@@ -396,7 +418,11 @@ typedef union {
int dyp; int dyp;
int dyt; int dyt;
}; };
#ifdef OPUS_X64
long long wlAll; /* covers both native 32-bit metric fields */
#else
long wlAll; long wlAll;
#endif
} DYY; } DYY;
#else #else
typedef union { typedef union {
+13
View File
@@ -1403,6 +1403,11 @@ LNoHyphen:
} }
else else
{ {
/* Appending just beyond the terminal display PLC must dirty the DR
* itself, not only the WWD. InvalCp3 deliberately ignores ranges
* beyond the currently displayed cpMac, so without this the window
* is later marked clean with no EDL for the new paragraph. */
pdrT->fDirty = fTrue;
FreePdrf(&drfFetch); FreePdrf(&drfFetch);
InvalCp(PcaSet(&caT, selCur.doc, cpMinInval, cpMinInval + 1)); InvalCp(PcaSet(&caT, selCur.doc, cpMinInval, cpMinInval + 1));
UpdateWw(wwCur, fFalse); UpdateWw(wwCur, fFalse);
@@ -1636,6 +1641,14 @@ not following in cp space (yp space already checked above) */
/* next line is invalid if it exists (<dlMac) and /* next line is invalid if it exists (<dlMac) and
not following in cp space or not following in yp space */ not following in cp space or not following in yp space */
if (cpNextLine != vfli.cpMac || if (cpNextLine != vfli.cpMac ||
#ifdef OPUS_X64
/* The quick-insert piece can leave the terminal PLC
* boundary equal to the EOP line's cpMac even though
* the insertion point is the start of a new paragraph.
* Do not mark the window clean until UpdateWw has
* materialized that following display line. */
(dl >= IMacPlc(hplcedl) && cpInsNew >= vfli.cpMac) ||
#endif
(dl < IMacPlc(hplcedl) && (dl < IMacPlc(hplcedl) &&
((GetPlc(hplcedl, dl, &edl), edl.fDirty) || ((GetPlc(hplcedl, dl, &edl), edl.fDirty) ||
edl.ypTop != ypTop + vfli.dypLine)) || edl.ypTop != ypTop + vfli.dypLine)) ||
+32 -12
View File
@@ -133,26 +133,40 @@ struct SCC
}; };
struct CA ca; struct CA ca;
}; };
int dcpDepend : 8; unsigned char dcpDepend;
#ifdef OPUS_X64 #ifdef OPUS_X64
int fDirtyDr : 1; int fDirtyDr : 1;
#else #else
int fDirty : 1; int fDirty : 1;
#endif #endif
int fCpBad : 1; int fCpBad : 1;
int fLimSuspect: 1; int fLimSuspect : 1;
int : 5; int fNoParaStart : 1;
int fIncomplete : 1;
int fInTable : 1;
int fBottomTableFrame : 1;
int fForceWidth : 1;
struct PLCEDL **hplcedl; struct PLCEDL **hplcedl;
int dypAbove; int dypAbove;
int dxpOutLeft; int dxpOutLeft;
int dxpOutRight; int dxpOutRight;
int idrFlow; /* text should flow to this dr */ int idrFlow; /* text should flow to this dr */
int lrk; /* type of lr from which this came */ char ccolM1;
int fNoPrev : 1; /* redundant bit: 1 means there is no char lrk; /* type of lr from which this came */
dr with this dr as successor */ int fNoPrev : 1; /* redundant bit: 1 means there is no
int fConstrainLeft : 1; /* constrained by abs on left */ dr with this dr as successor */
int fConstrainRight : 1; /* on right */ int fConstrainLeft : 1; /* constrained by abs on left */
int wSpare1 : 13; /* spare for future use */ int fConstrainRight : 1; /* on right */
int fNewColOnly : 1;
int fFatLine : 1;
int fCantGrow : 1;
int fHdrFtr : 1;
int fForceFirstRow : 1;
int fRMark : 1;
int fSpaceBefore : 1;
int : 6;
int xwLimScroll;
int dxaBetween;
/* Note: the DR definition now includes a PLCEDL /* Note: the DR definition now includes a PLCEDL
header, but this is only for far PLCEDL's. Since header, but this is only for far PLCEDL's. Since
the SCC is using a near PLCEDL defined at the the SCC is using a near PLCEDL defined at the
@@ -212,6 +226,12 @@ struct SCC
}; };
}; };
#ifdef OPUS_X64
typedef char OPUS_SCC_HPLCEDL_OFFSET_MUST_MATCH_DR[
(offsetof(struct SCC, hplcedl) - offsetof(struct SCC, rgdr) ==
offsetof(struct DR, hplcedl)) ? 1 : -1];
#endif
#define cwSCC (sizeof (struct SCC) / sizeof (int)) #define cwSCC (sizeof (struct SCC) / sizeof (int))
#define cbBmbAbove 20000 #define cbBmbAbove 20000
+26 -26
View File
@@ -23,21 +23,21 @@ struct SEL
{ {
union { union {
struct { struct {
int : 10; unsigned int : 10;
int sk : 6; unsigned int sk : 6;
}; };
struct { struct {
int fRightward : 1; unsigned int fRightward : 1;
int fSelAtPara: 1; unsigned int fSelAtPara: 1;
int fWithinCell : 1; unsigned int fWithinCell : 1;
int fTableAnchor : 1; unsigned int fTableAnchor : 1;
int : 6; unsigned int : 6;
int fColumn : 1; unsigned int fColumn : 1;
int fTable : 1; unsigned int fTable : 1;
int fGraphics : 1; unsigned int fGraphics : 1;
int fBlock : 1; unsigned int fBlock : 1;
int fNil : 1; unsigned int fNil : 1;
int fIns : 1; unsigned int fIns : 1;
}; };
}; };
unsigned char fForward; unsigned char fForward;
@@ -89,22 +89,22 @@ struct SEL
int dyp; int dyp;
/* tick at which cursor was last blinked */ /* tick at which cursor was last blinked */
long tickOld; long tickOld;
int fUpdateChp : 1; unsigned int fUpdateChp : 1;
int fUpdateChpGray : 1; unsigned int fUpdateChpGray : 1;
int fUpdatePap : 1; unsigned int fUpdatePap : 1;
int fUpdateRibbon : 1; unsigned int fUpdateRibbon : 1;
int fUpdateRuler : 1; unsigned int fUpdateRuler : 1;
int fUpdateStatLine : 1; unsigned int fUpdateStatLine : 1;
int fUpdateStatLine2: 1; unsigned int fUpdateStatLine2: 1;
#ifdef MAC #ifdef MAC
int fNinchChp : 1; unsigned int fNinchChp : 1;
int fNinchPap : 1; unsigned int fNinchPap : 1;
int fNinchSep : 1; unsigned int fNinchSep : 1;
int fItalic : 1; unsigned int fItalic : 1;
int : 5; unsigned int : 5;
#else #else
int : 9; unsigned int : 9;
#endif /* MAC */ #endif /* MAC */
struct RC rcwClip; struct RC rcwClip;
struct CHP chp; struct CHP chp;
+1 -1
View File
@@ -957,7 +957,7 @@ over xp, depending whichever is closer to the middle point of the char */
break; break;
} }
/* note how chrm is cb of the variant chr structure! */ /* note how chrm is cb of the variant chr structure! */
(char *)pchr += chrm; (char *)pchr += CbFromChrm(chrm);
} }
LHaveCp: LHaveCp:
+8
View File
@@ -107,6 +107,14 @@ typedef IB HUGE * HQ;
/* for source compatibilty with Opus huge block manipulations */ /* for source compatibilty with Opus huge block manipulations */
struct BPS HUGE *HpbpsIbp(); struct BPS HUGE *HpbpsIbp();
#ifdef OPUS_X64
/* Native replacement for FILEWINN.ASM. This must be declared because an
* implicit-int call truncates the flat cache-page pointer on AMD64. */
CHAR HUGE *HpOfBptbExt(int ibp);
/* DEBUG.H remaps HpchGetPn calls to the translated native entry. Declare
* that entry before the remap so C callers retain the full AMD64 pointer. */
CHAR HUGE *N_HpchGetPn(int fn, int pn);
#endif
+1 -1
View File
@@ -644,7 +644,7 @@ struct PREF
int fShowAllMacros: 1 ; int fShowAllMacros: 1 ;
int : 1 ; /* spare */ int : 1 ; /* spare */
/* used in customize dialog */ /* used in customize dialog */
int iAS: 2; /* Auto Save frequency index. */ unsigned int iAS: 2; /* Auto Save frequency index (0..3). */
int fDraftView: 1; int fDraftView: 1;
int fZoomApp: 1; int fZoomApp: 1;
+230 -9
View File
@@ -316,8 +316,13 @@ extern HWND vhwndCBT;
extern int vcxtHelp; /* help context id */ extern int vcxtHelp; /* help context id */
extern BOOL vfHelp; /* whether we're in Help Mode */ extern BOOL vfHelp; /* whether we're in Help Mode */
extern long vcmsecHelp; extern long vcmsecHelp;
#ifdef OPUS_X64
extern WPARAM vwParamHelp;
extern LPARAM vlParamHelp;
#else
extern WORD vwParamHelp; extern WORD vwParamHelp;
extern LONG vlParamHelp; extern LONG vlParamHelp;
#endif
extern HCURSOR vhcHourGlass; extern HCURSOR vhcHourGlass;
extern HCURSOR vhcIBeam; extern HCURSOR vhcIBeam;
extern HCURSOR vhcArrow; extern HCURSOR vhcArrow;
@@ -390,7 +395,25 @@ extern int vfNoInval;
void MwdVertScroll( int, WORD, int ); void MwdVertScroll( int, WORD, int );
void MwdHorzScroll( int, WORD, int ); void MwdHorzScroll( int, WORD, int );
void WwPaneMouse( int, unsigned, WORD, POINT ); void WwPaneMouse( int, unsigned, WORD, POINT );
#ifdef OPUS_X64
LRESULT LMenuChar(HWND, WPARAM, LPARAM);
void DrawMenuHelp(HMENU, UINT_PTR, int);
void SaveMenuHelpContext(WPARAM, LPARAM, int);
/*
* Opus used the sign bit of a Win16 WORD-sized int to distinguish its
* command ids from the SC_* values in WM_SYSCOMMAND. A Win64 int is 32
* bits, so casting WPARAM to int makes every SC_* value positive and causes
* Word to swallow window move/size/close commands as application commands.
*/
#define FOpusCommandWParam(wParam) ((short) LOWORD(wParam) >= 0)
#define BcmFromWParam(wParam) ((WORD) LOWORD(wParam))
#define WM_OPUS_X64_QUERY_SELECTION (WM_APP + 0x351)
#else
LONG LMenuChar(HWND, WORD, LONG); LONG LMenuChar(HWND, WORD, LONG);
#define FOpusCommandWParam(wParam) ((int) (wParam) >= 0)
#define BcmFromWParam(wParam) (wParam)
#endif
#ifdef DEBUG #ifdef DEBUG
@@ -750,12 +773,21 @@ LONG lParam;
{ {
static int fEnteredIdle=fTrue; static int fEnteredIdle=fTrue;
static HMENU hMenu; static HMENU hMenu;
#ifdef OPUS_X64
static UINT_PTR bcm;
#else
static int bcm; static int bcm;
#endif
static int mf; static int mf;
int cxt; int cxt;
#ifdef OPUS_X64
LRESULT AppWndProcRare(HWND, UINT, WPARAM, LPARAM);
LRESULT AppWndProcAct(HWND, UINT, WPARAM, LPARAM);
#else
long AppWndProcRare(); long AppWndProcRare();
long AppWndProcAct(); long AppWndProcAct();
#endif
struct RC rc; struct RC rc;
@@ -799,7 +831,7 @@ LONG lParam;
/* CBT hook must be the first thing we do under WM_COMMAND */ /* CBT hook must be the first thing we do under WM_COMMAND */
if (vhwndCBT && !SendMessage(vhwndCBT, WM_CBTSEMEV, smvCommand, if (vhwndCBT && !SendMessage(vhwndCBT, WM_CBTSEMEV, smvCommand,
MAKELONG(CxtFromBcm(wParam), 0 /* from menu */))) MAKELONG(CxtFromBcm(BcmFromWParam(wParam)), 0 /* from menu */)))
{ {
return (0L); return (0L);
} }
@@ -813,12 +845,12 @@ LONG lParam;
RestorePrompt(); RestorePrompt();
if (wParam == bcmNil) /* menu empty */ if (BcmFromWParam(wParam) == bcmNil) /* menu empty */
return (0L); return (0L);
Assert((int) wParam >= 0); Assert(FOpusCommandWParam(wParam));
vcxtHelp = cxtNil; vcxtHelp = cxtNil;
FExecCmd(wParam); FExecCmd(BcmFromWParam(wParam));
break; break;
case WM_SYSCOMMAND: case WM_SYSCOMMAND:
@@ -887,9 +919,9 @@ LONG lParam;
Profile(vpfi == pfiMenu ? StartProf(30) : 0); Profile(vpfi == pfiMenu ? StartProf(30) : 0);
EnsureFocusInPane(); EnsureFocusInPane();
vcxtHelp = cxtNil; vcxtHelp = cxtNil;
if ((int) wParam >= 0) if (FOpusCommandWParam(wParam))
{ {
CmdExecBcmKc(wParam, kcNil); CmdExecBcmKc(BcmFromWParam(wParam), kcNil);
} }
else else
{ {
@@ -955,9 +987,17 @@ LDefProc:
if (vhwndStatLine) if (vhwndStatLine)
{ {
#ifdef OPUS_X64
hMenu = (HMENU) lParam;
mf = HIWORD(wParam);
bcm = (mf & MF_POPUP) && hMenu != NULL ?
(UINT_PTR) GetSubMenu(hMenu, LOWORD(wParam)) :
(UINT_PTR) LOWORD(wParam);
#else
hMenu = HIWORD(lParam); hMenu = HIWORD(lParam);
bcm = wParam; bcm = wParam;
mf = LOWORD(lParam ); mf = LOWORD(lParam );
#endif
if (hMenu == 0 && fEnteredIdle) if (hMenu == 0 && fEnteredIdle)
DrawMenuHelp(hMenu, bcm, mf); DrawMenuHelp(hMenu, bcm, mf);
fEnteredIdle = fFalse; fEnteredIdle = fFalse;
@@ -1026,9 +1066,17 @@ LONG lParam;
extern int mwCreate; extern int mwCreate;
static int fEnteredIdle=fTrue; static int fEnteredIdle=fTrue;
static HMENU hMenu; static HMENU hMenu;
#ifdef OPUS_X64
static UINT_PTR bcm;
#else
static int bcm; static int bcm;
#endif
static int mf; static int mf;
#ifdef OPUS_X64
LRESULT MwdWndProcRare(HWND, UINT, WPARAM, LPARAM);
#else
long MwdWndProcRare(); long MwdWndProcRare();
#endif
int ww; int ww;
PAINTSTRUCT ps; PAINTSTRUCT ps;
@@ -1065,6 +1113,21 @@ LONG lParam;
SetUatMode(uamNavigation); SetUatMode(uamNavigation);
StopUatTimer(); StopUatTimer();
#endif /* RSH */ #endif /* RSH */
#ifdef OPUS_X64
{
WORD code = LOWORD(wParam);
int dqThumb = HIWORD(wParam);
HWND hwndScroll = (HWND) lParam;
if (message == WM_HSCROLL)
MwdHorzScroll(wwCur, code, dqThumb);
else
MwdVertScroll(((*hwwdCur)->hwndVScroll == hwndScroll) ?
wwCur : WwOther(wwCur), code, dqThumb);
if (vfRecording)
RecordScroll(message, code, dqThumb);
}
#else
if (message == WM_HSCROLL) if (message == WM_HSCROLL)
MwdHorzScroll( wwCur, wParam, (int)lParam); MwdHorzScroll( wwCur, wParam, (int)lParam);
else else
@@ -1072,11 +1135,17 @@ LONG lParam;
wwCur : WwOther(wwCur), wParam, (int)lParam); wwCur : WwOther(wwCur), wParam, (int)lParam);
if (vfRecording) if (vfRecording)
RecordScroll(message, wParam, LOWORD(lParam)); RecordScroll(message, wParam, LOWORD(lParam));
#endif
break; break;
case WM_MOUSEACTIVATE: case WM_MOUSEACTIVATE:
{ {
int iRet = 0; int iRet =
#ifdef OPUS_X64
MA_ACTIVATE;
#else
0;
#endif
if (vhwndAppModalFocus != hNil) if (vhwndAppModalFocus != hNil)
if (!vfDeactByOtherApp) if (!vfDeactByOtherApp)
@@ -1115,7 +1184,14 @@ LONG lParam;
NewCurWw( PmwdMw(MwFromHwndMw(hwnd))->wwActive, fFalse /*fDoNotSelect*/); NewCurWw( PmwdMw(MwFromHwndMw(hwnd))->wwActive, fFalse /*fDoNotSelect*/);
/* fall through */ /* fall through */
default: default:
#ifdef OPUS_X64
/* Modern USER can activate and deliver this click without the
* Win16 re-entrancy workaround. Eating it makes the first click
* after switching documents disappear. */
iRet = MA_ACTIVATE;
#else
iRet = MA_ACTIVATEANDEAT; iRet = MA_ACTIVATEANDEAT;
#endif
break; break;
} }
} }
@@ -1189,8 +1265,8 @@ LONG lParam;
EnsureFocusInPane(); EnsureFocusInPane();
if ((int) wParam >= 0) if (FOpusCommandWParam(wParam))
return CmdExecBcmKc(wParam, kcNil) == cmdOK; return CmdExecBcmKc(BcmFromWParam(wParam), kcNil) == cmdOK;
switch (wParam & 0xfff0) switch (wParam & 0xfff0)
{ {
@@ -1229,9 +1305,17 @@ LONG lParam;
if (vhwndStatLine) if (vhwndStatLine)
{ {
#ifdef OPUS_X64
hMenu = (HMENU) lParam;
mf = HIWORD(wParam);
bcm = (mf & MF_POPUP) && hMenu != NULL ?
(UINT_PTR) GetSubMenu(hMenu, LOWORD(wParam)) :
(UINT_PTR) LOWORD(wParam);
#else
hMenu = HIWORD(lParam); hMenu = HIWORD(lParam);
bcm = wParam; bcm = wParam;
mf = LOWORD(lParam ); mf = LOWORD(lParam );
#endif
if (hMenu == 0 && fEnteredIdle) if (hMenu == 0 && fEnteredIdle)
DrawMenuHelp(hMenu, bcm, mf); DrawMenuHelp(hMenu, bcm, mf);
fEnteredIdle = fFalse; fEnteredIdle = fFalse;
@@ -1278,15 +1362,23 @@ DefaultProc: /* All messages not processed come here. */
else, we can compute the context from these saved values. else, we can compute the context from these saved values.
*/ */
/* %%Function:SaveMenuHelpContext %%Owner:rosiep */ /* %%Function:SaveMenuHelpContext %%Owner:rosiep */
#ifdef OPUS_X64
void SaveMenuHelpContext(WPARAM wParam, LPARAM lParam, int cxt)
#else
SaveMenuHelpContext(wParam,lParam,cxt) SaveMenuHelpContext(wParam,lParam,cxt)
WORD wParam; WORD wParam;
LONG lParam; LONG lParam;
int cxt; int cxt;
#endif
{ {
Assert(cxt == cxtAppMenuSelect || cxt == cxtDocMenuSelect); Assert(cxt == cxtAppMenuSelect || cxt == cxtDocMenuSelect);
/* if we're exiting Menu Mode, no more help context */ /* if we're exiting Menu Mode, no more help context */
#ifdef OPUS_X64
if (lParam == 0 && HIWORD(wParam) == 0xffff)
#else
if (HIWORD(lParam) == 0 || wParam == 0) if (HIWORD(lParam) == 0 || wParam == 0)
#endif
{ {
vwParamHelp = 0; vwParamHelp = 0;
vlParamHelp = 0; vlParamHelp = 0;
@@ -1380,7 +1472,11 @@ LONG lParam;
{ {
int ww; int ww;
struct RC rc; struct RC rc;
#ifdef OPUS_X64
LRESULT RareWwPaneWndProc(HWND, UINT, WPARAM, LPARAM);
#else
long RareWwPaneWndProc(); long RareWwPaneWndProc();
#endif
#ifdef SHOWPNEMSG #ifdef SHOWPNEMSG
ShowMsg ("pn", hwnd, message, wParam, lParam); ShowMsg ("pn", hwnd, message, wParam, lParam);
@@ -1400,6 +1496,104 @@ LONG lParam;
default: default:
return RareWwPaneWndProc( hwnd, message, wParam,lParam ); return RareWwPaneWndProc( hwnd, message, wParam,lParam );
#ifdef OPUS_X64
case WM_OPUS_X64_QUERY_SELECTION:
switch (LOWORD(wParam))
{
case 0: return (LRESULT) selCur.cpFirst;
case 1: return (LRESULT) selCur.cpLim;
case 2: return (LRESULT) selCur.fIns;
case 3: return (LRESULT) selCur.sty;
case 4: return (LRESULT) selCur.xw;
case 5: return (LRESULT) vfDoubleClick;
case 6: return (LRESULT) selCur.sk;
case 7: return (LRESULT) selCur.yw;
case 8: return (LRESULT) selCur.dyp;
case 9: return (LRESULT) selCur.fOn;
case 10: return (LRESULT) selCur.fHidden;
case 11: return (LRESULT) selCur.xpFirst;
case 12: return (LRESULT) selCur.xpLim;
case 13: return (LRESULT) vfli.cpMin;
case 14: return (LRESULT) vfli.cpMac;
case 15: return (LRESULT) vfli.xpLeft;
case 16: return (LRESULT) vfli.xpRight;
case 17: return (LRESULT) vfli.ichMac;
case 18: return (LRESULT) vfli.rgdxp[0];
case 19: return (LRESULT) vfli.rgdxp[
vfli.ichMac == 0 ? 0 : vfli.ichMac - 1];
case 24: return (LRESULT) sizeof(struct CHR);
case 25: return (LRESULT) sizeof(struct CHRT);
case 26: return (LRESULT) sizeof(struct CHRV);
case 27: return (LRESULT) sizeof(struct CHRF);
case 28: return (LRESULT) sizeof(struct CHRDF);
case 29: return (LRESULT) sizeof(struct CHRFG);
case 30:
{
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
return (LRESULT) IMacPlc(pdr->hplcedl);
}
case 31:
{
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
return (LRESULT) CpPlc(pdr->hplcedl, (int) lParam);
}
case 32:
case 33:
case 34:
case 35:
{
struct EDL edl;
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
GetPlc(pdr->hplcedl, (int) lParam, &edl);
if (LOWORD(wParam) == 32) return (LRESULT) edl.ypTop;
if (LOWORD(wParam) == 33) return (LRESULT) edl.dyp;
if (LOWORD(wParam) == 34) return (LRESULT) edl.dcp;
return (LRESULT) edl.fDirty;
}
case 36:
case 37:
{
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
return LOWORD(wParam) == 36 ?
(LRESULT) pdr->cpFirst : (LRESULT) pdr->cpLim;
}
case 38: return (LRESULT) sizeof(struct EDL);
case 39:
{
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
return (LRESULT) pdr->fDirty;
}
case 40:
return (LRESULT) PwwdWw(WwFromHwnd(hwnd))->fDirty;
case 41: return (LRESULT) CpMacDocEdit(selCur.doc);
case 42:
{
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
return (LRESULT) pdr->dyl;
}
case 43:
return (LRESULT) DyOfRc(&PwwdWw(WwFromHwnd(hwnd))->rcwDisp);
case 44:
{
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
return (LRESULT) pdr->dxl;
}
case 45:
return (LRESULT) DxOfRc(&PwwdWw(WwFromHwnd(hwnd))->rcwDisp);
case 46: return (LRESULT) CpMacDoc(selCur.doc);
case 47:
case 48:
{
struct EDL edl;
struct DR *pdr = PdrGalley(PwwdWw(WwFromHwnd(hwnd)));
GetPlc(pdr->hplcedl, (int) lParam, &edl);
return LOWORD(wParam) == 47 ?
(LRESULT) edl.dlk : (LRESULT) edl.fEnd;
}
}
return (LRESULT) -1;
#endif
case WM_SETFOCUS: case WM_SETFOCUS:
/* The window is getting the focus. wParam contains the window /* The window is getting the focus. wParam contains the window
** handle of the window that previously had the focus. */ ** handle of the window that previously had the focus. */
@@ -1483,7 +1677,14 @@ LONG lParam;
} }
else else
{ {
#ifdef OPUS_X64
/* The Win16 eat-on-activate workaround makes the next
* physical click look like a double-click on modern USER.
* Let the activating click position the caret immediately. */
return(MA_ACTIVATE);
#else
return(MA_ACTIVATEANDEAT); return(MA_ACTIVATEANDEAT);
#endif
} }
} }
DefaultProc: /* All messages not processed come here. */ DefaultProc: /* All messages not processed come here. */
@@ -2816,15 +3017,24 @@ lblSet:
by the window proc receiving the message. by the window proc receiving the message.
*/ */
/* %%Function:LMenuChar %%Owner:peterj */ /* %%Function:LMenuChar %%Owner:peterj */
#ifdef OPUS_X64
LRESULT LMenuChar(HWND hwnd, WPARAM wParam, LPARAM lParam)
#else
LONG LMenuChar(hwnd, wParam, lParam) LONG LMenuChar(hwnd, wParam, lParam)
HWND hwnd; HWND hwnd;
WORD wParam; WORD wParam;
LONG lParam; LONG lParam;
#endif
{ {
if (vhwndAppModalFocus != NULL) if (vhwndAppModalFocus != NULL)
return MAKELONG(0, 1); return MAKELONG(0, 1);
#ifdef OPUS_X64
if (LOWORD(wParam) == '-' && !(HIWORD(wParam) & MF_POPUP) &&
hwwdCur != hNil)
#else
if (wParam == '-' && !(LOWORD(lParam) & MF_POPUP) && hwwdCur != hNil) if (wParam == '-' && !(LOWORD(lParam) & MF_POPUP) && hwwdCur != hNil)
#endif
{ {
if (vfSysMenu) if (vfSysMenu)
{ {
@@ -3181,7 +3391,18 @@ BOOL fRightButton;
} }
} }
#ifdef OPUS_X64
/*
* The Win16 loop could rely on GetKeyState's queue snapshot while nested
* inside the button-down dispatch. On modern Windows that snapshot can
* lag the physical/SENDINPUT transition and prematurely end a drag before
* the corresponding button-up reaches this replay loop.
*/
return ((GetAsyncKeyState(fRightButton ? VK_RBUTTON : VK_LBUTTON) &
0x8000) != 0);
#else
return (GetKeyState( fRightButton ? VK_RBUTTON : VK_LBUTTON ) < 0); return (GetKeyState( fRightButton ? VK_RBUTTON : VK_LBUTTON ) < 0);
#endif
} }
+4
View File
@@ -133,11 +133,15 @@ extern int vfTableKeymap;
/* %%Function:AppWndProcAct %%Owner:chic */ /* %%Function:AppWndProcAct %%Owner:chic */
#ifdef OPUS_X64
LRESULT AppWndProcAct(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
#else
long AppWndProcAct(hwnd, message, wParam, lParam) long AppWndProcAct(hwnd, message, wParam, lParam)
HWND hwnd; HWND hwnd;
unsigned message; unsigned message;
WORD wParam; WORD wParam;
LONG lParam; LONG lParam;
#endif
{ {
switch (message) switch (message)
+18
View File
@@ -131,11 +131,15 @@ HWND vhwndZoom = hNil;
/* %%Function:MwdWndProcRare %%Owner:chic */ /* %%Function:MwdWndProcRare %%Owner:chic */
#ifdef OPUS_X64
LRESULT MwdWndProcRare(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
#else
long MwdWndProcRare(hwnd, message, wParam, lParam) long MwdWndProcRare(hwnd, message, wParam, lParam)
HWND hwnd; HWND hwnd;
int message; int message;
WORD wParam; WORD wParam;
LONG lParam; LONG lParam;
#endif
{ {
extern int mwCreate; extern int mwCreate;
@@ -169,12 +173,21 @@ LONG lParam;
{ {
struct MWD *pmwd = PmwdMw(mw); struct MWD *pmwd = PmwdMw(mw);
#ifdef OPUS_X64
pmwd->xp = (short) LOWORD(lParam);
pmwd->yp = (short) HIWORD(lParam);
#else
pmwd->xp = LOWORD(lParam); pmwd->xp = LOWORD(lParam);
pmwd->yp = HIWORD(lParam); pmwd->yp = HIWORD(lParam);
#endif
/* the dimensions are recorded in the size message */ /* the dimensions are recorded in the size message */
if (vfRecording && fRecordMove) if (vfRecording && fRecordMove)
#ifdef OPUS_X64
RecordDocMove((short) LOWORD(lParam), (short) HIWORD(lParam));
#else
RecordDocMove(LOWORD(lParam), HIWORD(lParam)); RecordDocMove(LOWORD(lParam), HIWORD(lParam));
#endif
fRecordMove = fFalse; fRecordMove = fFalse;
} }
break; break;
@@ -214,11 +227,16 @@ LONG lParam;
/* %%Function:RareWwPaneWndProc %%Owner:chic */ /* %%Function:RareWwPaneWndProc %%Owner:chic */
#ifdef OPUS_X64
LRESULT RareWwPaneWndProc(HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam)
#else
long RareWwPaneWndProc(hwnd, message, wParam, lParam) long RareWwPaneWndProc(hwnd, message, wParam, lParam)
HWND hwnd; HWND hwnd;
int message; int message;
WORD wParam; WORD wParam;
LONG lParam; LONG lParam;
#endif
{ {
int ww; int ww;
struct WWD *pwwd; struct WWD *pwwd;
-240
View File
@@ -1,240 +0,0 @@
#include "legacy_asm_port.h"
#include <Windows.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <cstring>
#include <limits>
#include <stdexcept>
namespace opus::x64 {
namespace {
enum class PortKind : std::uint8_t {
translated_cpp,
portable_c_counterpart,
win32_replacement,
retired_platform_code,
};
struct AssemblyPortEntry {
std::string_view path;
PortKind kind;
};
// One entry per .asm file under src. This table is intentionally explicit:
// adding an assembly module makes CMake fail until its x64 disposition is
// reviewed. "portable_c_counterpart" means the hand-written assembly was an
// optimized version of an extant C implementation in Opus/wordtech.
constexpr std::array kAssemblyPorts{
AssemblyPortEntry{"Opus/asm/asserth.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"Opus/asm/auxout.asm", PortKind::win32_replacement},
AssemblyPortEntry{"Opus/asm/clsplcn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/cmdlookn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/dialog1n.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/disp1n.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/disp1n2.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/disp2n.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/disp3n.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/disptbln.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/disptbn2.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/editn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/editn2.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/eldden.asm", PortKind::win32_replacement},
AssemblyPortEntry{"Opus/asm/expn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fetch2n.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fetchn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fetchn2.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fetchn3.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fetchtbn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fieldcrn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fieldfmn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/fieldspn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/file2n.asm", PortKind::win32_replacement},
AssemblyPortEntry{"Opus/asm/filewinn.asm", PortKind::win32_replacement},
AssemblyPortEntry{"Opus/asm/formatn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/formatn2.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/formulan.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/grbitx.asm", PortKind::translated_cpp},
AssemblyPortEntry{"Opus/asm/grhc.asm", PortKind::translated_cpp},
AssemblyPortEntry{"Opus/asm/index2n.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/inssubsn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/int3f.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"Opus/asm/layout22.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/layout2n.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/movecmds.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"Opus/asm/natinit.asm", PortKind::translated_cpp},
AssemblyPortEntry{"Opus/asm/nattrans.asm", PortKind::translated_cpp},
AssemblyPortEntry{"Opus/asm/prln.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/profc.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"Opus/asm/profctl.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"Opus/asm/promptn.asm", PortKind::win32_replacement},
AssemblyPortEntry{"Opus/asm/qplc.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"Opus/asm/resn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/resn2.asm", PortKind::translated_cpp},
AssemblyPortEntry{"Opus/asm/rip.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"Opus/asm/rtfinn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/rtfsubsn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/searchn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/sttbn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/wordgrep.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"Opus/asm/wprocn.asm", PortKind::win32_replacement},
AssemblyPortEntry{"OpusEtAl/tools/src/appstub.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"OpusEtAl/tools/src/convtest/doslib.asm", PortKind::win32_replacement},
AssemblyPortEntry{"OpusEtAl/tools/src/convtest/init.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"OpusEtAl/tools/src/makekeyn.asm", PortKind::portable_c_counterpart},
AssemblyPortEntry{"OpusEtAl/tools/src/timedate.asm", PortKind::translated_cpp},
AssemblyPortEntry{"OpusEtAl/tools/src/winemscs.asm", PortKind::retired_platform_code},
AssemblyPortEntry{"OpusEtAl/tools/src/winemsds.asm", PortKind::retired_platform_code},
};
static_assert(kAssemblyPorts.size() == 59);
} // namespace
std::int32_t multiply_divide(const std::int32_t value,
const std::int32_t numerator,
const std::int32_t denominator) noexcept {
if (denominator == 0) {
const bool negative = (value < 0) != (numerator < 0);
return negative ? std::numeric_limits<std::int32_t>::min()
: std::numeric_limits<std::int32_t>::max();
}
const auto result = (static_cast<std::int64_t>(value) * numerator) / denominator;
return static_cast<std::int32_t>(std::clamp<std::int64_t>(
result, std::numeric_limits<std::int32_t>::min(),
std::numeric_limits<std::int32_t>::max()));
}
std::uint32_t unsigned_multiply_divide(const std::uint32_t value,
const std::uint32_t numerator,
const std::uint32_t denominator) noexcept {
if (denominator == 0) {
return std::numeric_limits<std::uint32_t>::max();
}
const auto result = (static_cast<std::uint64_t>(value) * numerator) / denominator;
return static_cast<std::uint32_t>(std::min<std::uint64_t>(
result, std::numeric_limits<std::uint32_t>::max()));
}
double legacy_log(const double value) noexcept { return std::log(value); }
double legacy_exp(const double value) noexcept { return std::exp(value); }
double legacy_sqrt(const double value) noexcept { return std::sqrt(value); }
double legacy_square(const double value) noexcept { return value * value; }
void fill_byte_pattern(void* destination, const std::size_t byte_count,
const void* pattern, const std::size_t pattern_size) {
if (byte_count == 0) {
return;
}
if (destination == nullptr || pattern == nullptr || pattern_size == 0) {
throw std::invalid_argument("fill_byte_pattern received an invalid buffer");
}
auto* output = static_cast<std::byte*>(destination);
const auto* input = static_cast<const std::byte*>(pattern);
for (std::size_t offset = 0; offset < byte_count; ++offset) {
output[offset] = input[offset % pattern_size];
}
}
bool buffers_differ(const void* left, const void* right,
const std::size_t byte_count) noexcept {
if (byte_count == 0) {
return false;
}
if (left == nullptr || right == nullptr) {
return true;
}
return std::memcmp(left, right, byte_count) != 0;
}
std::size_t zero_terminated_length(const char* text) noexcept {
return text == nullptr ? 0 : std::strlen(text);
}
std::size_t copy_zero_terminated(char* destination,
const std::size_t destination_size,
const char* source) noexcept {
if (destination == nullptr || destination_size == 0) {
return 0;
}
if (source == nullptr) {
destination[0] = '\0';
return 0;
}
const auto count = std::min(destination_size - 1, std::strlen(source));
std::memcpy(destination, source, count);
destination[count] = '\0';
return count;
}
bool is_ascii_alpha(const std::uint8_t value) noexcept {
const auto upper = ascii_upper(value);
return upper >= 'A' && upper <= 'Z';
}
bool is_ascii_digit(const std::uint8_t value) noexcept {
return value >= '0' && value <= '9';
}
bool is_ascii_alphanumeric(const std::uint8_t value) noexcept {
return is_ascii_alpha(value) || is_ascii_digit(value);
}
std::uint8_t ascii_upper(const std::uint8_t value) noexcept {
return value >= 'a' && value <= 'z' ? static_cast<std::uint8_t>(value - ('a' - 'A'))
: value;
}
LegacyTime local_time() noexcept {
SYSTEMTIME value{};
GetLocalTime(&value);
return {value.wHour, value.wMinute, value.wSecond,
static_cast<std::uint16_t>(value.wMilliseconds / 10)};
}
LegacyDate local_date() noexcept {
SYSTEMTIME value{};
GetLocalTime(&value);
return {value.wYear, value.wMonth, value.wDay, value.wDayOfWeek};
}
std::uint64_t available_disk_bytes(const std::wstring_view path) noexcept {
ULARGE_INTEGER available{};
const std::wstring owned_path(path);
if (!GetDiskFreeSpaceExW(owned_path.c_str(), &available, nullptr, nullptr)) {
return 0;
}
return available.QuadPart;
}
bool is_remote_path(const std::wstring_view path) noexcept {
if (path.starts_with(L"\\\\")) {
return true;
}
if (path.size() < 2 || path[1] != L':') {
return false;
}
wchar_t root[] = {path[0], L':', L'\\', L'\0'};
return GetDriveTypeW(root) == DRIVE_REMOTE;
}
bool assembly_manifest_complete() noexcept {
for (std::size_t left = 0; left < kAssemblyPorts.size(); ++left) {
if (kAssemblyPorts[left].path.empty()) {
return false;
}
for (std::size_t right = left + 1; right < kAssemblyPorts.size(); ++right) {
if (kAssemblyPorts[left].path == kAssemblyPorts[right].path) {
return false;
}
}
}
return true;
}
std::size_t assembly_manifest_count() noexcept { return kAssemblyPorts.size(); }
} // namespace opus::x64
-63
View File
@@ -1,63 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
namespace opus::x64 {
// Fixed-width replacements for assembly primitives that are still useful to
// the native port. Higher-level Opus routines are replaced by the portable C
// algorithms in Opus/wordtech as that document engine is migrated.
struct LegacyTime {
std::uint16_t hour{};
std::uint16_t minute{};
std::uint16_t second{};
std::uint16_t hundredths{};
};
struct LegacyDate {
std::uint16_t year{};
std::uint16_t month{};
std::uint16_t day{};
std::uint16_t day_of_week{};
};
[[nodiscard]] std::int32_t multiply_divide(std::int32_t value,
std::int32_t numerator,
std::int32_t denominator) noexcept;
[[nodiscard]] std::uint32_t unsigned_multiply_divide(std::uint32_t value,
std::uint32_t numerator,
std::uint32_t denominator) noexcept;
[[nodiscard]] double legacy_log(double value) noexcept;
[[nodiscard]] double legacy_exp(double value) noexcept;
[[nodiscard]] double legacy_sqrt(double value) noexcept;
[[nodiscard]] double legacy_square(double value) noexcept;
void fill_byte_pattern(void* destination, std::size_t byte_count,
const void* pattern, std::size_t pattern_size);
[[nodiscard]] bool buffers_differ(const void* left, const void* right,
std::size_t byte_count) noexcept;
[[nodiscard]] std::size_t zero_terminated_length(const char* text) noexcept;
[[nodiscard]] std::size_t copy_zero_terminated(char* destination,
std::size_t destination_size,
const char* source) noexcept;
[[nodiscard]] bool is_ascii_alpha(std::uint8_t value) noexcept;
[[nodiscard]] bool is_ascii_digit(std::uint8_t value) noexcept;
[[nodiscard]] bool is_ascii_alphanumeric(std::uint8_t value) noexcept;
[[nodiscard]] std::uint8_t ascii_upper(std::uint8_t value) noexcept;
[[nodiscard]] LegacyTime local_time() noexcept;
[[nodiscard]] LegacyDate local_date() noexcept;
[[nodiscard]] std::uint64_t available_disk_bytes(std::wstring_view path) noexcept;
[[nodiscard]] bool is_remote_path(std::wstring_view path) noexcept;
// Returns true only if the checked-in migration table accounts for every
// legacy .asm module. This is also run during application startup.
[[nodiscard]] bool assembly_manifest_complete() noexcept;
[[nodiscard]] std::size_t assembly_manifest_count() noexcept;
} // namespace opus::x64
+1
View File
@@ -4,6 +4,7 @@
typedef struct _CABABOUT typedef struct _CABABOUT
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszAboutApp; CHAR **hszAboutApp;
CHAR **hszAboutVersion; CHAR **hszAboutVersion;
CHAR **hszAboutCopyright; CHAR **hszAboutCopyright;
-2
View File
@@ -13,7 +13,6 @@
#define tmcUnassignKey (tmcUserMin + 9) #define tmcUnassignKey (tmcUserMin + 9)
#define tmcDescKey (tmcUserMin + 10) #define tmcDescKey (tmcUserMin + 10)
#pragma pack(push, 2)
typedef struct _CABCHANGEKEYS typedef struct _CABCHANGEKEYS
{ {
CABH cabh; CABH cabh;
@@ -22,7 +21,6 @@ typedef struct _CABCHANGEKEYS
unsigned uKeyList; unsigned uKeyList;
int iContext; int iContext;
} CABCHANGEKEYS; } CABCHANGEKEYS;
#pragma pack(pop)
typedef CABCHANGEKEYS **HCABCHANGEKEYS; typedef CABCHANGEKEYS **HCABCHANGEKEYS;
#define cabiCABCHANGEKEYS Cabi((sizeof(CABCHANGEKEYS) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABCHANGEKEYS Cabi((sizeof(CABCHANGEKEYS) + sizeof(WORD) - 1) / sizeof(WORD), 1)
-2
View File
@@ -13,7 +13,6 @@
#define tmcResetMenu (tmcUserMin + 9) #define tmcResetMenu (tmcUserMin + 9)
#define tmcDescMenu (tmcUserMin + 10) #define tmcDescMenu (tmcUserMin + 10)
#pragma pack(push, 2)
typedef struct _CABASSIGNTOMENU typedef struct _CABASSIGNTOMENU
{ {
CABH cabh; CABH cabh;
@@ -23,7 +22,6 @@ typedef struct _CABASSIGNTOMENU
CHAR **hszTitle; CHAR **hszTitle;
int iContext; int iContext;
} CABASSIGNTOMENU; } CABASSIGNTOMENU;
#pragma pack(pop)
typedef CABASSIGNTOMENU **HCABASSIGNTOMENU; typedef CABASSIGNTOMENU **HCABASSIGNTOMENU;
#define cabiCABASSIGNTOMENU Cabi((sizeof(CABASSIGNTOMENU) + sizeof(WORD) - 1) / sizeof(WORD), 3) #define cabiCABASSIGNTOMENU Cabi((sizeof(CABASSIGNTOMENU) + sizeof(WORD) - 1) / sizeof(WORD), 3)
+1
View File
@@ -7,6 +7,7 @@
typedef struct _CABINSBOOKMARK typedef struct _CABINSBOOKMARK
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszBkmkName; CHAR **hszBkmkName;
} CABINSBOOKMARK; } CABINSBOOKMARK;
-2
View File
@@ -13,7 +13,6 @@
#define tmcCatDelete (tmcUserMin + 7) #define tmcCatDelete (tmcUserMin + 7)
#define tmcCatSummary (tmcUserMin + 8) #define tmcCatSummary (tmcUserMin + 8)
#pragma pack(push, 2)
typedef struct _CABCATALOG typedef struct _CABCATALOG
{ {
CABH cabh; CABH cabh;
@@ -34,7 +33,6 @@ typedef struct _CABCATALOG
BOOL fCatSrhMatchCase; BOOL fCatSrhMatchCase;
BOOL fCatSrhRedo; BOOL fCatSrhRedo;
} CABCATALOG; } CABCATALOG;
#pragma pack(pop)
typedef CABCATALOG **HCABCATALOG; typedef CABCATALOG **HCABCATALOG;
#define cabiCABCATALOG Cabi((sizeof(CABCATALOG) + sizeof(WORD) - 1) / sizeof(WORD), 8) #define cabiCABCATALOG Cabi((sizeof(CABCATALOG) + sizeof(WORD) - 1) / sizeof(WORD), 8)
-2
View File
@@ -6,13 +6,11 @@
#define tmcCatSrhSearched (tmcUserMin + 2) #define tmcCatSrhSearched (tmcUserMin + 2)
#define tmcCatSrhFileInUse (tmcUserMin + 3) #define tmcCatSrhFileInUse (tmcUserMin + 3)
#pragma pack(push, 2)
typedef struct _CABCATSRHPROG typedef struct _CABCATSRHPROG
{ {
CABH cabh; CABH cabh;
WORD sab; WORD sab;
} CABCATSRHPROG; } CABCATSRHPROG;
#pragma pack(pop)
typedef CABCATSRHPROG **HCABCATSRHPROG; typedef CABCATSRHPROG **HCABCATSRHPROG;
#define cabiCABCATSRHPROG Cabi((sizeof(CABCATSRHPROG) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABCATSRHPROG Cabi((sizeof(CABCATSRHPROG) + sizeof(WORD) - 1) / sizeof(WORD), 0)
-2
View File
@@ -15,7 +15,6 @@
#define tmcCatSrhMatchCase (tmcUserMin + 11) #define tmcCatSrhMatchCase (tmcUserMin + 11)
#define tmcCatSrhRedo (tmcUserMin + 12) #define tmcCatSrhRedo (tmcUserMin + 12)
#pragma pack(push, 2)
typedef struct _CABCATSEARCH typedef struct _CABCATSEARCH
{ {
CABH cabh; CABH cabh;
@@ -34,7 +33,6 @@ typedef struct _CABCATSEARCH
BOOL fCatSrhMatchCase; BOOL fCatSrhMatchCase;
BOOL fCatSrhRedo; BOOL fCatSrhRedo;
} CABCATSEARCH; } CABCATSEARCH;
#pragma pack(pop)
typedef CABCATSEARCH **HCABCATSEARCH; typedef CABCATSEARCH **HCABCATSEARCH;
#define cabiCABCATSEARCH Cabi((sizeof(CABCATSEARCH) + sizeof(WORD) - 1) / sizeof(WORD), 7) #define cabiCABCATSEARCH Cabi((sizeof(CABCATSEARCH) + sizeof(WORD) - 1) / sizeof(WORD), 7)
+1
View File
@@ -7,6 +7,7 @@
typedef struct _CABCHGPR typedef struct _CABCHGPR
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszLb; CHAR **hszLb;
} CABCHGPR; } CABCHGPR;
+1
View File
@@ -9,6 +9,7 @@
typedef struct _CABCONFIRMREPL typedef struct _CABCONFIRMREPL
{ {
CABH cabh; CABH cabh;
WORD sab;
BOOL fConfirm; BOOL fConfirm;
} CABCONFIRMREPL; } CABCONFIRMREPL;
+2 -2
View File
@@ -22,13 +22,13 @@ typedef struct _CABCUSTOMIZE
{ {
CABH cabh; CABH cabh;
WORD sab; WORD sab;
CHAR **hszName;
CHAR **hszInitials;
int iAS; int iAS;
int iUnit; int iUnit;
BOOL fBkgrndPag; BOOL fBkgrndPag;
BOOL fPromptSI; BOOL fPromptSI;
BOOL fAutoDelete; BOOL fAutoDelete;
CHAR **hszName;
CHAR **hszInitials;
int cBtnFldClicks; int cBtnFldClicks;
} CABCUSTOMIZE; } CABCUSTOMIZE;
+2 -1
View File
@@ -23,6 +23,8 @@
typedef struct _CABDOCUMENT typedef struct _CABDOCUMENT
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszTemplate;
unsigned uDocPageWidth; unsigned uDocPageWidth;
unsigned uDocPageHeight; unsigned uDocPageHeight;
unsigned uDocDefTabs; unsigned uDocDefTabs;
@@ -35,7 +37,6 @@ typedef struct _CABDOCUMENT
int iFN; int iFN;
int iFNStartAt; int iFNStartAt;
BOOL fFNRestart; BOOL fFNRestart;
CHAR **hszTemplate;
BOOL fWidowControl; BOOL fWidowControl;
} CABDOCUMENT; } CABDOCUMENT;
+1
View File
@@ -19,6 +19,7 @@
typedef struct _CABDOCSTAT typedef struct _CABDOCSTAT
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszFName; CHAR **hszFName;
CHAR **hszDir; CHAR **hszDir;
CHAR **hszDOT; CHAR **hszDOT;
+2 -2
View File
@@ -17,10 +17,10 @@ typedef struct _CABEDMACRO
CABH cabh; CABH cabh;
WORD sab; WORD sab;
CHAR **hszName; CHAR **hszName;
int iContext;
BOOL fShowAll;
CHAR **hszDesc; CHAR **hszDesc;
CHAR **hszNewName; CHAR **hszNewName;
int iContext;
BOOL fShowAll;
} CABEDMACRO; } CABEDMACRO;
typedef CABEDMACRO **HCABEDMACRO; typedef CABEDMACRO **HCABEDMACRO;
+1 -1
View File
@@ -26,9 +26,9 @@ typedef struct _CABDEFINESTYLE
CHAR **hszDSStyle; CHAR **hszDSStyle;
CHAR **hszDSBasedOn; CHAR **hszDSBasedOn;
CHAR **hszDSNext; CHAR **hszDSNext;
BOOL fTemplate;
CHAR **hszDSNewName; CHAR **hszDSNewName;
CHAR **hszMergeStyle; CHAR **hszMergeStyle;
BOOL fTemplate;
unsigned uSource; unsigned uSource;
} CABDEFINESTYLE; } CABDEFINESTYLE;
+1 -1
View File
@@ -11,8 +11,8 @@ typedef struct _CABINSERTFTN
{ {
CABH cabh; CABH cabh;
WORD sab; WORD sab;
BOOL fAuto;
CHAR **hstRef; CHAR **hstRef;
BOOL fAuto;
} CABINSERTFTN; } CABINSERTFTN;
typedef CABINSERTFTN **HCABINSERTFTN; typedef CABINSERTFTN **HCABINSERTFTN;
+1
View File
@@ -6,6 +6,7 @@
typedef struct _CABGOTO typedef struct _CABGOTO
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszGoto; CHAR **hszGoto;
} CABGOTO; } CABGOTO;
-2
View File
@@ -9,7 +9,6 @@
#define tmcHypChange (tmcUserMin + 5) #define tmcHypChange (tmcUserMin + 5)
#define tmcHypNoChange (tmcUserMin + 6) #define tmcHypNoChange (tmcUserMin + 6)
#pragma pack(push, 2)
typedef struct _CABHYPHEN typedef struct _CABHYPHEN
{ {
CABH cabh; CABH cabh;
@@ -18,7 +17,6 @@ typedef struct _CABHYPHEN
BOOL fHypCaps; BOOL fHypCaps;
BOOL fHypConfirm; BOOL fHypConfirm;
} CABHYPHEN; } CABHYPHEN;
#pragma pack(pop)
typedef CABHYPHEN **HCABHYPHEN; typedef CABHYPHEN **HCABHYPHEN;
#define cabiCABHYPHEN Cabi((sizeof(CABHYPHEN) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABHYPHEN Cabi((sizeof(CABHYPHEN) + sizeof(WORD) - 1) / sizeof(WORD), 1)
-2
View File
@@ -11,7 +11,6 @@
#define tmcIndexBlank (tmcUserMin + 3) #define tmcIndexBlank (tmcUserMin + 3)
#define tmcIndexLetter (tmcUserMin + 4) #define tmcIndexLetter (tmcUserMin + 4)
#pragma pack(push, 2)
typedef struct _CABINDEX typedef struct _CABINDEX
{ {
CABH cabh; CABH cabh;
@@ -20,7 +19,6 @@ typedef struct _CABINDEX
int iHeading; int iHeading;
BOOL fReplace; BOOL fReplace;
} CABINDEX; } CABINDEX;
#pragma pack(pop)
typedef CABINDEX **HCABINDEX; typedef CABINDEX **HCABINDEX;
#define cabiCABINDEX Cabi((sizeof(CABINDEX) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABINDEX Cabi((sizeof(CABINDEX) + sizeof(WORD) - 1) / sizeof(WORD), 0)
-2
View File
@@ -6,7 +6,6 @@
#define tmcXeBold (tmcUserMin + 3) #define tmcXeBold (tmcUserMin + 3)
#define tmcXeItalic (tmcUserMin + 4) #define tmcXeItalic (tmcUserMin + 4)
#pragma pack(push, 2)
typedef struct _CABINDEXENTRY typedef struct _CABINDEXENTRY
{ {
CABH cabh; CABH cabh;
@@ -16,7 +15,6 @@ typedef struct _CABINDEXENTRY
BOOL fBold; BOOL fBold;
BOOL fItalic; BOOL fItalic;
} CABINDEXENTRY; } CABINDEXENTRY;
#pragma pack(pop)
typedef CABINDEXENTRY **HCABINDEXENTRY; typedef CABINDEXENTRY **HCABINDEXENTRY;
#define cabiCABINDEXENTRY Cabi((sizeof(CABINDEXENTRY) + sizeof(WORD) - 1) / sizeof(WORD), 2) #define cabiCABINDEXENTRY Cabi((sizeof(CABINDEXENTRY) + sizeof(WORD) - 1) / sizeof(WORD), 2)
+1
View File
@@ -11,6 +11,7 @@
typedef struct _CABINSBREAK typedef struct _CABINSBREAK
{ {
CABH cabh; CABH cabh;
WORD sab;
int iType; int iType;
} CABINSBREAK; } CABINSBREAK;
-2
View File
@@ -8,7 +8,6 @@
#define tmcIFldHelp (tmcUserMin + 4) #define tmcIFldHelp (tmcUserMin + 4)
#define tmcIFldAdd (tmcUserMin + 5) #define tmcIFldAdd (tmcUserMin + 5)
#pragma pack(push, 2)
typedef struct _CABINSFIELD typedef struct _CABINSFIELD
{ {
CABH cabh; CABH cabh;
@@ -17,7 +16,6 @@ typedef struct _CABINSFIELD
unsigned uFlt; unsigned uFlt;
unsigned uInst; unsigned uInst;
} CABINSFIELD; } CABINSFIELD;
#pragma pack(pop)
typedef CABINSFIELD **HCABINSFIELD; typedef CABINSFIELD **HCABINSFIELD;
#define cabiCABINSFIELD Cabi((sizeof(CABINSFIELD) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABINSFIELD Cabi((sizeof(CABINSFIELD) + sizeof(WORD) - 1) / sizeof(WORD), 1)
+2 -1
View File
@@ -9,9 +9,10 @@
typedef struct _CABINSFILE typedef struct _CABINSFILE
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszFile; CHAR **hszFile;
int iDirectory;
CHAR **hszRange; CHAR **hszRange;
int iDirectory;
BOOL fLink; BOOL fLink;
} CABINSFILE; } CABINSFILE;
+1 -2
View File
@@ -6,14 +6,13 @@
#define tmcIPDir (tmcUserMin + 2) #define tmcIPDir (tmcUserMin + 2)
#define tmcNewPic (tmcUserMin + 3) #define tmcNewPic (tmcUserMin + 3)
#pragma pack(push, 2)
typedef struct _CABINSPIC typedef struct _CABINSPIC
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszFile; CHAR **hszFile;
int iDirectory; int iDirectory;
} CABINSPIC; } CABINSPIC;
#pragma pack(pop)
typedef CABINSPIC **HCABINSPIC; typedef CABINSPIC **HCABINSPIC;
#define cabiCABINSPIC Cabi((sizeof(CABINSPIC) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABINSPIC Cabi((sizeof(CABINSPIC) + sizeof(WORD) - 1) / sizeof(WORD), 1)
+2 -1
View File
@@ -11,8 +11,9 @@
typedef struct _CABNEWDOC typedef struct _CABNEWDOC
{ {
CABH cabh; CABH cabh;
BOOL fNewDot; WORD sab;
CHAR **hszNewType; CHAR **hszNewType;
BOOL fNewDot;
} CABNEWDOC; } CABNEWDOC;
typedef CABNEWDOC **HCABNEWDOC; typedef CABNEWDOC **HCABNEWDOC;
+6 -1
View File
@@ -1,2 +1,7 @@
#pragma once #pragma once
static DLG_CONST DLT dltNewDoc = { 0 }; /* Regenerated from Opus/dlg/new.des. */
extern BOOL FDlgNew(DLM, TMC, WORD, WORD, WORD);
static DLG_CONST DLT dltNewDoc = {
{ 20, 24, 127, 114 }, IDDNewDoc, tmcNewType, FDlgNew,
9, bdrSysMenu, { 0 }
};
+1
View File
@@ -4,6 +4,7 @@
typedef struct _CABNEWOPEN typedef struct _CABNEWOPEN
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszFileName; CHAR **hszFileName;
} CABNEWOPEN; } CABNEWOPEN;
+1
View File
@@ -10,6 +10,7 @@
typedef struct _CABOPEN typedef struct _CABOPEN
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszFile; CHAR **hszFile;
int iDirectory; int iDirectory;
BOOL fReadOnly; BOOL fReadOnly;
+6 -1
View File
@@ -1,2 +1,7 @@
#pragma once #pragma once
static DLG_CONST DLT dltOpen = { 0 }; /* Regenerated from Opus/dlg/open.des. */
extern BOOL FDlgOpen(DLM, TMC, WORD, WORD, WORD);
static DLG_CONST DLT dltOpen = {
{ 8, 24, 206, 104 }, IDDOpen, tmcOpenFileName, FDlgOpen,
11, bdrSysMenu, { 0 }
};
+2 -2
View File
@@ -88,7 +88,7 @@ int DosxError() {
error, static_cast<DWORD>((std::numeric_limits<int>::max)()))); error, static_cast<DWORD>((std::numeric_limits<int>::max)())));
} }
void* HpOfBptbExt(const int page_index) { unsigned char* HpOfBptbExt(const int page_index) {
if (vbptbExt.pages == nullptr || page_index < 0 || if (vbptbExt.pages == nullptr || page_index < 0 ||
page_index >= vbptbExt.ibp_max) { page_index >= vbptbExt.ibp_max) {
return nullptr; return nullptr;
@@ -97,7 +97,7 @@ void* HpOfBptbExt(const int page_index) {
} }
unsigned char* HpBaseForIbp(const int page_index) { unsigned char* HpBaseForIbp(const int page_index) {
return static_cast<unsigned char*>(HpOfBptbExt(page_index)); return HpOfBptbExt(page_index);
} }
void OsTime(NativeTime* time) { void OsTime(NativeTime* time) {
+3 -1
View File
@@ -50,6 +50,7 @@ constexpr UINT kWmDdeData = 0x03e5;
constexpr UINT kWmDdeRequest = 0x03e6; constexpr UINT kWmDdeRequest = 0x03e6;
constexpr UINT kWmDdePoke = 0x03e7; constexpr UINT kWmDdePoke = 0x03e7;
constexpr UINT kWmDdeExecute = 0x03e8; constexpr UINT kWmDdeExecute = 0x03e8;
constexpr UINT kWmOpusX64QuerySelection = WM_APP + 0x351;
enum class MouseCursor { none, ibeam, arrow }; enum class MouseCursor { none, ibeam, arrow };
@@ -94,7 +95,8 @@ constexpr UINT kMwdMessages[] = {
constexpr UINT kWwPaneMessages[] = { constexpr UINT kWwPaneMessages[] = {
WM_CREATE, WM_SIZE, WM_SETFOCUS, WM_KILLFOCUS, WM_PAINT, WM_CREATE, WM_SIZE, WM_SETFOCUS, WM_KILLFOCUS, WM_PAINT,
WM_MOUSEACTIVATE, WM_SETCURSOR, WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_MOUSEACTIVATE, WM_SETCURSOR, WM_MOUSEMOVE, WM_LBUTTONDOWN,
WM_LBUTTONDBLCLK, WM_RBUTTONDOWN, WM_SYSCOMMAND, WM_MENUCHAR}; WM_LBUTTONDBLCLK, WM_RBUTTONDOWN, WM_SYSCOMMAND, WM_MENUCHAR,
kWmOpusX64QuerySelection};
constexpr UINT kDdeMessages[] = { constexpr UINT kDdeMessages[] = {
kWmDdeTerminate, kWmDdeAdvise, kWmDdeUnadvise, kWmDdeAck, kWmDdeTerminate, kWmDdeAdvise, kWmDdeUnadvise, kWmDdeAck,
kWmDdeData, kWmDdeRequest, kWmDdePoke, kWmDdeExecute}; kWmDdeData, kWmDdeRequest, kWmDdePoke, kWmDdeExecute};
@@ -3,13 +3,14 @@
int main(void) int main(void)
{ {
/* Values are generated by Microsoft's original MKCMD implementation /* Values are generated by Microsoft's original MKCMD parser from
* from opuscmd.cmd and the checked-in ibcm.rel compatibility map. */ * opuscmd.cmd. On x64 these are offsets in the expanded native symbol
if (bcmCut != 1686 || bcmCopy != 1702) * table; IBCM remains the original compatibility-map index. */
if (bcmCut != 2252 || bcmCopy != 2274)
return 1; return 1;
if (ibcmEditCut != 86 || ibcmEditCopy != 87) if (ibcmEditCut != 86 || ibcmEditCopy != 87)
return 2; return 2;
if (bcmMacStd != 8295) if (bcmMacStd != 11247)
return 3; return 3;
return 0; return 0;
} }
@@ -321,6 +321,7 @@ LONG WINAPI ObserveVectoredException(EXCEPTION_POINTERS* exception) {
static volatile LONG writing_exception = 0; static volatile LONG writing_exception = 0;
if (exception != nullptr && exception->ExceptionRecord != nullptr && if (exception != nullptr && exception->ExceptionRecord != nullptr &&
(exception->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || (exception->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
exception->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO ||
exception->ExceptionRecord->ExceptionCode == 0xC0000374u || exception->ExceptionRecord->ExceptionCode == 0xC0000374u ||
exception->ExceptionRecord->ExceptionCode == 0xC0000409u || exception->ExceptionRecord->ExceptionCode == 0xC0000409u ||
exception->ExceptionRecord->ExceptionCode == 0xE0421001u) && exception->ExceptionRecord->ExceptionCode == 0xE0421001u) &&
+23 -8
View File
@@ -28,6 +28,9 @@ constexpr std::size_t kWordBytes = sizeof(Word);
constexpr std::size_t kCabMinWords = constexpr std::size_t kCabMinWords =
(sizeof(CabHeader) + sizeof(Word)) / kWordBytes; (sizeof(CabHeader) + sizeof(Word)) / kWordBytes;
constexpr std::size_t kPointerWords = sizeof(void*) / kWordBytes; constexpr std::size_t kPointerWords = sizeof(void*) / kWordBytes;
constexpr std::size_t kHandleBaseWords =
(kCabMinWords + kPointerWords - 1) / kPointerWords * kPointerWords;
constexpr std::size_t kHandleBaseIag = kHandleBaseWords - kCabMinWords;
constexpr Word kNinch = 0xffff; constexpr Word kNinch = 0xffff;
std::byte* cab_bytes(const CabHandle cab) noexcept { std::byte* cab_bytes(const CabHandle cab) noexcept {
@@ -45,8 +48,9 @@ std::size_t cab_word_count(const CabHandle cab) noexcept {
void*** handle_slot(const CabHandle cab, const Word argument_index) noexcept { void*** handle_slot(const CabHandle cab, const Word argument_index) noexcept {
auto* const header = cab_header(cab); auto* const header = cab_header(cab);
if (header == nullptr || argument_index >= header->handle_words || if (header == nullptr || argument_index < kHandleBaseIag ||
argument_index % kPointerWords != 0) { argument_index >= kHandleBaseIag + header->handle_words ||
(argument_index - kHandleBaseIag) % kPointerWords != 0) {
return nullptr; return nullptr;
} }
return reinterpret_cast<void***>( return reinterpret_cast<void***>(
@@ -58,7 +62,8 @@ void clear_cab_data(const CabHandle cab) noexcept {
if (header == nullptr) { if (header == nullptr) {
return; return;
} }
for (Word index = 0; index < header->handle_words; for (Word index = static_cast<Word>(kHandleBaseIag);
index < kHandleBaseIag + header->handle_words;
index = static_cast<Word>(index + kPointerWords)) { index = static_cast<Word>(index + kPointerWords)) {
void*** const slot = handle_slot(cab, index); void*** const slot = handle_slot(cab, index);
if (slot != nullptr && *slot != nullptr) { if (slot != nullptr && *slot != nullptr) {
@@ -77,7 +82,8 @@ bool initialize_cab(const CabHandle cab, const Word initializer) noexcept {
const std::size_t total_words = initializer & 0x00ffu; const std::size_t total_words = initializer & 0x00ffu;
const std::size_t handle_count = initializer >> 8u; const std::size_t handle_count = initializer >> 8u;
if (total_words < kCabMinWords || total_words > cab_word_count(cab) || if (total_words < kCabMinWords || total_words > cab_word_count(cab) ||
handle_count * kPointerWords > total_words - kCabMinWords) { kHandleBaseIag + handle_count * kPointerWords >
total_words - kCabMinWords) {
return false; return false;
} }
@@ -149,7 +155,7 @@ void copy_sz(const CabHandle cab, char* destination,
extern "C" { extern "C" {
CabHandle hcabDlgCur = nullptr; CabHandle hcabDlgCur = nullptr;
Word wRefDlgCur = 0; std::uintptr_t wRefDlgCur = 0;
CabHandle HcabAlloc_sdm21(const Word initializer) { CabHandle HcabAlloc_sdm21(const Word initializer) {
const std::size_t total_words = initializer & 0x00ffu; const std::size_t total_words = initializer & 0x00ffu;
@@ -193,7 +199,11 @@ void NinchCab(const CabHandle cab) {
} }
clear_cab_data(cab); clear_cab_data(cab);
auto* words = reinterpret_cast<Word*>(cab_bytes(cab)); auto* words = reinterpret_cast<Word*>(cab_bytes(cab));
for (Word index = header->handle_words; index < header->simple_words; const Word simple_first = header->handle_words == 0
? 0
: static_cast<Word>(kHandleBaseIag +
header->handle_words);
for (Word index = simple_first; index < header->simple_words;
++index) { ++index) {
words[kCabMinWords + index] = kNinch; words[kCabMinWords + index] = kNinch;
} }
@@ -312,13 +322,18 @@ CabHandle HcabDupeCab(const CabHandle source) {
auto* const destination_header = cab_header(duplicate); auto* const destination_header = cab_header(duplicate);
auto* const source_words = reinterpret_cast<const Word*>(cab_bytes(source)); auto* const source_words = reinterpret_cast<const Word*>(cab_bytes(source));
auto* const destination_words = reinterpret_cast<Word*>(cab_bytes(duplicate)); auto* const destination_words = reinterpret_cast<Word*>(cab_bytes(duplicate));
for (Word index = source_header->handle_words; const Word simple_first = source_header->handle_words == 0
? 0
: static_cast<Word>(kHandleBaseIag +
source_header->handle_words);
for (Word index = simple_first;
index < source_header->simple_words; ++index) { index < source_header->simple_words; ++index) {
destination_words[kCabMinWords + index] = destination_words[kCabMinWords + index] =
source_words[kCabMinWords + index]; source_words[kCabMinWords + index];
} }
for (Word index = 0; index < source_header->handle_words; for (Word index = static_cast<Word>(kHandleBaseIag);
index < kHandleBaseIag + source_header->handle_words;
index = static_cast<Word>(index + kPointerWords)) { index = static_cast<Word>(index + kPointerWords)) {
void*** const source_slot = handle_slot(source, index); void*** const source_slot = handle_slot(source, index);
if (source_slot != nullptr && *source_slot != nullptr && if (source_slot != nullptr && *source_slot != nullptr &&
+17 -10
View File
@@ -22,8 +22,12 @@ CabHandle HcabDupeCab(CabHandle);
constexpr Word kCabMinWords = 3; constexpr Word kCabMinWords = 3;
constexpr Word kPointerWords = sizeof(void*) / sizeof(Word); constexpr Word kPointerWords = sizeof(void*) / sizeof(Word);
constexpr Word kHandleBaseIag =
((kCabMinWords + kPointerWords - 1) / kPointerWords * kPointerWords) -
kCabMinWords;
constexpr Word kHandleCount = 2; constexpr Word kHandleCount = 2;
constexpr Word kArgumentWords = kHandleCount * kPointerWords + 2; constexpr Word kArgumentWords =
kHandleBaseIag + kHandleCount * kPointerWords + 2;
constexpr Word kTotalWords = kCabMinWords + kArgumentWords; constexpr Word kTotalWords = kCabMinWords + kArgumentWords;
constexpr Word kInitializer = kTotalWords | (kHandleCount << 8); constexpr Word kInitializer = kTotalWords | (kHandleCount << 8);
@@ -44,43 +48,46 @@ int main() {
return fail(__LINE__); return fail(__LINE__);
} }
if (!FSetCabSz(cab, "Alpha", 0)) { if (!FSetCabSz(cab, "Alpha", kHandleBaseIag)) {
return fail(__LINE__); return fail(__LINE__);
} }
const unsigned char counted[] = {4, 'B', 'e', 't', 'a'}; const unsigned char counted[] = {4, 'B', 'e', 't', 'a'};
if (!FSetCabSt(cab, counted, kPointerWords)) { if (!FSetCabSt(cab, counted, kHandleBaseIag + kPointerWords)) {
return fail(__LINE__); return fail(__LINE__);
} }
char sz[16]{}; char sz[16]{};
GetCabSz(cab, sz, sizeof(sz), 0); GetCabSz(cab, sz, sizeof(sz), kHandleBaseIag);
if (std::strcmp(sz, "Alpha") != 0) { if (std::strcmp(sz, "Alpha") != 0) {
return fail(__LINE__); return fail(__LINE__);
} }
unsigned char stz[16]{}; unsigned char stz[16]{};
GetCabStz(cab, stz, sizeof(stz), kPointerWords); GetCabStz(cab, stz, sizeof(stz), kHandleBaseIag + kPointerWords);
if (stz[0] != 4 || std::memcmp(stz + 1, "Beta", 5) != 0) { if (stz[0] != 4 || std::memcmp(stz + 1, "Beta", 5) != 0) {
return fail(__LINE__); return fail(__LINE__);
} }
auto* mutable_words = static_cast<Word*>(OpusDerefH(cab)); auto* mutable_words = static_cast<Word*>(OpusDerefH(cab));
mutable_words[kCabMinWords + kHandleCount * kPointerWords] = 42; mutable_words[kCabMinWords + kHandleBaseIag +
kHandleCount * kPointerWords] = 42;
CabHandle const duplicate = HcabDupeCab(cab); CabHandle const duplicate = HcabDupeCab(cab);
if (duplicate == nullptr) { if (duplicate == nullptr) {
return fail(__LINE__); return fail(__LINE__);
} }
GetCabSz(duplicate, sz, sizeof(sz), 0); GetCabSz(duplicate, sz, sizeof(sz), kHandleBaseIag);
if (std::strcmp(sz, "Alpha") != 0 || if (std::strcmp(sz, "Alpha") != 0 ||
static_cast<Word*>(OpusDerefH(duplicate)) static_cast<Word*>(OpusDerefH(duplicate))
[kCabMinWords + kHandleCount * kPointerWords] != 42) { [kCabMinWords + kHandleBaseIag +
kHandleCount * kPointerWords] != 42) {
return fail(__LINE__); return fail(__LINE__);
} }
NinchCab(cab); NinchCab(cab);
GetCabSz(cab, sz, sizeof(sz), 0); GetCabSz(cab, sz, sizeof(sz), kHandleBaseIag);
mutable_words = static_cast<Word*>(OpusDerefH(cab)); mutable_words = static_cast<Word*>(OpusDerefH(cab));
if (sz[0] != '\0' || if (sz[0] != '\0' ||
mutable_words[kCabMinWords + kHandleCount * kPointerWords] != mutable_words[kCabMinWords + kHandleBaseIag +
kHandleCount * kPointerWords] !=
0xffffu) { 0xffffu) {
return fail(__LINE__); return fail(__LINE__);
} }
+809 -10
View File
@@ -1,4 +1,5 @@
#include "opus_x64_compat.h" #include "opus_x64_compat.h"
#include "opus_x64_heap.h"
extern "C" { extern "C" {
#include "dac.h" #include "dac.h"
} }
@@ -13,7 +14,10 @@ extern "C" {
extern "C" { extern "C" {
extern void** hcabDlgCur; extern void** hcabDlgCur;
extern std::uint16_t wRefDlgCur; extern std::uintptr_t wRefDlgCur;
extern HWND vhWndMsgBoxParent;
void GetCabSz(void**, char*, std::uint16_t, std::uint16_t);
int FSetCabSz(void**, const char*, std::uint16_t);
} }
/* /*
@@ -53,7 +57,7 @@ struct Dli {
int dx; int dx;
int dy; int dy;
Dword flags; Dword flags;
Word reference; std::uintptr_t reference;
unsigned char* runtime_items; unsigned char* runtime_items;
}; };
@@ -75,15 +79,21 @@ struct DialogState {
DltHeader** template_handle = nullptr; DltHeader** template_handle = nullptr;
Hcab cab = nullptr; Hcab cab = nullptr;
HWND window = nullptr; HWND window = nullptr;
Word reference = 0; std::uintptr_t reference = 0;
Word hid = 0; Word hid = 0;
Word sab = 0; Word sab = 0;
Tmc focus = 0; Tmc focus = 0;
Tmc default_tmc = 1; Tmc default_tmc = 1;
Tmc result_tmc = 2;
bool visible = false; bool visible = false;
bool dying = false; bool dying = false;
bool modal = false; bool modal = false;
bool native_modal = false;
bool commands_active = false;
std::string caption; std::string caption;
std::string current_directory;
std::string file_pattern;
HWND directory_label = nullptr;
std::unordered_map<Tmc, ControlState> controls; std::unordered_map<Tmc, ControlState> controls;
}; };
@@ -95,7 +105,39 @@ Hdlg g_focus_dialog = 0;
bool g_initialized = false; bool g_initialized = false;
bool g_noninteractive = false; bool g_noninteractive = false;
constexpr Word kDlmInit = 0x0001;
constexpr Word kDlmTerm = 0x0003;
constexpr Word kDlmExit = 0x0004;
constexpr Word kDlmChange = 0x0005;
constexpr Word kDlmClick = 0x0006;
constexpr Word kDlmDblClk = 0x0007;
constexpr Word kIddNewDoc = 2;
constexpr Word kIddOpen = 3;
constexpr Tmc kTmcOk = 1;
constexpr Tmc kTmcCancel = 2;
constexpr Tmc kTmcSummary = 0x0400;
constexpr Tmc kTmcNewDot = 0x0401;
constexpr Tmc kTmcRNewDoc = 0x0402;
constexpr Tmc kTmcRNewDot = 0x0403;
constexpr Tmc kTmcNewType = 0x0404;
constexpr Tmc kTmcNewTypeList = 0x0405;
constexpr Tmc kTmcOpenFileName = 0x0400;
constexpr Tmc kTmcOpenFileList = 0x0401;
constexpr Tmc kTmcOpenFileDir = 0x0402;
constexpr Tmc kTmcOpenCatalog = 0x0403;
constexpr Tmc kTmcOpenReadOnly = 0x0404;
constexpr Word kOpenFileNameIag = 1;
constexpr std::size_t kOpenCabBytes = 24;
constexpr std::size_t kOpenReadOnlyOffset = 20;
constexpr Word kNewTypeIag = 1;
constexpr std::size_t kNewCabBytes = 24;
constexpr std::size_t kNewDotOffset = 16;
using NativeDialogProc = int (*)(Word, Tmc, Word, Word, Word);
void set_sds_handle(Hdlg current, Hdlg focus); void set_sds_handle(Hdlg current, Hdlg focus);
LRESULT CALLBACK native_dialog_window_proc(HWND, UINT, WPARAM, LPARAM);
void handle_dialog_command(Hdlg, WPARAM, LPARAM);
DialogState* find_dialog(const Hdlg dialog) { DialogState* find_dialog(const Hdlg dialog) {
const auto found = g_dialogs.find(dialog); const auto found = g_dialogs.find(dialog);
@@ -134,7 +176,76 @@ int scaled_y(const int value) {
return MulDiv(value, dac.dySysFontChar == 0 ? 16 : dac.dySysFontChar, 8); return MulDiv(value, dac.dySysFontChar == 0 ? 16 : dac.dySysFontChar, 8);
} }
ATOM ensure_native_dialog_class() {
static ATOM atom = 0;
if (atom != 0) {
return atom;
}
WNDCLASSEXA cls{};
cls.cbSize = sizeof(cls);
cls.style = CS_DBLCLKS;
cls.lpfnWndProc = native_dialog_window_proc;
cls.hInstance = GetModuleHandleW(nullptr);
cls.hCursor = LoadCursorA(nullptr, IDC_ARROW);
cls.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1);
cls.lpszClassName = "OpusSdmDialog";
atom = RegisterClassExA(&cls);
if (atom == 0 && GetLastError() == ERROR_CLASS_ALREADY_EXISTS) {
atom = 1;
}
return atom;
}
HWND create_dialog_host(const DialogState& dialog, const Dli* initializer) { HWND create_dialog_host(const DialogState& dialog, const Dli* initializer) {
if (dialog.modal &&
(dialog.hid == kIddOpen || dialog.hid == kIddNewDoc)) {
if (ensure_native_dialog_class() == 0) {
return nullptr;
}
HWND owner = initializer != nullptr ? initializer->hwnd : nullptr;
if (owner == nullptr || !IsWindow(owner)) {
owner = vhWndMsgBoxParent;
}
if (owner == nullptr || !IsWindow(owner)) {
owner = GetActiveWindow();
}
int client_width = scaled_x(dialog.hid == kIddNewDoc ? 127 : 206);
int client_height = scaled_y(dialog.hid == kIddNewDoc ? 114 : 104);
if (dialog.template_handle != nullptr &&
*dialog.template_handle != nullptr) {
client_width = (std::max)(1, scaled_x(
(*dialog.template_handle)->rec.dx));
client_height = (std::max)(1, scaled_y(
(*dialog.template_handle)->rec.dy));
}
constexpr DWORD style =
WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN;
constexpr DWORD extended_style =
WS_EX_DLGMODALFRAME | WS_EX_CONTROLPARENT;
RECT window_rect{0, 0, client_width, client_height};
AdjustWindowRectEx(&window_rect, style, false, extended_style);
const int width = window_rect.right - window_rect.left;
const int height = window_rect.bottom - window_rect.top;
RECT anchor{};
if (owner == nullptr || !GetWindowRect(owner, &anchor)) {
SystemParametersInfoA(SPI_GETWORKAREA, 0, &anchor, 0);
}
const int x = anchor.left +
(anchor.right - anchor.left - width) / 2;
const int y = anchor.top +
(anchor.bottom - anchor.top - height) / 2;
const char* const caption =
dialog.hid == kIddNewDoc ? "New" : "Open";
return CreateWindowExA(
extended_style, "OpusSdmDialog", caption, style, x, y, width,
height, owner, nullptr, GetModuleHandleW(nullptr),
reinterpret_cast<void*>(static_cast<std::uintptr_t>(
dialog.handle)));
}
if (initializer == nullptr || initializer->hwnd == nullptr || if (initializer == nullptr || initializer->hwnd == nullptr ||
!IsWindow(initializer->hwnd)) { !IsWindow(initializer->hwnd)) {
return nullptr; return nullptr;
@@ -208,6 +319,377 @@ void create_static_text(DialogState& dialog, const char* caption,
} }
} }
void create_untracked_control(DialogState& dialog, const char* window_class,
const char* caption, const Rec& rectangle,
const DWORD control_style) {
if (dialog.window == nullptr || !IsWindow(dialog.window)) {
return;
}
const HWND window = CreateWindowExA(
0, window_class, caption,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | control_style,
scaled_x(rectangle.x), scaled_y(rectangle.y),
(std::max)(1, scaled_x(rectangle.dx)),
(std::max)(1, scaled_y(rectangle.dy)), dialog.window, nullptr,
GetModuleHandleW(nullptr), nullptr);
if (window != nullptr) {
SendMessageA(window, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)),
false);
}
}
std::string join_path(const std::string& directory,
const std::string& leaf) {
if (directory.empty()) {
return leaf;
}
const char last = directory.back();
return directory + (last == '\\' || last == '/' ? "" : "\\") + leaf;
}
void add_native_list_entry(DialogState& dialog, const Tmc tmc,
const std::string& entry) {
auto& state = dialog.controls[tmc];
state.entries.push_back(entry);
if (state.window != nullptr && IsWindow(state.window)) {
SendMessageA(state.window, LB_ADDSTRING, 0,
reinterpret_cast<LPARAM>(entry.c_str()));
}
}
void set_open_directory_label(DialogState& dialog) {
if (dialog.directory_label != nullptr &&
IsWindow(dialog.directory_label)) {
SetWindowTextA(dialog.directory_label,
dialog.current_directory.c_str());
}
}
void establish_open_directory(DialogState& dialog,
const std::string& specification) {
char full_path[32768] = {};
char* file_part = nullptr;
const std::string source = specification.empty() ? "*.*" : specification;
const DWORD length = GetFullPathNameA(
source.c_str(), static_cast<DWORD>(sizeof(full_path)), full_path,
&file_part);
if (length == 0 || length >= sizeof(full_path)) {
GetCurrentDirectoryA(static_cast<DWORD>(sizeof(full_path)), full_path);
dialog.current_directory = full_path;
dialog.file_pattern = "*.*";
return;
}
const DWORD attributes = GetFileAttributesA(full_path);
if (attributes != INVALID_FILE_ATTRIBUTES &&
(attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
dialog.current_directory = full_path;
dialog.file_pattern = "*.*";
return;
}
dialog.file_pattern =
file_part == nullptr || *file_part == '\0' ? "*.*" : file_part;
if (file_part == nullptr || file_part == full_path) {
GetCurrentDirectoryA(static_cast<DWORD>(sizeof(full_path)), full_path);
dialog.current_directory = full_path;
} else {
std::size_t directory_length =
static_cast<std::size_t>(file_part - full_path);
while (directory_length > 3 &&
(full_path[directory_length - 1] == '\\' ||
full_path[directory_length - 1] == '/')) {
--directory_length;
}
dialog.current_directory.assign(full_path, directory_length);
}
}
void populate_open_lists(DialogState& dialog) {
auto& files = dialog.controls[kTmcOpenFileList];
auto& directories = dialog.controls[kTmcOpenFileDir];
files.entries.clear();
directories.entries.clear();
if (files.window != nullptr) {
SendMessageA(files.window, LB_RESETCONTENT, 0, 0);
}
if (directories.window != nullptr) {
SendMessageA(directories.window, LB_RESETCONTENT, 0, 0);
}
WIN32_FIND_DATAA find_data{};
HANDLE find = FindFirstFileA(
join_path(dialog.current_directory, dialog.file_pattern).c_str(),
&find_data);
if (find != INVALID_HANDLE_VALUE) {
do {
if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
add_native_list_entry(dialog, kTmcOpenFileList,
find_data.cFileName);
}
} while (FindNextFileA(find, &find_data));
FindClose(find);
}
char parent_path[32768] = {};
const std::string parent_spec = join_path(dialog.current_directory, "..");
if (GetFullPathNameA(parent_spec.c_str(),
static_cast<DWORD>(sizeof(parent_path)), parent_path,
nullptr) != 0 &&
_stricmp(parent_path, dialog.current_directory.c_str()) != 0) {
add_native_list_entry(dialog, kTmcOpenFileDir, "[..]");
}
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, kTmcOpenFileDir,
"[" + std::string(find_data.cFileName) + "]");
}
} while (FindNextFileA(find, &find_data));
FindClose(find);
}
set_open_directory_label(dialog);
}
void read_open_cab(DialogState& dialog) {
char file_name[32768] = {};
if (dialog.cab != nullptr) {
GetCabSz(dialog.cab, file_name,
static_cast<Word>((std::min)(sizeof(file_name),
std::size_t{0xffffu})),
kOpenFileNameIag);
}
auto& edit = dialog.controls[kTmcOpenFileName];
edit.text = file_name;
if (edit.window != nullptr) {
SetWindowTextA(edit.window, edit.text.c_str());
}
if (dialog.cab != nullptr && *dialog.cab != nullptr &&
OpusCbOfH(dialog.cab) >= kOpenCabBytes) {
int read_only = 0;
std::memcpy(&read_only,
static_cast<const unsigned char*>(*dialog.cab) +
kOpenReadOnlyOffset,
sizeof(read_only));
auto& checkbox = dialog.controls[kTmcOpenReadOnly];
checkbox.value = read_only != 0;
if (checkbox.window != nullptr) {
SendMessageA(checkbox.window, BM_SETCHECK,
checkbox.value ? BST_CHECKED : BST_UNCHECKED, 0);
}
}
establish_open_directory(dialog, edit.text);
populate_open_lists(dialog);
}
void sync_open_cab(DialogState& dialog) {
auto edit = dialog.controls.find(kTmcOpenFileName);
if (edit != dialog.controls.end() && edit->second.window != nullptr) {
const int length = GetWindowTextLengthA(edit->second.window);
std::vector<char> buffer(static_cast<std::size_t>(length) + 1);
GetWindowTextA(edit->second.window, buffer.data(),
static_cast<int>(buffer.size()));
edit->second.text = buffer.data();
}
if (dialog.cab != nullptr && edit != dialog.controls.end()) {
FSetCabSz(dialog.cab, edit->second.text.c_str(), kOpenFileNameIag);
}
auto checkbox = dialog.controls.find(kTmcOpenReadOnly);
if (checkbox != dialog.controls.end() && checkbox->second.window != nullptr) {
checkbox->second.value = static_cast<Word>(
SendMessageA(checkbox->second.window, BM_GETCHECK, 0, 0) ==
BST_CHECKED);
}
if (dialog.cab != nullptr && *dialog.cab != nullptr &&
OpusCbOfH(dialog.cab) >= kOpenCabBytes &&
checkbox != dialog.controls.end()) {
const int read_only = checkbox->second.value != 0;
std::memcpy(static_cast<unsigned char*>(*dialog.cab) +
kOpenReadOnlyOffset,
&read_only, sizeof(read_only));
}
}
void populate_new_type_list(DialogState& dialog) {
auto& list = dialog.controls[kTmcNewTypeList];
list.entries.clear();
if (list.window != nullptr) {
SendMessageA(list.window, LB_RESETCONTENT, 0, 0);
}
const std::string initial = dialog.controls[kTmcNewType].text;
add_native_list_entry(dialog, kTmcNewTypeList,
initial.empty() ? "NORMAL" : initial);
WIN32_FIND_DATAA find_data{};
HANDLE find = FindFirstFileA("*.DOT", &find_data);
if (find == INVALID_HANDLE_VALUE) {
return;
}
do {
if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
continue;
}
const auto duplicate = std::find_if(
list.entries.begin(), list.entries.end(),
[&find_data](const std::string& entry) {
return _stricmp(entry.c_str(), find_data.cFileName) == 0;
});
if (duplicate == list.entries.end()) {
add_native_list_entry(dialog, kTmcNewTypeList,
find_data.cFileName);
}
} while (FindNextFileA(find, &find_data));
FindClose(find);
}
void read_new_cab(DialogState& dialog) {
char type_name[32768] = {};
if (dialog.cab != nullptr) {
GetCabSz(dialog.cab, type_name,
static_cast<Word>((std::min)(sizeof(type_name),
std::size_t{0xffffu})),
kNewTypeIag);
}
auto& edit = dialog.controls[kTmcNewType];
edit.text = type_name;
if (edit.window != nullptr) {
SetWindowTextA(edit.window, edit.text.c_str());
}
bool new_template = false;
if (dialog.cab != nullptr && *dialog.cab != nullptr &&
OpusCbOfH(dialog.cab) >= kNewCabBytes) {
int value = 0;
std::memcpy(&value,
static_cast<const unsigned char*>(*dialog.cab) +
kNewDotOffset,
sizeof(value));
new_template = value != 0;
}
dialog.controls[kTmcNewDot].value = new_template;
dialog.controls[kTmcRNewDoc].value = !new_template;
dialog.controls[kTmcRNewDot].value = new_template;
if (dialog.controls[kTmcRNewDoc].window != nullptr) {
SendMessageA(dialog.controls[kTmcRNewDoc].window, BM_SETCHECK,
new_template ? BST_UNCHECKED : BST_CHECKED, 0);
}
if (dialog.controls[kTmcRNewDot].window != nullptr) {
SendMessageA(dialog.controls[kTmcRNewDot].window, BM_SETCHECK,
new_template ? BST_CHECKED : BST_UNCHECKED, 0);
}
populate_new_type_list(dialog);
}
void sync_new_cab(DialogState& dialog) {
auto edit = dialog.controls.find(kTmcNewType);
if (edit != dialog.controls.end() && edit->second.window != nullptr) {
const int length = GetWindowTextLengthA(edit->second.window);
std::vector<char> buffer(static_cast<std::size_t>(length) + 1);
GetWindowTextA(edit->second.window, buffer.data(),
static_cast<int>(buffer.size()));
edit->second.text = buffer.data();
}
if (dialog.cab != nullptr && edit != dialog.controls.end()) {
FSetCabSz(dialog.cab, edit->second.text.c_str(), kNewTypeIag);
}
bool new_template = false;
const auto radio = dialog.controls.find(kTmcRNewDot);
if (radio != dialog.controls.end() && radio->second.window != nullptr) {
new_template = SendMessageA(radio->second.window, BM_GETCHECK, 0, 0) ==
BST_CHECKED;
}
dialog.controls[kTmcNewDot].value = new_template;
if (dialog.cab != nullptr && *dialog.cab != nullptr &&
OpusCbOfH(dialog.cab) >= kNewCabBytes) {
const int value = new_template;
std::memcpy(static_cast<unsigned char*>(*dialog.cab) + kNewDotOffset,
&value, sizeof(value));
}
}
void materialize_new_template(DialogState& dialog) {
if (dialog.hid != kIddNewDoc || dialog.window == nullptr) {
return;
}
create_native_control(dialog, kTmcOk, "BUTTON", "OK", {74, 6, 46, 14},
WS_TABSTOP | BS_DEFPUSHBUTTON);
create_native_control(dialog, kTmcCancel, "BUTTON", "Cancel",
{74, 23, 46, 14}, WS_TABSTOP | BS_PUSHBUTTON);
create_native_control(dialog, kTmcSummary, "BUTTON", "&Summary...",
{74, 39, 46, 14}, WS_TABSTOP | BS_PUSHBUTTON);
create_untracked_control(dialog, "BUTTON", "New", {5, 2, 61, 36},
BS_GROUPBOX);
create_native_control(dialog, kTmcRNewDoc, "BUTTON", "&Document",
{9, 12, 42, 10},
WS_TABSTOP | WS_GROUP | BS_AUTORADIOBUTTON);
create_native_control(dialog, kTmcRNewDot, "BUTTON", "&Template",
{9, 24, 42, 10},
WS_TABSTOP | BS_AUTORADIOBUTTON);
create_static_text(dialog, "&Use Template:", {5, 42, 53, 10});
create_native_control(dialog, kTmcNewType, "EDIT", "",
{5, 53, 61, 12},
WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL);
create_native_control(dialog, kTmcNewTypeList, "LISTBOX", "",
{8, 65, 68, 40},
WS_TABSTOP | WS_BORDER | WS_VSCROLL | LBS_NOTIFY |
LBS_SORT | LBS_NOINTEGRALHEIGHT);
dialog.caption = "New";
dialog.native_modal = true;
read_new_cab(dialog);
}
void materialize_open_template(DialogState& dialog) {
if (dialog.hid != kIddOpen || dialog.window == nullptr) {
return;
}
create_native_control(dialog, kTmcOpenFileName, "EDIT", "",
{67, 6, 83, 12},
WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL);
create_static_text(dialog, "Open File &Name:", {5, 7, 61, 9});
create_native_control(dialog, kTmcOpenFileList, "LISTBOX", "",
{5, 32, 60, 64},
WS_TABSTOP | WS_BORDER | WS_VSCROLL | LBS_NOTIFY |
LBS_SORT | LBS_NOINTEGRALHEIGHT);
create_static_text(dialog, "&Files:", {5, 21, 25, 9});
create_native_control(dialog, kTmcOpenFileDir, "LISTBOX", "",
{71, 48, 65, 48},
WS_TABSTOP | WS_BORDER | WS_VSCROLL | LBS_NOTIFY |
LBS_SORT | LBS_NOINTEGRALHEIGHT);
create_static_text(dialog, "&Directories:", {71, 38, 50, 9});
dialog.directory_label = CreateWindowExA(
0, "STATIC", "", WS_CHILD | WS_VISIBLE | SS_LEFT,
scaled_x(70), scaled_y(24), scaled_x(78), scaled_y(8),
dialog.window, nullptr, GetModuleHandleW(nullptr), nullptr);
if (dialog.directory_label != nullptr) {
SendMessageA(dialog.directory_label, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)),
false);
}
create_native_control(dialog, kTmcOk, "BUTTON", "OK",
{154, 5, 47, 14},
WS_TABSTOP | BS_DEFPUSHBUTTON);
create_native_control(dialog, kTmcCancel, "BUTTON", "Cancel",
{154, 22, 47, 14}, WS_TABSTOP | BS_PUSHBUTTON);
create_native_control(dialog, kTmcOpenCatalog, "BUTTON", "F&ind...",
{154, 39, 47, 14}, WS_TABSTOP | BS_PUSHBUTTON);
create_native_control(dialog, kTmcOpenReadOnly, "BUTTON", "&Read Only",
{155, 56, 47, 12},
WS_TABSTOP | BS_AUTOCHECKBOX);
dialog.caption = "Open";
dialog.native_modal = true;
read_open_cab(dialog);
}
void materialize_icon_bar_template(DialogState& dialog) { void materialize_icon_bar_template(DialogState& dialog) {
constexpr Word cxtRibbonIconBar = 0x8005; constexpr Word cxtRibbonIconBar = 0x8005;
constexpr Word cxtRulerIconBar = 0x8006; constexpr Word cxtRulerIconBar = 0x8006;
@@ -290,6 +772,244 @@ std::string counted_or_zero_terminated(const char* text) {
return std::string(text); return std::string(text);
} }
bool invoke_dialog_proc(DialogState& dialog, const Word message,
const Tmc tmc, const Word new_value = 0,
const Word old_value = 0,
const Word parameter = 0) {
if (dialog.template_handle == nullptr ||
*dialog.template_handle == nullptr ||
(*dialog.template_handle)->dialog_proc == nullptr) {
return true;
}
const auto proc = reinterpret_cast<NativeDialogProc>(
(*dialog.template_handle)->dialog_proc);
return proc(message, tmc, new_value, old_value, parameter) != 0;
}
std::string selected_list_text(const ControlState& control_state) {
if (control_state.window == nullptr) {
return {};
}
const LRESULT selection =
SendMessageA(control_state.window, LB_GETCURSEL, 0, 0);
if (selection == LB_ERR) {
return {};
}
const LRESULT length =
SendMessageA(control_state.window, LB_GETTEXTLEN, selection, 0);
if (length == LB_ERR) {
return {};
}
std::vector<char> text(static_cast<std::size_t>(length) + 1);
SendMessageA(control_state.window, LB_GETTEXT, selection,
reinterpret_cast<LPARAM>(text.data()));
return text.data();
}
void select_new_type(DialogState& dialog) {
const auto found = dialog.controls.find(kTmcNewTypeList);
if (found == dialog.controls.end()) {
return;
}
const std::string selected = selected_list_text(found->second);
if (selected.empty()) {
return;
}
auto& edit = dialog.controls[kTmcNewType];
edit.text = selected;
if (edit.window != nullptr) {
SetWindowTextA(edit.window, edit.text.c_str());
SendMessageA(edit.window, EM_SETSEL, 0, static_cast<LPARAM>(-1));
}
}
void select_open_file(DialogState& dialog) {
const auto found = dialog.controls.find(kTmcOpenFileList);
if (found == dialog.controls.end()) {
return;
}
const std::string selected = selected_list_text(found->second);
if (selected.empty()) {
return;
}
auto& edit = dialog.controls[kTmcOpenFileName];
edit.text = join_path(dialog.current_directory, selected);
if (edit.window != nullptr) {
SetWindowTextA(edit.window, edit.text.c_str());
SendMessageA(edit.window, EM_SETSEL, 0,
static_cast<LPARAM>(-1));
}
}
void enter_open_directory(DialogState& dialog) {
const auto found = dialog.controls.find(kTmcOpenFileDir);
if (found == dialog.controls.end()) {
return;
}
std::string selected = selected_list_text(found->second);
if (selected.size() < 2 || selected.front() != '[' ||
selected.back() != ']') {
return;
}
selected = selected.substr(1, selected.size() - 2);
char full_path[32768] = {};
const std::string destination =
join_path(dialog.current_directory, selected);
if (GetFullPathNameA(destination.c_str(),
static_cast<DWORD>(sizeof(full_path)), full_path,
nullptr) == 0) {
return;
}
dialog.current_directory = full_path;
populate_open_lists(dialog);
auto& edit = dialog.controls[kTmcOpenFileName];
edit.text = join_path(dialog.current_directory, dialog.file_pattern);
if (edit.window != nullptr) {
SetWindowTextA(edit.window, edit.text.c_str());
}
}
void finish_native_dialog(DialogState& dialog, const Tmc result) {
if (dialog.hid == kIddOpen) {
sync_open_cab(dialog);
} else if (dialog.hid == kIddNewDoc) {
sync_new_cab(dialog);
}
if (!invoke_dialog_proc(dialog, kDlmTerm, result)) {
return;
}
dialog.result_tmc = result;
dialog.dying = true;
dialog.visible = false;
if (dialog.window != nullptr && IsWindow(dialog.window)) {
ShowWindow(dialog.window, SW_HIDE);
}
}
void handle_dialog_command(const Hdlg handle, const WPARAM w_param,
const LPARAM l_param) {
auto* dialog = find_dialog(handle);
if (dialog == nullptr || dialog->dying) {
return;
}
const Tmc tmc = static_cast<Tmc>(LOWORD(w_param) & ~0x8000u);
const Word notification = HIWORD(w_param);
auto found = dialog->controls.find(tmc);
if (found != dialog->controls.end() &&
found->second.window == reinterpret_cast<HWND>(l_param)) {
if (tmc == kTmcOpenFileName && dialog->hid == kIddOpen) {
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 (tmc == kTmcOpenReadOnly && dialog->hid == kIddOpen) {
found->second.value = static_cast<Word>(
SendMessageA(found->second.window, BM_GETCHECK, 0, 0) ==
BST_CHECKED);
} else if (tmc == kTmcNewType && dialog->hid == kIddNewDoc) {
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();
}
}
if (!dialog->commands_active) {
return;
}
g_current_dialog = handle;
g_focus_dialog = handle;
sync_current_dialog_globals();
if (dialog->hid == kIddNewDoc && tmc == kTmcNewType &&
notification == EN_CHANGE) {
invoke_dialog_proc(*dialog, kDlmChange, tmc);
return;
}
if (dialog->hid == kIddNewDoc && tmc == kTmcNewTypeList &&
(notification == LBN_SELCHANGE || notification == LBN_DBLCLK)) {
select_new_type(*dialog);
invoke_dialog_proc(*dialog,
notification == LBN_DBLCLK ? kDlmDblClk
: kDlmClick,
tmc);
return;
}
if (dialog->hid == kIddOpen && tmc == kTmcOpenFileName &&
notification == EN_CHANGE) {
invoke_dialog_proc(*dialog, kDlmChange, tmc);
return;
}
if (dialog->hid == kIddOpen && tmc == kTmcOpenFileList &&
(notification == LBN_SELCHANGE || notification == LBN_DBLCLK)) {
select_open_file(*dialog);
invoke_dialog_proc(*dialog,
notification == LBN_DBLCLK ? kDlmDblClk
: kDlmClick,
tmc);
if (notification == LBN_DBLCLK && !dialog->dying) {
finish_native_dialog(*dialog, kTmcOk);
}
return;
}
if (dialog->hid == kIddOpen && tmc == kTmcOpenFileDir &&
(notification == LBN_SELCHANGE || notification == LBN_DBLCLK)) {
invoke_dialog_proc(*dialog,
notification == LBN_DBLCLK ? kDlmDblClk
: kDlmClick,
tmc);
if (notification == LBN_DBLCLK && !dialog->dying) {
enter_open_directory(*dialog);
}
return;
}
if (notification == BN_CLICKED) {
if (dialog->hid == kIddNewDoc &&
(tmc == kTmcRNewDoc || tmc == kTmcRNewDot)) {
const bool new_template = tmc == kTmcRNewDot;
dialog->controls[kTmcNewDot].value = new_template;
dialog->controls[kTmcRNewDoc].value = !new_template;
dialog->controls[kTmcRNewDot].value = new_template;
invoke_dialog_proc(*dialog, kDlmClick, tmc);
} else if (tmc == kTmcOk || tmc == kTmcCancel ||
(dialog->hid == kIddOpen &&
tmc == kTmcOpenCatalog) ||
(dialog->hid == kIddNewDoc &&
tmc == kTmcSummary)) {
finish_native_dialog(*dialog, tmc);
} else {
invoke_dialog_proc(*dialog, kDlmClick, tmc);
}
}
}
LRESULT CALLBACK native_dialog_window_proc(const HWND window,
const UINT message,
const WPARAM w_param,
const LPARAM l_param) {
if (message == WM_NCCREATE) {
const auto* create = reinterpret_cast<const CREATESTRUCTA*>(l_param);
SetWindowLongPtrA(window, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(create->lpCreateParams));
}
const Hdlg handle = static_cast<Hdlg>(reinterpret_cast<std::uintptr_t>(
reinterpret_cast<void*>(GetWindowLongPtrA(window, GWLP_USERDATA))));
switch (message) {
case WM_COMMAND:
handle_dialog_command(handle, w_param, l_param);
return 0;
case WM_CLOSE:
if (auto* dialog = find_dialog(handle); dialog != nullptr) {
finish_native_dialog(*dialog, kTmcCancel);
}
return 0;
default:
return DefWindowProcA(window, message, w_param, l_param);
}
}
} // namespace } // namespace
extern "C" { extern "C" {
@@ -306,7 +1026,7 @@ DAC_SDM dac = {};
HWND vhWndMsgBoxParent = nullptr; HWND vhWndMsgBoxParent = nullptr;
extern void** hcabDlgCur; extern void** hcabDlgCur;
extern Word wRefDlgCur; extern std::uintptr_t wRefDlgCur;
int FInitSdm_sdm21(void*) { int FInitSdm_sdm21(void*) {
g_initialized = true; g_initialized = true;
@@ -374,19 +1094,97 @@ Hdlg HdlgStartDlg(DltHeader** dialog_template, Hcab cab, Dli* initializer) {
} }
dialog.window = create_dialog_host(dialog, initializer); dialog.window = create_dialog_host(dialog, initializer);
g_dialogs.emplace(handle, std::move(dialog)); g_dialogs.emplace(handle, std::move(dialog));
materialize_icon_bar_template(g_dialogs.at(handle));
g_current_dialog = handle; g_current_dialog = handle;
g_focus_dialog = handle; g_focus_dialog = handle;
sync_current_dialog_globals(); sync_current_dialog_globals();
materialize_icon_bar_template(g_dialogs.at(handle));
materialize_new_template(g_dialogs.at(handle));
materialize_open_template(g_dialogs.at(handle));
return handle; return handle;
} }
Tmc TmcDoDlgDli(DltHeader** dialog_template, Hcab cab, Dli* initializer) { Tmc TmcDoDlgDli(DltHeader** dialog_template, Hcab cab, Dli* initializer) {
if (HdlgStartDlg(dialog_template, cab, initializer) == 0) { const Hdlg previous_current = g_current_dialog;
const Hdlg previous_focus = g_focus_dialog;
const Hdlg handle = HdlgStartDlg(dialog_template, cab, initializer);
if (handle == 0) {
return static_cast<Tmc>(-1); return static_cast<Tmc>(-1);
} }
g_dialog.visible = true; auto* dialog = find_dialog(handle);
return 2; // tmcCancel until native template materialization is active. if (dialog == nullptr) {
return static_cast<Tmc>(-1);
}
Tmc result = kTmcCancel;
HWND owner = nullptr;
bool restore_owner = false;
if (dialog->modal && dialog->native_modal && dialog->window != nullptr) {
owner = GetWindow(dialog->window, GW_OWNER);
restore_owner = owner != nullptr && IsWindow(owner) &&
IsWindowEnabled(owner) != 0;
if (restore_owner) {
EnableWindow(owner, false);
}
invoke_dialog_proc(*dialog, kDlmInit, dialog->focus);
dialog->commands_active = true;
if (!dialog->dying) {
dialog->visible = true;
ShowWindow(dialog->window, SW_SHOW);
UpdateWindow(dialog->window);
SetActiveWindow(dialog->window);
const auto focus = dialog->controls.find(
static_cast<Tmc>(dialog->focus & ~0x8000u));
if (focus != dialog->controls.end() &&
focus->second.window != nullptr) {
SetFocus(focus->second.window);
}
}
MSG message{};
while (!dialog->dying) {
const int status = GetMessageA(&message, nullptr, 0, 0);
if (status <= 0) {
if (status == 0) {
PostQuitMessage(static_cast<int>(message.wParam));
}
dialog->result_tmc = kTmcCancel;
dialog->dying = true;
break;
}
if (!IsDialogMessageA(dialog->window, &message)) {
TranslateMessage(&message);
DispatchMessageA(&message);
}
dialog = find_dialog(handle);
if (dialog == nullptr) {
break;
}
}
if (dialog != nullptr) {
result = dialog->result_tmc;
dialog->commands_active = false;
invoke_dialog_proc(*dialog, kDlmExit, result);
}
}
dialog = find_dialog(handle);
if (dialog != nullptr && dialog->window != nullptr &&
IsWindow(dialog->window)) {
DestroyWindow(dialog->window);
}
g_dialogs.erase(handle);
if (restore_owner && owner != nullptr && IsWindow(owner)) {
EnableWindow(owner, true);
SetActiveWindow(owner);
}
g_current_dialog = find_dialog(previous_current) == nullptr
? 0
: previous_current;
g_focus_dialog = find_dialog(previous_focus) == nullptr ? 0
: previous_focus;
sync_current_dialog_globals();
return result;
} }
Tmc TmcDoDlg_sdm21(DltHeader** dialog_template, Hcab cab, Tmc TmcDoDlg_sdm21(DltHeader** dialog_template, Hcab cab,
@@ -397,7 +1195,8 @@ Tmc TmcDoDlg_sdm21(DltHeader** dialog_template, Hcab cab,
return TmcDoDlgDli(dialog_template, cab, &initializer); return TmcDoDlgDli(dialog_template, cab, &initializer);
} }
void EndDlg(Tmc) { void EndDlg(Tmc result) {
g_dialog.result_tmc = result;
g_dialog.dying = true; g_dialog.dying = true;
g_dialog.visible = false; g_dialog.visible = false;
if (g_dialog.window != nullptr && IsWindow(g_dialog.window)) { if (g_dialog.window != nullptr && IsWindow(g_dialog.window)) {
@@ -701,7 +1500,7 @@ Hcab HcabFromDlg(int dialog) {
} }
void SaveCabs(void (*callback)(Hcab, Word, Tmc, int), int save) { void SaveCabs(void (*callback)(Hcab, Word, Tmc, int), int save) {
if (callback != nullptr && g_dialog.cab != nullptr) { if (callback != nullptr && g_dialog.cab != nullptr) {
callback(g_dialog.cab, g_dialog.reference, 0, save); callback(g_dialog.cab, g_dialog.hid, 0, save);
} }
} }
+67 -1
View File
@@ -71,7 +71,7 @@ struct TestDli {
int dx; int dx;
int dy; int dy;
std::uint32_t flags; std::uint32_t flags;
TestWord reference; std::uintptr_t reference;
unsigned char* runtime_items; unsigned char* runtime_items;
}; };
@@ -83,9 +83,51 @@ extern "C" HWND HwndFromDlg(TestWord);
extern "C" HWND HwndOfTmc(TestWord); extern "C" HWND HwndOfTmc(TestWord);
extern "C" int FModalDlg(TestWord); extern "C" int FModalDlg(TestWord);
extern "C" int FFreeDlg(); extern "C" int FFreeDlg();
extern "C" TestWord TmcDoDlgDli(TestDltHeader**, void**, TestDli*);
extern "C" void EndDlg(TestWord);
extern "C" void SetTmcText_sdm21(TestWord, char*); extern "C" void SetTmcText_sdm21(TestWord, char*);
extern "C" void GetTmcText_sdm21(TestWord, char*, TestWord); extern "C" void GetTmcText_sdm21(TestWord, char*, TestWord);
int modal_init_count = 0;
int modal_exit_count = 0;
int new_modal_init_count = 0;
int new_modal_exit_count = 0;
bool new_modal_controls_present = false;
bool WindowHasClass(const HWND window, const char* expected) {
char class_name[32] = {};
return window != nullptr &&
GetClassNameA(window, class_name, sizeof(class_name)) != 0 &&
std::strcmp(class_name, expected) == 0;
}
int ModalRuntimeProbe(TestWord message, TestWord, TestWord, TestWord,
TestWord) {
if (message == 1) {
++modal_init_count;
EndDlg(2);
} else if (message == 4) {
++modal_exit_count;
}
return 1;
}
int NewModalRuntimeProbe(TestWord message, TestWord, TestWord, TestWord,
TestWord) {
if (message == 1) {
++new_modal_init_count;
new_modal_controls_present =
WindowHasClass(HwndOfTmc(0x0402), "Button") &&
WindowHasClass(HwndOfTmc(0x0403), "Button") &&
WindowHasClass(HwndOfTmc(0x0404), "Edit") &&
WindowHasClass(HwndOfTmc(0x0405), "ListBox");
EndDlg(2);
} else if (message == 4) {
++new_modal_exit_count;
}
return 1;
}
int main() { int main() {
std::array offsets{2, 8, 13, 3}; std::array offsets{2, 8, 13, 3};
AddDcbToLprgbst(offsets.data(), static_cast<int>(offsets.size()), 5, 8); AddDcbToLprgbst(offsets.data(), static_cast<int>(offsets.size()), 5, 8);
@@ -283,6 +325,30 @@ int main() {
EndSdm(); EndSdm();
return 23; return 23;
} }
TestDltHeader modal_template{{8, 24, 206, 104}, 3, 0x8400,
reinterpret_cast<void*>(ModalRuntimeProbe),
11, 4};
auto* modal_template_pointer = &modal_template;
TestDli modal_initializer{parent, 0, 0, 1, 0, nullptr};
if (TmcDoDlgDli(&modal_template_pointer, nullptr, &modal_initializer) != 2 ||
modal_init_count != 1 || modal_exit_count != 1 ||
!IsWindow(second_host)) {
DestroyWindow(parent);
EndSdm();
return 24;
}
TestDltHeader new_modal_template{
{20, 24, 127, 114}, 2, 0x8404,
reinterpret_cast<void*>(NewModalRuntimeProbe), 9, 4};
auto* new_modal_template_pointer = &new_modal_template;
if (TmcDoDlgDli(&new_modal_template_pointer, nullptr,
&modal_initializer) != 2 ||
new_modal_init_count != 1 || new_modal_exit_count != 1 ||
!new_modal_controls_present || !IsWindow(second_host)) {
DestroyWindow(parent);
EndSdm();
return 25;
}
EndSdm(); EndSdm();
DestroyWindow(parent); DestroyWindow(parent);
+1 -1
View File
@@ -24,6 +24,7 @@ typedef struct _CABPARALOOKS
{ {
CABH cabh; CABH cabh;
WORD sab; WORD sab;
CHAR **hszStyle;
int iJustify; int iJustify;
int wParLeftIn; int wParLeftIn;
int wParRightIn; int wParRightIn;
@@ -31,7 +32,6 @@ typedef struct _CABPARALOOKS
int wParDyaBefore; int wParDyaBefore;
int wParDyaAfter; int wParDyaAfter;
int wParDyaLine; int wParDyaLine;
CHAR **hszStyle;
BOOL fParKeepLT; BOOL fParKeepLT;
BOOL fParKeepNP; BOOL fParKeepNP;
int iBrcp; int iBrcp;
+1
View File
@@ -6,6 +6,7 @@
typedef struct _CABFILEPSWD typedef struct _CABFILEPSWD
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszPswd; CHAR **hszPswd;
} CABFILEPSWD; } CABFILEPSWD;
+1 -1
View File
@@ -4,8 +4,8 @@ typedef struct _CABPASTELINK
{ {
CABH cabh; CABH cabh;
WORD sab; WORD sab;
BOOL fHot;
CHAR **hszLink; CHAR **hszLink;
BOOL fHot;
} CABPASTELINK; } CABPASTELINK;
typedef CABPASTELINK **HCABPASTELINK; typedef CABPASTELINK **HCABPASTELINK;
#define cabiCABPASTELINK Cabi((sizeof(CABPASTELINK) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABPASTELINK Cabi((sizeof(CABPASTELINK) + sizeof(WORD) - 1) / sizeof(WORD), 1)
+1 -2
View File
@@ -9,10 +9,10 @@
#define tmcCropBottom (tmcUserMin + 5) #define tmcCropBottom (tmcUserMin + 5)
#define tmcCropRight (tmcUserMin + 6) #define tmcCropRight (tmcUserMin + 6)
#pragma pack(push, 2)
typedef struct _CABFORMATPIC typedef struct _CABFORMATPIC
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszOrigSize; CHAR **hszOrigSize;
int iPicBrcl; int iPicBrcl;
int wScaleMy; int wScaleMy;
@@ -22,7 +22,6 @@ typedef struct _CABFORMATPIC
int wCropBottom; int wCropBottom;
int wCropRight; int wCropRight;
} CABFORMATPIC; } CABFORMATPIC;
#pragma pack(pop)
typedef CABFORMATPIC **HCABFORMATPIC; typedef CABFORMATPIC **HCABFORMATPIC;
+3 -3
View File
@@ -29,11 +29,12 @@ typedef struct _CABPRINT
CABH cabh; CABH cabh;
WORD sab; WORD sab;
CHAR **hszPrPrinter; CHAR **hszPrPrinter;
CHAR **hszPrFrom;
CHAR **hszPrTo;
CHAR **hszFileName;
int istPrSrc; int istPrSrc;
int cCopies; int cCopies;
int prng; int prng;
CHAR **hszPrFrom;
CHAR **hszPrTo;
BOOL fReverse; BOOL fReverse;
BOOL fDraft; BOOL fDraft;
BOOL fRefresh; BOOL fRefresh;
@@ -42,7 +43,6 @@ typedef struct _CABPRINT
BOOL fAnnotations; BOOL fAnnotations;
BOOL fSeeHidden; BOOL fSeeHidden;
BOOL fShowInst; BOOL fShowInst;
CHAR **hszFileName;
} CABPRINT; } CABPRINT;
typedef CABPRINT **HCABPRINT; typedef CABPRINT **HCABPRINT;
-2
View File
@@ -9,7 +9,6 @@
#define tmcPMPrint (tmcUserMin + 5) #define tmcPMPrint (tmcUserMin + 5)
#define tmcPMNewDoc (tmcUserMin + 6) #define tmcPMNewDoc (tmcUserMin + 6)
#pragma pack(push, 2)
typedef struct _CABPRINTMERGE typedef struct _CABPRINTMERGE
{ {
CABH cabh; CABH cabh;
@@ -18,7 +17,6 @@ typedef struct _CABPRINTMERGE
int iRecFrom; int iRecFrom;
int iRecTo; int iRecTo;
} CABPRINTMERGE; } CABPRINTMERGE;
#pragma pack(pop)
typedef CABPRINTMERGE **HCABPRINTMERGE; typedef CABPRINTMERGE **HCABPRINTMERGE;
#define cabiCABPRINTMERGE Cabi((sizeof(CABPRINTMERGE) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABPRINTMERGE Cabi((sizeof(CABPRINTMERGE) + sizeof(WORD) - 1) / sizeof(WORD), 0)
+1
View File
@@ -12,6 +12,7 @@
typedef struct _CABPROMPT typedef struct _CABPROMPT
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszPrompt; CHAR **hszPrompt;
CHAR **hszInput; CHAR **hszInput;
} CABPROMPT; } CABPROMPT;
+1 -1
View File
@@ -10,8 +10,8 @@ typedef struct _CABRECORDER
CABH cabh; CABH cabh;
WORD sab; WORD sab;
CHAR **pszName; CHAR **pszName;
int iContext;
CHAR **pszDesc; CHAR **pszDesc;
int iContext;
} CABRECORDER; } CABRECORDER;
typedef CABRECORDER **HCABRECORDER; typedef CABRECORDER **HCABRECORDER;
-2
View File
@@ -12,7 +12,6 @@
#define tmcRPAllLevels (tmcUserMin + 8) #define tmcRPAllLevels (tmcUserMin + 8)
#define tmcRPFormat ((tmcUserMin + 9) | ftmcGrouped) #define tmcRPFormat ((tmcUserMin + 9) | ftmcGrouped)
#pragma pack(push, 2)
typedef struct _CABRENUMPARAS typedef struct _CABRENUMPARAS
{ {
CABH cabh; CABH cabh;
@@ -23,7 +22,6 @@ typedef struct _CABRENUMPARAS
BOOL fManual; BOOL fManual;
BOOL fShowAllLev; BOOL fShowAllLev;
} CABRENUMPARAS; } CABRENUMPARAS;
#pragma pack(pop)
typedef CABRENUMPARAS **HCABRENUMPARAS; typedef CABRENUMPARAS **HCABRENUMPARAS;
#define cabiCABRENUMPARAS Cabi((sizeof(CABRENUMPARAS) + sizeof(WORD) - 1) / sizeof(WORD), 2) #define cabiCABRENUMPARAS Cabi((sizeof(CABRENUMPARAS) + sizeof(WORD) - 1) / sizeof(WORD), 2)
+1
View File
@@ -16,6 +16,7 @@
typedef struct _CABRIBBON typedef struct _CABRIBBON
{ {
CABH cabh; CABH cabh;
WORD sab;
int ftc; int ftc;
int hps; int hps;
} CABRIBBON; } CABRIBBON;
+1
View File
@@ -12,6 +12,7 @@
typedef struct _CABRIBBON3 typedef struct _CABRIBBON3
{ {
CABH cabh; CABH cabh;
WORD sab;
int ftc; int ftc;
int hps; int hps;
} CABRIBBON3; } CABRIBBON3;
+1
View File
@@ -13,6 +13,7 @@
typedef struct _CABRULER typedef struct _CABRULER
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszStyle; CHAR **hszStyle;
} CABRULER; } CABRULER;
+1
View File
@@ -9,6 +9,7 @@
typedef struct _CABRULER3 typedef struct _CABRULER3
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszStyle; CHAR **hszStyle;
} CABRULER3; } CABRULER3;
+1
View File
@@ -9,6 +9,7 @@
typedef struct _CABRUNMACRO typedef struct _CABRUNMACRO
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszName; CHAR **hszName;
BOOL fShowAll; BOOL fShowAll;
} CABRUNMACRO; } CABRUNMACRO;
-2
View File
@@ -11,7 +11,6 @@
#define tmcSortCol (tmcUserMin + 7) #define tmcSortCol (tmcUserMin + 7)
#define tmcSortCase (tmcUserMin + 8) #define tmcSortCase (tmcUserMin + 8)
#pragma pack(push, 2)
typedef struct _CABSORT typedef struct _CABSORT
{ {
CABH cabh; CABH cabh;
@@ -23,7 +22,6 @@ typedef struct _CABSORT
BOOL fSortCol; BOOL fSortCol;
BOOL fCase; BOOL fCase;
} CABSORT; } CABSORT;
#pragma pack(pop)
typedef CABSORT **HCABSORT; typedef CABSORT **HCABSORT;
#define cabiCABSORT Cabi((sizeof(CABSORT) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABSORT Cabi((sizeof(CABSORT) + sizeof(WORD) - 1) / sizeof(WORD), 0)
-2
View File
@@ -12,7 +12,6 @@
#define tmcSplIgnoreCaps (tmcUserMin + 8) #define tmcSplIgnoreCaps (tmcUserMin + 8)
#define tmcSplAutoSugg (tmcUserMin + 9) #define tmcSplAutoSugg (tmcUserMin + 9)
#pragma pack(push, 2)
typedef struct _CABSPELLER typedef struct _CABSPELLER
{ {
CABH cabh; CABH cabh;
@@ -23,7 +22,6 @@ typedef struct _CABSPELLER
BOOL fSplIgnoreCaps; BOOL fSplIgnoreCaps;
BOOL fSplAutoSugg; BOOL fSplAutoSugg;
} CABSPELLER; } CABSPELLER;
#pragma pack(pop)
typedef CABSPELLER **HCABSPELLER; typedef CABSPELLER **HCABSPELLER;
#define cabiCABSPELLER Cabi((sizeof(CABSPELLER) + sizeof(WORD) - 1) / sizeof(WORD), 3) #define cabiCABSPELLER Cabi((sizeof(CABSPELLER) + sizeof(WORD) - 1) / sizeof(WORD), 3)
+1 -2
View File
@@ -13,17 +13,16 @@
#define tmcSplMMIgnoreCaps (tmcUserMin + 9) #define tmcSplMMIgnoreCaps (tmcUserMin + 9)
#define tmcSplMMAutoSugg (tmcUserMin + 10) #define tmcSplMMAutoSugg (tmcUserMin + 10)
#pragma pack(push, 2)
typedef struct _CABSPELLERMM typedef struct _CABSPELLERMM
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszSplMMChangeTo; CHAR **hszSplMMChangeTo;
unsigned uSplMMSuggList; unsigned uSplMMSuggList;
int iSplMMAddToBox; int iSplMMAddToBox;
BOOL fSplMMIgnoreCaps; BOOL fSplMMIgnoreCaps;
BOOL fSplMMAutoSugg; BOOL fSplMMAutoSugg;
} CABSPELLERMM; } CABSPELLERMM;
#pragma pack(pop)
typedef CABSPELLERMM **HCABSPELLERMM; typedef CABSPELLERMM **HCABSPELLERMM;
#define cabiCABSPELLERMM Cabi((sizeof(CABSPELLERMM) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABSPELLERMM Cabi((sizeof(CABSPELLERMM) + sizeof(WORD) - 1) / sizeof(WORD), 1)
-2
View File
@@ -15,7 +15,6 @@
#define tmcMergeCells (tmcUserMin + 10) #define tmcMergeCells (tmcUserMin + 10)
#define tmcSplitCells (tmcUserMin + 11) #define tmcSplitCells (tmcUserMin + 11)
#pragma pack(push, 2)
typedef struct _CABEDITTABLE typedef struct _CABEDITTABLE
{ {
CABH cabh; CABH cabh;
@@ -23,7 +22,6 @@ typedef struct _CABEDITTABLE
int cmdtype; int cmdtype;
BOOL fShiftVert; BOOL fShiftVert;
} CABEDITTABLE; } CABEDITTABLE;
#pragma pack(pop)
typedef CABEDITTABLE **HCABEDITTABLE; typedef CABEDITTABLE **HCABEDITTABLE;
#define cabiCABEDITTABLE Cabi((sizeof(CABEDITTABLE) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABEDITTABLE Cabi((sizeof(CABEDITTABLE) + sizeof(WORD) - 1) / sizeof(WORD), 0)
-2
View File
@@ -25,7 +25,6 @@
#define tmcNextColumn (tmcUserMin + 20) #define tmcNextColumn (tmcUserMin + 20)
#define tmcPrevColumn (tmcUserMin + 21) #define tmcPrevColumn (tmcUserMin + 21)
#pragma pack(push, 2)
typedef struct _CABFORMATTABLE typedef struct _CABFORMATTABLE
{ {
CABH cabh; CABH cabh;
@@ -46,7 +45,6 @@ typedef struct _CABFORMATTABLE
int jc; int jc;
BOOL fWholeTable; BOOL fWholeTable;
} CABFORMATTABLE; } CABFORMATTABLE;
#pragma pack(pop)
typedef CABFORMATTABLE **HCABFORMATTABLE; typedef CABFORMATTABLE **HCABFORMATTABLE;
#define cabiCABFORMATTABLE Cabi((sizeof(CABFORMATTABLE) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABFORMATTABLE Cabi((sizeof(CABFORMATTABLE) + sizeof(WORD) - 1) / sizeof(WORD), 1)
-2
View File
@@ -10,7 +10,6 @@
#define tmcFormatComma (tmcUserMin + 6) #define tmcFormatComma (tmcUserMin + 6)
#define tmcTunnelFormat (tmcUserMin + 7) #define tmcTunnelFormat (tmcUserMin + 7)
#pragma pack(push, 2)
typedef struct _CABINSERTTABLE typedef struct _CABINSERTTABLE
{ {
CABH cabh; CABH cabh;
@@ -20,7 +19,6 @@ typedef struct _CABINSERTTABLE
int dxaWidth; int dxaWidth;
int tblfmt; int tblfmt;
} CABINSERTTABLE; } CABINSERTTABLE;
#pragma pack(pop)
typedef CABINSERTTABLE **HCABINSERTTABLE; typedef CABINSERTTABLE **HCABINSERTTABLE;
#define cabiCABINSERTTABLE Cabi((sizeof(CABINSERTTABLE) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABINSERTTABLE Cabi((sizeof(CABINSERTTABLE) + sizeof(WORD) - 1) / sizeof(WORD), 0)
-2
View File
@@ -6,14 +6,12 @@
#define tmcCommaDelim (tmcUserMin + 2) #define tmcCommaDelim (tmcUserMin + 2)
#define tmcTabDelim (tmcUserMin + 3) #define tmcTabDelim (tmcUserMin + 3)
#pragma pack(push, 2)
typedef struct _CABTABLETOTEXT typedef struct _CABTABLETOTEXT
{ {
CABH cabh; CABH cabh;
WORD sab; WORD sab;
int tblfmt; int tblfmt;
} CABTABLETOTEXT; } CABTABLETOTEXT;
#pragma pack(pop)
typedef CABTABLETOTEXT **HCABTABLETOTEXT; typedef CABTABLETOTEXT **HCABTABLETOTEXT;
#define cabiCABTABLETOTEXT Cabi((sizeof(CABTABLETOTEXT) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABTABLETOTEXT Cabi((sizeof(CABTABLETOTEXT) + sizeof(WORD) - 1) / sizeof(WORD), 0)
-2
View File
@@ -10,7 +10,6 @@
#define tmcPartOfSpeech (tmcUserMin + 6) #define tmcPartOfSpeech (tmcUserMin + 6)
#define tmcDefinition (tmcUserMin + 7) #define tmcDefinition (tmcUserMin + 7)
#pragma pack(push, 2)
typedef struct _CABTHESAURUS typedef struct _CABTHESAURUS
{ {
CABH cabh; CABH cabh;
@@ -19,7 +18,6 @@ typedef struct _CABTHESAURUS
int uSynList; int uSynList;
int uDefList; int uDefList;
} CABTHESAURUS; } CABTHESAURUS;
#pragma pack(pop)
typedef CABTHESAURUS **HCABTHESAURUS; typedef CABTHESAURUS **HCABTHESAURUS;
#define cabiCABTHESAURUS Cabi((sizeof(CABTHESAURUS) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABTHESAURUS Cabi((sizeof(CABTHESAURUS) + sizeof(WORD) - 1) / sizeof(WORD), 1)
-2
View File
@@ -11,7 +11,6 @@
#define tmcTocFrom (tmcUserMin + 5) #define tmcTocFrom (tmcUserMin + 5)
#define tmcTocTo (tmcUserMin + 6) #define tmcTocTo (tmcUserMin + 6)
#pragma pack(push, 2)
typedef struct _CABTOC typedef struct _CABTOC
{ {
CABH cabh; CABH cabh;
@@ -22,7 +21,6 @@ typedef struct _CABTOC
unsigned wTocTo; unsigned wTocTo;
BOOL fReplace; BOOL fReplace;
} CABTOC; } CABTOC;
#pragma pack(pop)
typedef CABTOC **HCABTOC; typedef CABTOC **HCABTOC;
#define cabiCABTOC Cabi((sizeof(CABTOC) + sizeof(WORD) - 1) / sizeof(WORD), 0) #define cabiCABTOC Cabi((sizeof(CABTOC) + sizeof(WORD) - 1) / sizeof(WORD), 0)
+1
View File
@@ -7,6 +7,7 @@
typedef struct _CABUSERNAME typedef struct _CABUSERNAME
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **hszName; CHAR **hszName;
CHAR **hszInitials; CHAR **hszInitials;
} CABUSERNAME; } CABUSERNAME;
+1 -2
View File
@@ -1,13 +1,12 @@
#pragma once #pragma once
/* Compile contract reconstructed from Opus/dlg/usrdlg.des. */ /* Compile contract reconstructed from Opus/dlg/usrdlg.des. */
#pragma pack(push, 2)
typedef struct _CABUSRDLG typedef struct _CABUSRDLG
{ {
CABH cabh; CABH cabh;
WORD sab;
CHAR **foo; CHAR **foo;
} CABUSRDLG; } CABUSRDLG;
#pragma pack(pop)
typedef CABUSRDLG **HCABUSRDLG; typedef CABUSRDLG **HCABUSRDLG;
#define cabiCABUSRDLG Cabi((sizeof(CABUSRDLG) + sizeof(WORD) - 1) / sizeof(WORD), 1) #define cabiCABUSRDLG Cabi((sizeof(CABUSRDLG) + sizeof(WORD) - 1) / sizeof(WORD), 1)
+1
View File
@@ -8,6 +8,7 @@
typedef struct _CABEXCR typedef struct _CABEXCR
{ {
CABH cabh; CABH cabh;
WORD sab;
int iFmt; int iFmt;
} CABEXCR; } CABEXCR;
+1 -1
View File
@@ -2,7 +2,7 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="0.1.0.0" processorArchitecture="amd64" <assemblyIdentity version="0.1.0.0" processorArchitecture="amd64"
name="Microsoft.Opus.WordX64Port" type="win32"/> name="Microsoft.Opus.WordX64Port" type="win32"/>
<description>Microsoft Word for Windows x64 port</description> <description>Microsoft Word for Windows x64 port by Justin Marshall</description>
<dependency> <dependency>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls"
-919
View File
@@ -1,919 +0,0 @@
#include "legacy_asm_port.h"
#include <Windows.h>
#include <CommCtrl.h>
#include <CommDlg.h>
#include <Richedit.h>
#include <Shellapi.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <cwctype>
#include <filesystem>
#include <limits>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
namespace {
constexpr wchar_t kWindowClass[] = L"OpusWordX64Window";
constexpr wchar_t kProductName[] = L"Microsoft Word x64 Port";
constexpr UINT_PTR kStatusTimer = 1;
enum Command : UINT {
cmd_file_new = 100,
cmd_file_open,
cmd_file_save,
cmd_file_save_as,
cmd_file_print,
cmd_file_exit,
cmd_edit_undo = 200,
cmd_edit_redo,
cmd_edit_cut,
cmd_edit_copy,
cmd_edit_paste,
cmd_edit_select_all,
cmd_edit_find,
cmd_edit_find_next,
cmd_format_bold = 300,
cmd_format_italic,
cmd_format_underline,
cmd_format_font,
cmd_format_left,
cmd_format_center,
cmd_format_right,
cmd_format_justify,
cmd_tools_word_count = 400,
cmd_help_about = 500,
};
[[nodiscard]] std::wstring system_error_message(const DWORD error) {
wchar_t* buffer = nullptr;
const DWORD count = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, error, 0, reinterpret_cast<wchar_t*>(&buffer), 0, nullptr);
std::wstring message = count != 0 && buffer != nullptr
? std::wstring(buffer, count)
: L"Unknown error (" + std::to_wstring(error) + L")";
if (buffer != nullptr) {
LocalFree(buffer);
}
while (!message.empty() && (message.back() == L'\r' || message.back() == L'\n')) {
message.pop_back();
}
return message;
}
[[nodiscard]] std::wstring lower_extension(const std::wstring& path) {
auto extension = std::filesystem::path(path).extension().wstring();
std::ranges::transform(extension, extension.begin(),
[](const wchar_t ch) { return static_cast<wchar_t>(std::towlower(ch)); });
return extension;
}
[[nodiscard]] std::vector<std::byte> read_file(const std::wstring& path) {
const HANDLE file = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) {
throw std::runtime_error("CreateFileW failed: " + std::to_string(GetLastError()));
}
LARGE_INTEGER size{};
if (!GetFileSizeEx(file, &size) || size.QuadPart < 0 ||
size.QuadPart > static_cast<LONGLONG>(std::numeric_limits<DWORD>::max())) {
const DWORD error = GetLastError();
CloseHandle(file);
throw std::runtime_error("GetFileSizeEx failed: " + std::to_string(error));
}
std::vector<std::byte> bytes(static_cast<std::size_t>(size.QuadPart));
DWORD read = 0;
const BOOL succeeded = bytes.empty() ||
ReadFile(file, bytes.data(), static_cast<DWORD>(bytes.size()), &read, nullptr);
const DWORD error = succeeded ? ERROR_SUCCESS : GetLastError();
CloseHandle(file);
if (!succeeded || read != bytes.size()) {
throw std::runtime_error("ReadFile failed: " + std::to_string(error));
}
return bytes;
}
void write_file(const std::wstring& path, const std::vector<std::byte>& bytes) {
const HANDLE file = CreateFileW(path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) {
throw std::runtime_error("CreateFileW failed: " + std::to_string(GetLastError()));
}
DWORD written = 0;
const BOOL succeeded = bytes.empty() ||
WriteFile(file, bytes.data(), static_cast<DWORD>(bytes.size()), &written, nullptr);
const DWORD error = succeeded ? ERROR_SUCCESS : GetLastError();
CloseHandle(file);
if (!succeeded || written != bytes.size()) {
throw std::runtime_error("WriteFile failed: " + std::to_string(error));
}
}
[[nodiscard]] std::wstring decode_text(const std::vector<std::byte>& bytes) {
if (bytes.size() >= 2 && bytes[0] == std::byte{0xff} && bytes[1] == std::byte{0xfe}) {
std::wstring result((bytes.size() - 2) / sizeof(wchar_t), L'\0');
std::memcpy(result.data(), bytes.data() + 2, result.size() * sizeof(wchar_t));
return result;
}
std::size_t offset = 0;
if (bytes.size() >= 3 && bytes[0] == std::byte{0xef} && bytes[1] == std::byte{0xbb} &&
bytes[2] == std::byte{0xbf}) {
offset = 3;
}
const auto* text = reinterpret_cast<const char*>(bytes.data() + offset);
const int byte_count = static_cast<int>(bytes.size() - offset);
if (byte_count == 0) {
return {};
}
UINT code_page = CP_UTF8;
DWORD flags = MB_ERR_INVALID_CHARS;
int character_count = MultiByteToWideChar(code_page, flags, text, byte_count, nullptr, 0);
if (character_count == 0) {
code_page = CP_ACP;
flags = 0;
character_count = MultiByteToWideChar(code_page, flags, text, byte_count, nullptr, 0);
}
if (character_count == 0) {
throw std::runtime_error("The text encoding could not be decoded");
}
std::wstring result(static_cast<std::size_t>(character_count), L'\0');
MultiByteToWideChar(code_page, flags, text, byte_count, result.data(), character_count);
return result;
}
[[nodiscard]] std::vector<std::byte> encode_utf8(const std::wstring_view text) {
const int byte_count = WideCharToMultiByte(CP_UTF8, 0, text.data(),
static_cast<int>(text.size()), nullptr, 0,
nullptr, nullptr);
std::vector<std::byte> result{
std::byte{0xef}, std::byte{0xbb}, std::byte{0xbf},
};
const auto initial_size = result.size();
result.resize(initial_size + static_cast<std::size_t>(byte_count));
if (byte_count != 0) {
WideCharToMultiByte(CP_UTF8, 0, text.data(), static_cast<int>(text.size()),
reinterpret_cast<char*>(result.data() + initial_size), byte_count,
nullptr, nullptr);
}
return result;
}
[[nodiscard]] HMENU build_menu() {
const HMENU menu = CreateMenu();
const HMENU file = CreatePopupMenu();
AppendMenuW(file, MF_STRING, cmd_file_new, L"&New\tCtrl+N");
AppendMenuW(file, MF_STRING, cmd_file_open, L"&Open...\tCtrl+O");
AppendMenuW(file, MF_STRING, cmd_file_save, L"&Save\tCtrl+S");
AppendMenuW(file, MF_STRING, cmd_file_save_as, L"Save &As...");
AppendMenuW(file, MF_SEPARATOR, 0, nullptr);
AppendMenuW(file, MF_STRING, cmd_file_print, L"&Print...\tCtrl+P");
AppendMenuW(file, MF_SEPARATOR, 0, nullptr);
AppendMenuW(file, MF_STRING, cmd_file_exit, L"E&xit");
AppendMenuW(menu, MF_POPUP, reinterpret_cast<UINT_PTR>(file), L"&File");
const HMENU edit = CreatePopupMenu();
AppendMenuW(edit, MF_STRING, cmd_edit_undo, L"&Undo\tCtrl+Z");
AppendMenuW(edit, MF_STRING, cmd_edit_redo, L"&Redo\tCtrl+Y");
AppendMenuW(edit, MF_SEPARATOR, 0, nullptr);
AppendMenuW(edit, MF_STRING, cmd_edit_cut, L"Cu&t\tCtrl+X");
AppendMenuW(edit, MF_STRING, cmd_edit_copy, L"&Copy\tCtrl+C");
AppendMenuW(edit, MF_STRING, cmd_edit_paste, L"&Paste\tCtrl+V");
AppendMenuW(edit, MF_STRING, cmd_edit_select_all, L"Select &All\tCtrl+A");
AppendMenuW(edit, MF_SEPARATOR, 0, nullptr);
AppendMenuW(edit, MF_STRING, cmd_edit_find, L"&Find...\tCtrl+F");
AppendMenuW(edit, MF_STRING, cmd_edit_find_next, L"Find &Next\tF3");
AppendMenuW(menu, MF_POPUP, reinterpret_cast<UINT_PTR>(edit), L"&Edit");
const HMENU format = CreatePopupMenu();
AppendMenuW(format, MF_STRING, cmd_format_bold, L"&Bold\tCtrl+B");
AppendMenuW(format, MF_STRING, cmd_format_italic, L"&Italic\tCtrl+I");
AppendMenuW(format, MF_STRING, cmd_format_underline, L"&Underline\tCtrl+U");
AppendMenuW(format, MF_STRING, cmd_format_font, L"&Font...");
AppendMenuW(format, MF_SEPARATOR, 0, nullptr);
AppendMenuW(format, MF_STRING, cmd_format_left, L"Align &Left\tCtrl+L");
AppendMenuW(format, MF_STRING, cmd_format_center, L"&Center\tCtrl+E");
AppendMenuW(format, MF_STRING, cmd_format_right, L"Align &Right\tCtrl+R");
AppendMenuW(format, MF_STRING, cmd_format_justify, L"&Justify\tCtrl+J");
AppendMenuW(menu, MF_POPUP, reinterpret_cast<UINT_PTR>(format), L"F&ormat");
const HMENU tools = CreatePopupMenu();
AppendMenuW(tools, MF_STRING, cmd_tools_word_count, L"&Word Count...");
AppendMenuW(menu, MF_POPUP, reinterpret_cast<UINT_PTR>(tools), L"&Tools");
const HMENU help = CreatePopupMenu();
AppendMenuW(help, MF_STRING, cmd_help_about, L"&About Microsoft Word x64 Port");
AppendMenuW(menu, MF_POPUP, reinterpret_cast<UINT_PTR>(help), L"&Help");
return menu;
}
class WordApplication {
public:
explicit WordApplication(const HINSTANCE instance) : instance_(instance) {}
int run(const int show_command) {
int argument_count = 0;
wchar_t** arguments = CommandLineToArgvW(GetCommandLineW(), &argument_count);
if (arguments != nullptr && argument_count > 1 &&
std::wstring_view(arguments[1]) == L"--self-test") {
std::array<std::uint8_t, 7> pattern_buffer{};
constexpr std::array<std::uint8_t, 3> pattern{1, 2, 3};
opus::x64::fill_byte_pattern(pattern_buffer.data(), pattern_buffer.size(),
pattern.data(), pattern.size());
const bool passed = opus::x64::assembly_manifest_complete() &&
opus::x64::assembly_manifest_count() == 59 &&
opus::x64::multiply_divide(10, 3, 2) == 15 &&
opus::x64::legacy_square(4.0) == 16.0 &&
pattern_buffer == std::array<std::uint8_t, 7>{1, 2, 3, 1, 2, 3, 1} &&
opus::x64::is_ascii_alphanumeric('Z') &&
opus::x64::ascii_upper('q') == 'Q';
LocalFree(arguments);
return passed ? 0 : 2;
}
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
INITCOMMONCONTROLSEX controls{sizeof(controls), ICC_BAR_CLASSES | ICC_STANDARD_CLASSES};
InitCommonControlsEx(&controls);
rich_edit_library_ = LoadLibraryW(L"Msftedit.dll");
if (rich_edit_library_ == nullptr) {
show_error(L"Microsoft Rich Edit could not be loaded", GetLastError());
if (arguments != nullptr) {
LocalFree(arguments);
}
return 1;
}
WNDCLASSEXW window_class{sizeof(window_class)};
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpfnWndProc = &WordApplication::window_proc;
window_class.hInstance = instance_;
window_class.hIcon = LoadIconW(nullptr, IDI_APPLICATION);
window_class.hCursor = LoadCursorW(nullptr, IDC_ARROW);
window_class.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_APPWORKSPACE + 1);
window_class.lpszClassName = kWindowClass;
window_class.hIconSm = window_class.hIcon;
if (RegisterClassExW(&window_class) == 0) {
show_error(L"The application window could not be registered", GetLastError());
FreeLibrary(rich_edit_library_);
if (arguments != nullptr) {
LocalFree(arguments);
}
return 1;
}
main_window_ = CreateWindowExW(
0, kWindowClass, kProductName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 1100, 800, nullptr, nullptr, instance_, this);
if (main_window_ == nullptr) {
show_error(L"The application window could not be created", GetLastError());
FreeLibrary(rich_edit_library_);
if (arguments != nullptr) {
LocalFree(arguments);
}
return 1;
}
if (arguments != nullptr && argument_count > 1 &&
std::wstring_view(arguments[1]) == L"--ui-self-test") {
SetWindowTextW(editor_, L"Word x64 UI smoke test");
const bool passed = IsWindow(main_window_) != FALSE && IsWindow(editor_) != FALSE &&
IsWindow(status_) != FALSE && GetWindowTextLengthW(editor_) == 22;
DestroyWindow(main_window_);
LocalFree(arguments);
FreeLibrary(rich_edit_library_);
return passed ? 0 : 3;
}
if (arguments != nullptr && argument_count > 1) {
open_path(arguments[1]);
}
if (arguments != nullptr) {
LocalFree(arguments);
}
ShowWindow(main_window_, show_command);
UpdateWindow(main_window_);
const std::array accelerators{
ACCEL{FVIRTKEY | FCONTROL, 'N', cmd_file_new},
ACCEL{FVIRTKEY | FCONTROL, 'O', cmd_file_open},
ACCEL{FVIRTKEY | FCONTROL, 'S', cmd_file_save},
ACCEL{FVIRTKEY | FCONTROL, 'P', cmd_file_print},
ACCEL{FVIRTKEY | FCONTROL, 'Z', cmd_edit_undo},
ACCEL{FVIRTKEY | FCONTROL, 'Y', cmd_edit_redo},
ACCEL{FVIRTKEY | FCONTROL, 'X', cmd_edit_cut},
ACCEL{FVIRTKEY | FCONTROL, 'C', cmd_edit_copy},
ACCEL{FVIRTKEY | FCONTROL, 'V', cmd_edit_paste},
ACCEL{FVIRTKEY | FCONTROL, 'A', cmd_edit_select_all},
ACCEL{FVIRTKEY | FCONTROL, 'F', cmd_edit_find},
ACCEL{FVIRTKEY, VK_F3, cmd_edit_find_next},
ACCEL{FVIRTKEY | FCONTROL, 'B', cmd_format_bold},
ACCEL{FVIRTKEY | FCONTROL, 'I', cmd_format_italic},
ACCEL{FVIRTKEY | FCONTROL, 'U', cmd_format_underline},
ACCEL{FVIRTKEY | FCONTROL, 'L', cmd_format_left},
ACCEL{FVIRTKEY | FCONTROL, 'E', cmd_format_center},
ACCEL{FVIRTKEY | FCONTROL, 'R', cmd_format_right},
ACCEL{FVIRTKEY | FCONTROL, 'J', cmd_format_justify},
};
const HACCEL accelerator_table = CreateAcceleratorTableW(
const_cast<LPACCEL>(accelerators.data()), static_cast<int>(accelerators.size()));
MSG message{};
while (GetMessageW(&message, nullptr, 0, 0) > 0) {
if (find_dialog_ != nullptr && IsDialogMessageW(find_dialog_, &message)) {
continue;
}
if (!TranslateAcceleratorW(main_window_, accelerator_table, &message)) {
TranslateMessage(&message);
DispatchMessageW(&message);
}
}
DestroyAcceleratorTable(accelerator_table);
FreeLibrary(rich_edit_library_);
return static_cast<int>(message.wParam);
}
private:
static LRESULT CALLBACK window_proc(const HWND window, const UINT message,
const WPARAM wparam, const LPARAM lparam) {
WordApplication* app = reinterpret_cast<WordApplication*>(
GetWindowLongPtrW(window, GWLP_USERDATA));
if (message == WM_NCCREATE) {
const auto* create = reinterpret_cast<const CREATESTRUCTW*>(lparam);
app = static_cast<WordApplication*>(create->lpCreateParams);
app->main_window_ = window;
SetWindowLongPtrW(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(app));
}
return app != nullptr ? app->dispatch(message, wparam, lparam)
: DefWindowProcW(window, message, wparam, lparam);
}
LRESULT dispatch(const UINT message, const WPARAM wparam, const LPARAM lparam) {
if (message == find_message_) {
on_find_message(*reinterpret_cast<const FINDREPLACEW*>(lparam));
return 0;
}
switch (message) {
case WM_CREATE:
return create_children() ? 0 : -1;
case WM_SIZE:
layout(LOWORD(lparam), HIWORD(lparam));
return 0;
case WM_SETFOCUS:
SetFocus(editor_);
return 0;
case WM_COMMAND:
if (reinterpret_cast<HWND>(lparam) == editor_ && HIWORD(wparam) == EN_CHANGE) {
status_dirty_ = true;
update_title();
return 0;
}
execute_command(LOWORD(wparam));
return 0;
case WM_NOTIFY:
if (reinterpret_cast<const NMHDR*>(lparam)->hwndFrom == editor_) {
status_dirty_ = true;
}
return 0;
case WM_INITMENU:
update_menu(reinterpret_cast<HMENU>(wparam));
return 0;
case WM_TIMER:
if (wparam == kStatusTimer && status_dirty_) {
update_status();
}
return 0;
case WM_DROPFILES:
open_drop(reinterpret_cast<HDROP>(wparam));
return 0;
case WM_CLOSE:
if (prompt_save_changes()) {
DestroyWindow(main_window_);
}
return 0;
case WM_DESTROY:
KillTimer(main_window_, kStatusTimer);
PostQuitMessage(0);
return 0;
default:
return DefWindowProcW(main_window_, message, wparam, lparam);
}
}
bool create_children() {
SetMenu(main_window_, build_menu());
editor_ = CreateWindowExW(
WS_EX_CLIENTEDGE, MSFTEDIT_CLASS, L"",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_WANTRETURN |
ES_NOHIDESEL | ES_AUTOVSCROLL,
0, 0, 0, 0, main_window_, reinterpret_cast<HMENU>(1), instance_, nullptr);
status_ = CreateWindowExW(0, STATUSCLASSNAMEW, nullptr, WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, main_window_, reinterpret_cast<HMENU>(2),
instance_, nullptr);
if (editor_ == nullptr || status_ == nullptr) {
return false;
}
SendMessageW(editor_, EM_SETEVENTMASK, 0, ENM_CHANGE | ENM_SELCHANGE);
SendMessageW(editor_, EM_SETBKGNDCOLOR, 0, RGB(255, 255, 255));
SendMessageW(editor_, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(16, 16));
SendMessageW(editor_, EM_EXLIMITTEXT, 0, std::numeric_limits<LONG>::max());
CHARFORMAT2W format{sizeof(format)};
format.dwMask = CFM_FACE | CFM_SIZE | CFM_CHARSET;
format.yHeight = 220;
format.bCharSet = DEFAULT_CHARSET;
wcscpy_s(format.szFaceName, L"Segoe UI");
SendMessageW(editor_, EM_SETCHARFORMAT, SCF_ALL, reinterpret_cast<LPARAM>(&format));
find_message_ = RegisterWindowMessageW(FINDMSGSTRINGW);
DragAcceptFiles(main_window_, TRUE);
SetTimer(main_window_, kStatusTimer, 250, nullptr);
set_clean();
update_status();
SetFocus(editor_);
return true;
}
void layout(const int width, const int height) {
SendMessageW(status_, WM_SIZE, 0, 0);
RECT status_rect{};
GetWindowRect(status_, &status_rect);
const int status_height = status_rect.bottom - status_rect.top;
MoveWindow(editor_, 0, 0, width, std::max(0, height - status_height), TRUE);
const int parts[]{std::max(200, width - 330), std::max(320, width - 150), -1};
SendMessageW(status_, SB_SETPARTS, std::size(parts), reinterpret_cast<LPARAM>(parts));
status_dirty_ = true;
}
void execute_command(const UINT command) {
switch (command) {
case cmd_file_new: new_document(); break;
case cmd_file_open: open_dialog(); break;
case cmd_file_save: save(false); break;
case cmd_file_save_as: save(true); break;
case cmd_file_print: print_document(); break;
case cmd_file_exit: SendMessageW(main_window_, WM_CLOSE, 0, 0); break;
case cmd_edit_undo: SendMessageW(editor_, EM_UNDO, 0, 0); break;
case cmd_edit_redo: SendMessageW(editor_, EM_REDO, 0, 0); break;
case cmd_edit_cut: SendMessageW(editor_, WM_CUT, 0, 0); break;
case cmd_edit_copy: SendMessageW(editor_, WM_COPY, 0, 0); break;
case cmd_edit_paste: SendMessageW(editor_, WM_PASTE, 0, 0); break;
case cmd_edit_select_all: SendMessageW(editor_, EM_SETSEL, 0, -1); break;
case cmd_edit_find: show_find(); break;
case cmd_edit_find_next: find_next(find_flags_); break;
case cmd_format_bold: toggle_effect(CFM_BOLD, CFE_BOLD); break;
case cmd_format_italic: toggle_effect(CFM_ITALIC, CFE_ITALIC); break;
case cmd_format_underline: toggle_effect(CFM_UNDERLINE, CFE_UNDERLINE); break;
case cmd_format_font: choose_font(); break;
case cmd_format_left: set_alignment(PFA_LEFT); break;
case cmd_format_center: set_alignment(PFA_CENTER); break;
case cmd_format_right: set_alignment(PFA_RIGHT); break;
case cmd_format_justify: set_alignment(PFA_JUSTIFY); break;
case cmd_tools_word_count: show_word_count(); break;
case cmd_help_about: show_about(); break;
default: break;
}
status_dirty_ = true;
}
void update_menu(const HMENU menu) const {
const bool can_undo = SendMessageW(editor_, EM_CANUNDO, 0, 0) != 0;
const bool can_redo = SendMessageW(editor_, EM_CANREDO, 0, 0) != 0;
CHARRANGE selection{};
SendMessageW(editor_, EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&selection));
EnableMenuItem(menu, cmd_edit_undo, MF_BYCOMMAND | (can_undo ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(menu, cmd_edit_redo, MF_BYCOMMAND | (can_redo ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(menu, cmd_edit_cut,
MF_BYCOMMAND | (selection.cpMin != selection.cpMax ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(menu, cmd_edit_copy,
MF_BYCOMMAND | (selection.cpMin != selection.cpMax ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(menu, cmd_edit_paste,
MF_BYCOMMAND | (SendMessageW(editor_, EM_CANPASTE, 0, 0) ? MF_ENABLED : MF_GRAYED));
}
void new_document() {
if (!prompt_save_changes()) {
return;
}
loading_ = true;
SetWindowTextW(editor_, L"");
current_path_.clear();
loading_ = false;
set_clean();
}
void open_dialog() {
if (!prompt_save_changes()) {
return;
}
std::array<wchar_t, 32768> path{};
OPENFILENAMEW dialog{sizeof(dialog)};
dialog.hwndOwner = main_window_;
dialog.lpstrFilter = L"Rich Text Format (*.rtf)\0*.rtf\0Text files (*.txt)\0*.txt\0All files (*.*)\0*.*\0";
dialog.lpstrFile = path.data();
dialog.nMaxFile = static_cast<DWORD>(path.size());
dialog.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
if (GetOpenFileNameW(&dialog)) {
open_path(path.data());
}
}
void open_drop(const HDROP drop) {
std::array<wchar_t, 32768> path{};
if (DragQueryFileW(drop, 0, path.data(), static_cast<UINT>(path.size())) != 0 &&
prompt_save_changes()) {
open_path(path.data());
}
DragFinish(drop);
}
void open_path(const std::wstring& path) {
if (lower_extension(path) == L".doc") {
MessageBoxW(main_window_,
L"The native x64 document engine does not read binary Word 1.x .doc files yet. "
L"Open an RTF or text document for this migration milestone.",
kProductName, MB_OK | MB_ICONINFORMATION);
return;
}
try {
loading_ = true;
if (lower_extension(path) == L".rtf") {
const HANDLE file = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) {
throw std::runtime_error("CreateFileW failed: " + std::to_string(GetLastError()));
}
EDITSTREAM stream{reinterpret_cast<DWORD_PTR>(file), 0, &stream_in};
SetWindowTextW(editor_, L"");
SendMessageW(editor_, EM_STREAMIN, SF_RTF, reinterpret_cast<LPARAM>(&stream));
CloseHandle(file);
if (stream.dwError != 0) {
throw std::runtime_error("Rich Edit could not read the RTF stream");
}
} else {
const auto text = decode_text(read_file(path));
SetWindowTextW(editor_, text.c_str());
}
current_path_ = path;
loading_ = false;
set_clean();
} catch (const std::exception& error) {
loading_ = false;
const std::wstring detail(error.what(), error.what() + std::strlen(error.what()));
MessageBoxW(main_window_, (L"Could not open the document.\n\n" + detail).c_str(),
kProductName, MB_OK | MB_ICONERROR);
}
}
bool save(const bool save_as) {
std::wstring path = current_path_;
if (save_as || path.empty()) {
std::array<wchar_t, 32768> selected{};
if (!path.empty()) {
wcsncpy_s(selected.data(), selected.size(), path.c_str(), _TRUNCATE);
} else {
wcscpy_s(selected.data(), selected.size(), L"Document.rtf");
}
OPENFILENAMEW dialog{sizeof(dialog)};
dialog.hwndOwner = main_window_;
dialog.lpstrFilter = L"Rich Text Format (*.rtf)\0*.rtf\0UTF-8 text (*.txt)\0*.txt\0";
dialog.lpstrFile = selected.data();
dialog.nMaxFile = static_cast<DWORD>(selected.size());
dialog.lpstrDefExt = L"rtf";
dialog.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
if (!GetSaveFileNameW(&dialog)) {
return false;
}
path = selected.data();
}
try {
if (lower_extension(path) == L".rtf") {
const HANDLE file = CreateFileW(path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (file == INVALID_HANDLE_VALUE) {
throw std::runtime_error("CreateFileW failed: " + std::to_string(GetLastError()));
}
EDITSTREAM stream{reinterpret_cast<DWORD_PTR>(file), 0, &stream_out};
SendMessageW(editor_, EM_STREAMOUT, SF_RTF, reinterpret_cast<LPARAM>(&stream));
CloseHandle(file);
if (stream.dwError != 0) {
throw std::runtime_error("Rich Edit could not write the RTF stream");
}
} else {
write_file(path, encode_utf8(document_text()));
}
current_path_ = path;
set_clean();
return true;
} catch (const std::exception& error) {
const std::wstring detail(error.what(), error.what() + std::strlen(error.what()));
MessageBoxW(main_window_, (L"Could not save the document.\n\n" + detail).c_str(),
kProductName, MB_OK | MB_ICONERROR);
return false;
}
}
bool prompt_save_changes() {
if (SendMessageW(editor_, EM_GETMODIFY, 0, 0) == 0) {
return true;
}
const int answer = MessageBoxW(main_window_, L"Save changes to this document?",
kProductName, MB_YESNOCANCEL | MB_ICONQUESTION);
return answer == IDNO || (answer == IDYES && save(false));
}
void set_clean() {
SendMessageW(editor_, EM_SETMODIFY, FALSE, 0);
update_title();
status_dirty_ = true;
}
void update_title() const {
std::wstring name = current_path_.empty()
? L"Document"
: std::filesystem::path(current_path_).filename().wstring();
if (!loading_ && SendMessageW(editor_, EM_GETMODIFY, 0, 0) != 0) {
name += L" *";
}
SetWindowTextW(main_window_, (name + L" - " + kProductName).c_str());
}
[[nodiscard]] std::wstring document_text() const {
const int length = GetWindowTextLengthW(editor_);
std::wstring text(static_cast<std::size_t>(length) + 1, L'\0');
if (length != 0) {
GetWindowTextW(editor_, text.data(), length + 1);
}
text.resize(static_cast<std::size_t>(length));
return text;
}
[[nodiscard]] static std::pair<std::size_t, std::size_t> count_text(
const std::wstring_view text) {
std::size_t words = 0;
std::size_t characters = 0;
bool in_word = false;
for (const wchar_t character : text) {
if (character != L'\r' && character != L'\n') {
++characters;
}
const bool word_character = std::iswalnum(character) != 0 || character == L'_';
if (word_character && !in_word) {
++words;
}
in_word = word_character;
}
return {words, characters};
}
void update_status() {
const auto text = document_text();
const auto [words, characters] = count_text(text);
CHARRANGE selection{};
SendMessageW(editor_, EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&selection));
const LRESULT line = SendMessageW(editor_, EM_LINEFROMCHAR, selection.cpMin, 0);
const LRESULT line_start = SendMessageW(editor_, EM_LINEINDEX, line, 0);
const std::wstring file = current_path_.empty() ? L" New document" : L" " + current_path_;
const std::wstring counts = L"Words: " + std::to_wstring(words) +
L" Characters: " + std::to_wstring(characters);
const std::wstring position = L"Ln " + std::to_wstring(line + 1) +
L", Col " + std::to_wstring(selection.cpMin - line_start + 1);
SendMessageW(status_, SB_SETTEXTW, 0, reinterpret_cast<LPARAM>(file.c_str()));
SendMessageW(status_, SB_SETTEXTW, 1, reinterpret_cast<LPARAM>(counts.c_str()));
SendMessageW(status_, SB_SETTEXTW, 2, reinterpret_cast<LPARAM>(position.c_str()));
status_dirty_ = false;
}
void show_word_count() const {
const auto [words, characters] = count_text(document_text());
const std::wstring message = L"Words: " + std::to_wstring(words) +
L"\nCharacters (excluding paragraph marks): " +
std::to_wstring(characters);
MessageBoxW(main_window_, message.c_str(), L"Word Count", MB_OK | MB_ICONINFORMATION);
}
void toggle_effect(const DWORD mask, const DWORD effect) const {
CHARFORMAT2W format{sizeof(format)};
format.dwMask = mask;
SendMessageW(editor_, EM_GETCHARFORMAT, SCF_SELECTION, reinterpret_cast<LPARAM>(&format));
format.dwEffects ^= effect;
SendMessageW(editor_, EM_SETCHARFORMAT, SCF_SELECTION, reinterpret_cast<LPARAM>(&format));
}
void set_alignment(const WORD alignment) const {
PARAFORMAT2 format{sizeof(format)};
format.dwMask = PFM_ALIGNMENT;
format.wAlignment = alignment;
SendMessageW(editor_, EM_SETPARAFORMAT, 0, reinterpret_cast<LPARAM>(&format));
}
void choose_font() const {
CHARFORMAT2W current{sizeof(current)};
SendMessageW(editor_, EM_GETCHARFORMAT, SCF_SELECTION, reinterpret_cast<LPARAM>(&current));
HDC dc = GetDC(editor_);
LOGFONTW font{};
font.lfHeight = -MulDiv(current.yHeight / 20, GetDeviceCaps(dc, LOGPIXELSY), 72);
font.lfWeight = (current.dwEffects & CFE_BOLD) != 0 ? FW_BOLD : FW_NORMAL;
font.lfItalic = (current.dwEffects & CFE_ITALIC) != 0;
font.lfUnderline = (current.dwEffects & CFE_UNDERLINE) != 0;
wcsncpy_s(font.lfFaceName, current.szFaceName, _TRUNCATE);
ReleaseDC(editor_, dc);
CHOOSEFONTW dialog{sizeof(dialog)};
dialog.hwndOwner = main_window_;
dialog.lpLogFont = &font;
dialog.iPointSize = current.yHeight / 2;
dialog.rgbColors = current.crTextColor;
dialog.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_EFFECTS;
if (!ChooseFontW(&dialog)) {
return;
}
CHARFORMAT2W selected{sizeof(selected)};
selected.dwMask = CFM_FACE | CFM_SIZE | CFM_COLOR | CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
selected.yHeight = dialog.iPointSize * 2;
selected.crTextColor = dialog.rgbColors;
selected.dwEffects = (font.lfWeight >= FW_BOLD ? CFE_BOLD : 0) |
(font.lfItalic ? CFE_ITALIC : 0) |
(font.lfUnderline ? CFE_UNDERLINE : 0);
wcsncpy_s(selected.szFaceName, font.lfFaceName, _TRUNCATE);
SendMessageW(editor_, EM_SETCHARFORMAT, SCF_SELECTION, reinterpret_cast<LPARAM>(&selected));
}
void show_find() {
if (find_dialog_ != nullptr) {
SetForegroundWindow(find_dialog_);
return;
}
find_state_ = {};
find_state_.lStructSize = sizeof(find_state_);
find_state_.hwndOwner = main_window_;
find_state_.Flags = FR_DOWN;
find_state_.lpstrFindWhat = find_text_.data();
find_state_.wFindWhatLen = static_cast<WORD>(find_text_.size());
find_dialog_ = FindTextW(&find_state_);
}
void on_find_message(const FINDREPLACEW& message) {
if ((message.Flags & FR_DIALOGTERM) != 0) {
find_dialog_ = nullptr;
return;
}
if ((message.Flags & FR_FINDNEXT) != 0) {
find_flags_ = message.Flags;
find_next(message.Flags);
}
}
void find_next(const DWORD flags) {
if (find_text_[0] == L'\0') {
show_find();
return;
}
CHARRANGE selection{};
SendMessageW(editor_, EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&selection));
const LONG text_length = GetWindowTextLengthW(editor_);
FINDTEXTEXW search{};
search.lpstrText = find_text_.data();
const bool down = (flags & FR_DOWN) != 0;
search.chrg = down ? CHARRANGE{selection.cpMax, text_length}
: CHARRANGE{selection.cpMin - 1, 0};
DWORD options = down ? FR_DOWN : 0;
options |= flags & (FR_MATCHCASE | FR_WHOLEWORD);
LRESULT result = SendMessageW(editor_, EM_FINDTEXTEXW, options,
reinterpret_cast<LPARAM>(&search));
if (result == -1) {
search.chrg = down ? CHARRANGE{0, text_length} : CHARRANGE{text_length, 0};
result = SendMessageW(editor_, EM_FINDTEXTEXW, options,
reinterpret_cast<LPARAM>(&search));
}
if (result == -1) {
MessageBeep(MB_ICONINFORMATION);
return;
}
SendMessageW(editor_, EM_EXSETSEL, 0, reinterpret_cast<LPARAM>(&search.chrgText));
SendMessageW(editor_, EM_SCROLLCARET, 0, 0);
SetFocus(editor_);
}
void print_document() const {
PRINTDLGW dialog{sizeof(dialog)};
dialog.hwndOwner = main_window_;
dialog.Flags = PD_RETURNDC | PD_NOSELECTION | PD_USEDEVMODECOPIESANDCOLLATE;
if (!PrintDlgW(&dialog)) {
return;
}
DOCINFOW document{sizeof(document)};
document.lpszDocName = current_path_.empty() ? L"Document" : current_path_.c_str();
if (StartDocW(dialog.hDC, &document) <= 0) {
DeleteDC(dialog.hDC);
return;
}
FORMATRANGE range{};
range.hdc = dialog.hDC;
range.hdcTarget = dialog.hDC;
const int dpi_x = GetDeviceCaps(dialog.hDC, LOGPIXELSX);
const int dpi_y = GetDeviceCaps(dialog.hDC, LOGPIXELSY);
range.rcPage = {0, 0,
MulDiv(GetDeviceCaps(dialog.hDC, PHYSICALWIDTH), 1440, dpi_x),
MulDiv(GetDeviceCaps(dialog.hDC, PHYSICALHEIGHT), 1440, dpi_y)};
constexpr LONG margin = 1080;
range.rc = {range.rcPage.left + margin, range.rcPage.top + margin,
range.rcPage.right - margin, range.rcPage.bottom - margin};
range.chrg = {0, -1};
LONG next = 0;
const LONG length = GetWindowTextLengthW(editor_);
bool failed = false;
while (next < length && !failed) {
if (StartPage(dialog.hDC) <= 0) {
failed = true;
break;
}
range.chrg.cpMin = next;
next = static_cast<LONG>(SendMessageW(editor_, EM_FORMATRANGE, TRUE,
reinterpret_cast<LPARAM>(&range)));
if (EndPage(dialog.hDC) <= 0 || next <= range.chrg.cpMin) {
failed = true;
}
}
SendMessageW(editor_, EM_FORMATRANGE, FALSE, 0);
failed ? AbortDoc(dialog.hDC) : EndDoc(dialog.hDC);
DeleteDC(dialog.hDC);
}
void show_about() const {
const std::wstring message =
L"Microsoft Word for Windows — native x64 migration\n\n"
L"This executable is AMD64 and contains no 16-bit assembly.\n"
L"Legacy assembly modules accounted for: " +
std::to_wstring(opus::x64::assembly_manifest_count()) +
L"\n\nCurrent document formats: RTF and UTF-8 text.";
MessageBoxW(main_window_, message.c_str(), L"About", MB_OK | MB_ICONINFORMATION);
}
static DWORD CALLBACK stream_in(const DWORD_PTR cookie, const LPBYTE buffer,
const LONG byte_count, LONG* bytes_read) {
DWORD read = 0;
if (!ReadFile(reinterpret_cast<HANDLE>(cookie), buffer,
static_cast<DWORD>(byte_count), &read, nullptr)) {
*bytes_read = 0;
return GetLastError();
}
*bytes_read = static_cast<LONG>(read);
return 0;
}
static DWORD CALLBACK stream_out(const DWORD_PTR cookie, const LPBYTE buffer,
const LONG byte_count, LONG* bytes_written) {
DWORD written = 0;
if (!WriteFile(reinterpret_cast<HANDLE>(cookie), buffer,
static_cast<DWORD>(byte_count), &written, nullptr)) {
*bytes_written = 0;
return GetLastError();
}
*bytes_written = static_cast<LONG>(written);
return 0;
}
void show_error(const std::wstring_view message, const DWORD error) const {
const std::wstring detail = std::wstring(message) + L".\n\n" + system_error_message(error);
MessageBoxW(main_window_, detail.c_str(), kProductName, MB_OK | MB_ICONERROR);
}
HINSTANCE instance_{};
HMODULE rich_edit_library_{};
HWND main_window_{};
HWND editor_{};
HWND status_{};
HWND find_dialog_{};
UINT find_message_{};
FINDREPLACEW find_state_{};
std::array<wchar_t, 256> find_text_{};
DWORD find_flags_{FR_DOWN};
std::wstring current_path_;
bool loading_{};
bool status_dirty_{true};
};
} // namespace
int WINAPI wWinMain(const HINSTANCE instance, HINSTANCE, PWSTR, const int show_command) {
WordApplication application(instance);
return application.run(show_command);
}
-35
View File
@@ -1,35 +0,0 @@
#include <windows.h>
1 RT_MANIFEST "winword.manifest"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,1,0,0
PRODUCTVERSION 0,1,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Microsoft (historical source)"
VALUE "FileDescription", "Microsoft Word for Windows x64 port"
VALUE "FileVersion", "0.1.0"
VALUE "InternalName", "WINWORD"
VALUE "OriginalFilename", "WINWORD_BOOTSTRAP.exe"
VALUE "ProductName", "Microsoft Word x64 Port"
VALUE "ProductVersion", "0.1.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1200
END
END