mirror of
https://github.com/jmarshall23/msword.git
synced 2026-08-11 23:50:53 +02:00
Fixed memory alignment bugs.
Fixed numerous display issues. Fixed numerous windows messaging issues.
This commit is contained in:
+88
-72
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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++;
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
typedef struct _CABINSBOOKMARK
|
typedef struct _CABINSBOOKMARK
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
CHAR **hszBkmkName;
|
CHAR **hszBkmkName;
|
||||||
} CABINSBOOKMARK;
|
} CABINSBOOKMARK;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
typedef struct _CABCHGPR
|
typedef struct _CABCHGPR
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
CHAR **hszLb;
|
CHAR **hszLb;
|
||||||
} CABCHGPR;
|
} CABCHGPR;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
typedef struct _CABCONFIRMREPL
|
typedef struct _CABCONFIRMREPL
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
BOOL fConfirm;
|
BOOL fConfirm;
|
||||||
} CABCONFIRMREPL;
|
} CABCONFIRMREPL;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
typedef struct _CABGOTO
|
typedef struct _CABGOTO
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
CHAR **hszGoto;
|
CHAR **hszGoto;
|
||||||
} CABGOTO;
|
} CABGOTO;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
typedef struct _CABINSBREAK
|
typedef struct _CABINSBREAK
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
int iType;
|
int iType;
|
||||||
} CABINSBREAK;
|
} CABINSBREAK;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
typedef struct _CABNEWOPEN
|
typedef struct _CABNEWOPEN
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
CHAR **hszFileName;
|
CHAR **hszFileName;
|
||||||
} CABNEWOPEN;
|
} CABNEWOPEN;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
};
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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) &&
|
||||||
|
|||||||
@@ -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 &&
|
||||||
|
|||||||
@@ -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__);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
typedef struct _CABFILEPSWD
|
typedef struct _CABFILEPSWD
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
CHAR **hszPswd;
|
CHAR **hszPswd;
|
||||||
} CABFILEPSWD;
|
} CABFILEPSWD;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
typedef struct _CABRULER
|
typedef struct _CABRULER
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
CHAR **hszStyle;
|
CHAR **hszStyle;
|
||||||
} CABRULER;
|
} CABRULER;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
typedef struct _CABRULER3
|
typedef struct _CABRULER3
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
CHAR **hszStyle;
|
CHAR **hszStyle;
|
||||||
} CABRULER3;
|
} CABRULER3;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,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)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
typedef struct _CABEXCR
|
typedef struct _CABEXCR
|
||||||
{
|
{
|
||||||
CABH cabh;
|
CABH cabh;
|
||||||
|
WORD sab;
|
||||||
int iFmt;
|
int iFmt;
|
||||||
} CABEXCR;
|
} CABEXCR;
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>(¤t));
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user