Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
mwg_add_runtime_data_target()

add_subdirectory(src/MapWinGIS.Core)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Suggestion | Confidence: Medium

Issue: The ActiveX subdirectory is added unconditionally, and mwg_add_midl_target hard-FATAL_ERRORs configure when midl.exe or a cl.exe on PATH is missing. There is no way to configure a Core-only CMake build.
Impact: Consumers who only want MapWinGIS.Core.dll (headless Core CI, documentation or packaging jobs, contributors without the ATL/MIDL components installed) cannot configure the project at all, even though the Core target has no MIDL dependency.
Fix: Add an option(MWG_BUILD_ACTIVEX "Build the ActiveX control (requires the Windows SDK MIDL and ATL)" ON) and gate this add_subdirectory (and document the option in docs/BUILDING.md) on it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Suggestion | Confidence: High

Issue: Nothing in CI exercises the new CMake build. .github/workflows/build.yml runs only the MSBuild .slnx build (plus tests); all the CMake verification in this PR (parity script, Ninja/VS-generator builds, regsvr32 round-trip) was run manually.
Impact: The entire value of this migration stack is "no lost flags / no new warnings", which is currently only guaranteed by a script a human has to remember to run. A future PR can quietly break the CMake build or the parity guarantee and CI stays green.
Fix: Add a cmake job to build.yml (e.g. Ninja x64 Debug configure + build + run Compare-CompileCommands.ps1 once the baseline is committed), so the parity guarantee is enforced on every PR.

add_subdirectory(src/MapWinGIS.ActiveX)
65 changes: 46 additions & 19 deletions build/scripts/Compare-CompileCommands.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ $explainedLinkDifferences = [ordered]@{
'^lib:<vcpkg_installed>/' = 'Library from an imported target (find_package)'
'^lib:odbc(cp)?32\.lib$' = 'MSBuild default library; unused, not in CMake''s default list'
'^/version:0\.0$' = 'CMake default image version; MSBuild leaves it at 0.0 too'
'^input:.*\.res$' = 'Compiled resource file name (<name>.rc.res in CMake)'
'^lib:(<builddir>/)?lib[\\/]mapwingis\.core\.lib$' = 'Core import library from target_link_libraries (MSBuild: project reference)'
}

# Compile differences that are deliberate (docs/CMAKE-MIGRATION.md).
$explainedCompileDifferences = [ordered]@{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Minor | Confidence: Medium

Issue: $explainedCompileDifferences is applied to every target indiscriminately. For example, '^/I<vcpkg_installed>/[^/]+/include$' would also reclassify a genuinely lost vcpkg include for a target that should have it (Core, or the OCX if it ever gains a direct vcpkg dependency) as "explained", and the same applies to /DGDAL_DEBUG.
Impact: The parity script is the quality gate of the whole migration; a too-broad pattern can silently downgrade a real regression from "lost" to "explained", which is exactly where regressions would show up once targets or dependencies change.
Fix: Key the explained compile patterns per binary/target (like a $explainedCompileDifferencesByTarget map), or at least add a per-pattern target allow-list, so an option is only explained for the targets where the difference is expected.

'^/I<intdir>$' = 'MIDL output moved from the intermediate directory to <build>/.../midl (D3)'
'^/I<builddir>/.*/midl$' = 'MIDL output directory (D3)'
'^/I<vcpkg_installed>/[^/]+/include$' = 'vcpkg auto-include; targets without a vcpkg dependency do not get it, the others get it from imported targets'
'^/I<vcpkg_installed>/[^/]+/include/geos$' = 'Interface include directory of GEOS::geos_c'
'^/DGDAL_DEBUG$' = 'Interface definition of the debug GDAL::GDAL'
}

# MSBuild project names that differ from the CMake target names.
Expand Down Expand Up @@ -290,7 +301,7 @@ function Read-MSBuildCommands([string] $logPath, [string] $binDir) {
$set = ConvertTo-OptionSet $arguments $baseDir $placeholders @('.c', '.cpp', '.cxx', '.cc')
foreach ($source in $set.Sources) {
# Keyed by target: the tests compile some ActiveX sources a second time.
$compiles["$target $source"] = [pscustomobject]@{
$compiles[(Get-SourceKey $target $source)] = [pscustomobject]@{
Target = $target
Source = $source
Options = Merge-VcpkgPlatform $set.Options
Expand Down Expand Up @@ -327,6 +338,8 @@ function Read-CMakeCommands([string] $buildDir, [string] $logPath, [string] $bin
}

foreach ($entry in (Get-Content -Raw -LiteralPath $database | ConvertFrom-Json)) {
# Resource compiles are in the database too; the MSBuild side has only cl.exe.
if ($entry.file -match '\.rc$') { continue }
$arguments = if ($entry.arguments) { @($entry.arguments | Select-Object -Skip 1) }
else { @(Split-CommandLine $entry.command | Select-Object -Skip 1) }
$fo = $arguments | Where-Object { $_ -match '^[/-]Fo' } | Select-Object -First 1
Expand All @@ -335,7 +348,7 @@ function Read-CMakeCommands([string] $buildDir, [string] $logPath, [string] $bin
$set = ConvertTo-OptionSet $arguments $entry.directory $placeholders @('.c', '.cpp', '.cxx', '.cc')
$source = Get-NormalizedPath $entry.file $entry.directory $placeholders
$target = if ($intDir -match '\\CMakeFiles\\(?<t>[^\\]+)\.dir') { $Matches['t'] } else { '' }
$compiles["$target $source"] = [pscustomobject]@{
$compiles[(Get-SourceKey $target $source)] = [pscustomobject]@{
Target = $target
Source = $source
Options = Merge-VcpkgPlatform $set.Options
Expand Down Expand Up @@ -407,6 +420,31 @@ function Compare-OptionSets($reference, $actual) {
return [pscustomobject]@{ Lost = $lost; Added = $added }
}

# Moves the differences that match a pattern into 'Explained', with the reason.
function Split-ExplainedDifferences($diff, $patterns) {
$explained = [ordered]@{}
$lost = @(); $added = @()
foreach ($pair in @(@{ Items = $diff.Lost; Kind = 'lost' }, @{ Items = $diff.Added; Kind = 'added' })) {
foreach ($option in $pair.Items) {
$reason = $null
foreach ($pattern in $patterns.Keys) {
if ($option -match $pattern) { $reason = $patterns[$pattern]; break }
}
if ($reason) { $explained["$($pair.Kind) $option"] = $reason }
elseif ($pair.Kind -eq 'lost') { $lost += $option }
else { $added += $option }
}
}
return [pscustomobject]@{ Lost = $lost; Added = $added; Explained = $explained }
}

# MIDL output lives in different directories in the two builds (D3); key the
# generated sources by file name.
function Get-SourceKey([string] $target, [string] $source) {
if ($source -match '^<(intdir|builddir)>/(?:.*/)?(?<file>[^/]+_i\.c)$') { $source = "<generated>/$($Matches['file'])" }
return "$target $source"
}

# --- MSBuild baseline ------------------------------------------------------

if (-not $MSBuildBinDirectory) {
Expand Down Expand Up @@ -462,8 +500,9 @@ if ($CMakeBuildDir) {
}
$diff = Compare-OptionSets $reference.Options $actual.Options
if ($diff.Lost.Count -or $diff.Added.Count) {
$compileDiff[$key] = $diff
$lostTotal += $diff.Lost.Count
$split = Split-ExplainedDifferences $diff $explainedCompileDifferences
$compileDiff[$key] = $split
$lostTotal += $split.Lost.Count
}
}
foreach ($key in ($cmakeCommands.Compiles.Keys | Where-Object { -not $msbuildCommands.Compiles.ContainsKey($_) })) {
Expand All @@ -482,22 +521,10 @@ if ($CMakeBuildDir) {
continue
}
$diff = Compare-OptionSets $msbuildCommands.Links[$binary] $cmakeCommands.Links[$binary]
$explained = [ordered]@{}
$lost = @(); $added = @()
foreach ($pair in @(@{ Items = $diff.Lost; Kind = 'lost' }, @{ Items = $diff.Added; Kind = 'added' })) {
foreach ($option in $pair.Items) {
$reason = $null
foreach ($pattern in $explainedLinkDifferences.Keys) {
if ($option -match $pattern) { $reason = $explainedLinkDifferences[$pattern]; break }
}
if ($reason) { $explained["$($pair.Kind) $option"] = $reason }
elseif ($pair.Kind -eq 'lost') { $lost += $option }
else { $added += $option }
}
}
if ($diff.Lost.Count -or $diff.Added.Count) {
$linkDiff[$binary] = [pscustomobject]@{ Lost = $lost; Added = $added; Explained = $explained }
$lostTotal += $lost.Count
$split = Split-ExplainedDifferences $diff $explainedLinkDifferences
$linkDiff[$binary] = $split
$lostTotal += $split.Lost.Count
}
}

Expand Down
2 changes: 2 additions & 0 deletions cmake/MwgCompilerOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ function(mwg_apply_common_options target)
"$<${c_cxx}:/utf-8;/Zc:__cplusplus;/Zc:preprocessor;/Zc:throwingNew;/bigobj>"
# ConformanceMode, SDLCheck, ExceptionHandling and MSBuild defaults
"$<${c_cxx}:/permissive-;/sdl;/EHsc;/GS;/Gd;/Gm-;/fp:precise;/Zc:wchar_t;/Zc:forScope;/Zc:inline>"
# CMake passes /TP for C++ but not /TC for C (the MIDL _i.c).
"$<$<COMPILE_LANGUAGE:C>:/TC>"
"$<${debug}:/Od;/JMC>"
"$<${release}:/O2;/Oi;/Gy;/guard:cf>"
)
Expand Down
111 changes: 111 additions & 0 deletions cmake/MwgMidl.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# SPDX-License-Identifier: MPL-2.0
#
# mwg_add_midl_target(<target> IDL <file.idl> [OUTPUT_DIR <dir>] [DEPENDS <file>...])
#
# Runs midl.exe through one explicit custom command for every generator (only
# the Visual Studio generators understand .idl sources), see
# docs/CMAKE-MIGRATION.md (D3). Creates:
#
# <target> custom target that owns the MIDL invocation
# <target>.Generated INTERFACE library: the MIDL output include directory,
# for the OCX and the tests
#
# and sets, in the caller's scope:
# <target>_HEADER <name>_i.h
# <target>_IID <name>_i.c (C, compile with the consumer)
# <target>_TLB <name>.tlb
# <target>_DIR output directory
#
# The options match the MSBuild Midl task: /W1 /char signed /env x64|win32
# /target "NT60". This IDL declares no non-automation interfaces, so MIDL
# writes no proxy or dlldata file; they are redirected into the output
# directory anyway and are not declared as outputs.

function(_mwg_find_midl out_var)
# The MSBuild Midl task uses the SDK's x86 midl.exe; any host build works.
set(hints "")
if(CMAKE_RC_COMPILER)
get_filename_component(rc_dir "${CMAKE_RC_COMPILER}" DIRECTORY)
get_filename_component(sdk_bin "${rc_dir}" DIRECTORY)
list(APPEND hints "${rc_dir}" "${sdk_bin}/x64" "${sdk_bin}/x86")
endif()
find_program(MWG_MIDL_EXECUTABLE midl HINTS ${hints} DOC "MIDL compiler from the Windows SDK")
if(NOT MWG_MIDL_EXECUTABLE)
message(FATAL_ERROR
"midl.exe was not found. It ships with the Windows SDK ${MWG_WINDOWS_SDK}; "
"configure from a Visual Studio toolchain (CLion) or a VS 2026 Developer PowerShell.")
endif()
set(${out_var} "${MWG_MIDL_EXECUTABLE}" PARENT_SCOPE)
endfunction()

function(mwg_add_midl_target target)
cmake_parse_arguments(PARSE_ARGV 1 arg "" "IDL;OUTPUT_DIR" "DEPENDS")
if(NOT arg_IDL)
message(FATAL_ERROR "mwg_add_midl_target: IDL is required")
endif()
if(NOT arg_OUTPUT_DIR)
set(arg_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/midl")
endif()

_mwg_find_midl(midl)

# MIDL preprocesses the IDL with cl.exe, which it finds on PATH only. The
# Ninja generator inherits the vcvars PATH; the Visual Studio generators
# run custom commands in an MSBuild environment that has it. A plain shell
# with a cl.exe from CMAKE_C_COMPILER is not enough.
if(NOT CMAKE_GENERATOR MATCHES "^Visual Studio")
find_program(_mwg_cl_on_path cl NO_CACHE NO_DEFAULT_PATH PATHS ENV PATH)
if(NOT _mwg_cl_on_path)
message(FATAL_ERROR
"cl.exe is not on PATH, but midl.exe needs it to preprocess ${arg_IDL}.\n"
"Use a Visual Studio toolchain in CLion, or configure and build from a "
"VS 2026 Developer PowerShell (vcvarsall.bat).")
endif()
endif()

cmake_path(ABSOLUTE_PATH arg_IDL BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE idl)
# LAST_ONLY: MapWinGIS.ActiveX.idl -> MapWinGIS.ActiveX
cmake_path(GET idl STEM LAST_ONLY name)
cmake_path(GET idl PARENT_PATH idl_dir)

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(env x64)
else()
set(env win32)
endif()

set(header "${arg_OUTPUT_DIR}/${name}_i.h")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Minor | Confidence: Medium

Issue: The MSBuild Midl task writes the type library to $(OutDir) (<TypeLibraryName>$(OutDir)MapWinGIS.ActiveX.tlb</TypeLibraryName> in MapWinGIS.ActiveX.vcxproj), i.e. next to the OCX; the CMake build writes it only to <build>/src/MapWinGIS.ActiveX/midl. This is not listed among the "explained differences" in the PR description or docs/CMAKE-MIGRATION.md.
Impact: Anything that packages, registers or redistributes the OCX together with its .tlb from the output directory (installers, Verify-ActiveXActivation.ps1-style scripts, the existing CI artifact upload of bin/Release/<platform>/) will behave differently between the two builds.
Fix: Either copy the .tlb next to the OCX after the MIDL step (or via a post-build cmake -E copy), or record this as an intentional difference in docs/CMAKE-MIGRATION.md.

set(iid "${arg_OUTPUT_DIR}/${name}_i.c")
set(tlb "${arg_OUTPUT_DIR}/${name}.tlb")

add_custom_command(
OUTPUT "${header}" "${iid}" "${tlb}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Minor | Confidence: Medium

Issue: MapWinGIS.ActiveX_p.c and dlldata.c are redirected into the output directory but are neither declared as OUTPUT/BYPRODUCTS nor consumed by any target. The header comment correctly notes that today's IDL declares no non-automation interfaces, but nothing guards that invariant.
Impact: The day the IDL gains a non-automation (non-oleautomation) interface, MIDL will emit a proxy file and the OCX will silently be built without the proxy/stub code and without dlldata.c, producing registration/marshalling failures that are hard to trace back to the build system.
Fix: Either add a configure-time check that fails when the IDL contains non-automation interfaces, or declare the two files as BYPRODUCTS and add a comment at the mwg_add_midl_target call site that they must be wired into consumers when they appear.

COMMAND "${CMAKE_COMMAND}" -E make_directory "${arg_OUTPUT_DIR}"
COMMAND "${midl}" /W1 /nologo /char signed /env ${env} /target NT60
/I "${idl_dir}"
/out "${arg_OUTPUT_DIR}"
/h "${name}_i.h"
/iid "${name}_i.c"
/proxy "${name}_p.c"
/dlldata dlldata.c
/tlb "${name}.tlb"
"${idl}"
MAIN_DEPENDENCY "${idl}"
DEPENDS ${arg_DEPENDS}
WORKING_DIRECTORY "${idl_dir}"
COMMENT "MIDL ${name}.idl"
VERBATIM
)

add_custom_target(${target} DEPENDS "${header}" "${iid}" "${tlb}" SOURCES "${idl}")
set_target_properties(${target} PROPERTIES FOLDER "src")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Suggestion | Confidence: Low

Issue: The build-directory path ${arg_OUTPUT_DIR} is exposed as an INTERFACE include directory without a BUILD_INTERFACE guard.
Impact: Fine for this phase, but the moment any target linking MapWinGIS.ActiveX.Interface.Generated is part of an install(EXPORT)/export() set, generation fails with "target ... not in any export set" / non-exportable interface errors. This will bite in Phase 3 when the tests link this target if an export is ever added alongside.
Fix: When exports appear, wrap it in $<BUILD_INTERFACE:...>; no change needed now — noting it so it doesn't surface as a surprise later.

add_library(${target}.Generated INTERFACE)
target_include_directories(${target}.Generated INTERFACE "${arg_OUTPUT_DIR}")
add_dependencies(${target}.Generated ${target})

set(${target}_HEADER "${header}" PARENT_SCOPE)
set(${target}_IID "${iid}" PARENT_SCOPE)
set(${target}_TLB "${tlb}" PARENT_SCOPE)
set(${target}_DIR "${arg_OUTPUT_DIR}" PARENT_SCOPE)
endfunction()
13 changes: 10 additions & 3 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,11 @@ MSBuild settings and the decisions the CMake build follows are in

### Building with CMake

The CMake build currently covers `MapWinGIS.Core.dll`; the ActiveX control,
tests and samples follow. It needs CMake 3.28 or later and Ninja; both ship
The CMake build currently covers `MapWinGIS.Core.dll` and `MapWinGIS.ocx`; the
tests and samples follow. The OCX needs the **C++ ATL for latest v145 build
tools** component for each architecture you build, and `midl.exe` needs `cl.exe`
on `PATH`, so configure and build from a Visual Studio toolchain (CLion) or a
Developer PowerShell. CMake 3.28 or later and Ninja are required; both ship
with Visual Studio 2026 and CLion. Run the bootstrap script first, then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: Minor | Confidence: Low

Issue: This sentence still says "CMake 3.28 or later and Ninja are required", but this PR's own verification (and docs/CMAKE-MIGRATION.md) covers the Visual Studio generator as well — Ninja is not required.
Impact: A reader on CLion/VS with the VS generator skips CMake believing it cannot work here.
Fix: Reword to "CMake 3.28 or later, with either Ninja or the Visual Studio generator".

configure from a VS 2026 Developer PowerShell (or any shell after
`vcvarsall.bat x64`):
Expand All @@ -218,7 +221,11 @@ cmake --build --preset x64-debug

- Output goes to `<build directory>\bin` (`bin\<Config>` for the Visual Studio
presets) and import libraries to `lib`, never to the MSBuild `bin\` folder, so
both builds can be used side by side.
both builds can be used side by side. MIDL output (`MapWinGIS.ActiveX_i.h`,
`_i.c`, `.tlb`) goes to `<build directory>\src\MapWinGIS.ActiveX\midl`.
- To register the CMake-built control for the current user:
`regsvr32 /n /i:user out\b\x64d\bin\MapWinGIS.ocx` (use
`%WINDIR%\SysWOW64\regsvr32.exe` for Win32; add `/u` to unregister).
- The vcpkg root is found in the same order as above. CMake uses its own install
tree, `vcpkg_installed\cmake-<Platform>`, shared by Debug and Release; the
binary cache makes it cheap.
Expand Down
28 changes: 28 additions & 0 deletions docs/CMAKE-MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,31 @@ Measured for Debug and Release, x64 and Win32 (Ninja presets):
by default for that platform.
- `dumpbin`: identical dependents, exports (260), subsystem and DLL
characteristics.

### MapWinGIS.ActiveX (Phase 2)

Measured for Debug and Release, x64 and Win32 (Ninja presets):

- Compile and link options: none lost; 0 warnings. Explained differences:
- The MIDL include directory is `<build>/src/MapWinGIS.ActiveX/midl`
instead of the intermediate directory (D3); the generated `_i.c` is
compared by file name.
- No vcpkg include directory: the OCX has no direct vcpkg dependency.
- The compiled resource is named `MapWinGIS.ActiveX.rc.res`, and the Core
import library comes from `target_link_libraries` instead of the project
reference.
- CMake needs two explicit settings to match MSBuild: `DEFINE_SYMBOL ""` (no
`MapWinGIS_ActiveX_EXPORTS`; the `.def` file exports the entry points) and
`/TC` for C sources (CMake passes `/TP` for C++ only).
- `dumpbin`: identical dependents, the five COM exports, subsystem and DLL
characteristics.
- The generated type library is byte-identical to the MSBuild one, and
`MapWinGIS.ActiveX_i.h` is identical below its generated header comment.
- MIDL runs through one custom command for all generators
(`cmake/MwgMidl.cmake`) with the MSBuild options. This IDL produces no
proxy or `dlldata.c`; MIDL is told to write them into the output directory
anyway, so nothing can land in the source tree.
- Per-user registration (`regsvr32 /n /i:user`), `New-Object -ComObject
MapWinGIS6.Control` and unregistration work for the x64 and Win32 OCX.
- Three clean `-j32` Ninja builds in a row succeeded (no MIDL/RC race), and the
Visual Studio generator builds x64 Debug/Release and x86 Debug.
99 changes: 99 additions & 0 deletions src/MapWinGIS.ActiveX/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# SPDX-License-Identifier: MPL-2.0
#
# MapWinGIS.ocx: thin ActiveX/COM wrapper over MapWinGIS.Core (static ATL,
# apartment threaded).

include(MwgMidl)

mwg_add_midl_target(MapWinGIS.ActiveX.Interface IDL MapWinGIS.ActiveX.idl)

# Compiled into the OCX and, with MWG_ENABLE_RENDERER_TEST_HOOKS, into the
# tests (docs/CMAKE-MIGRATION.md, D4).
set(MWG_ACTIVEX_SHARED_SOURCES
ComConversion.cpp
GdalOperationDispatcher.cpp
GdiVectorLayerRenderer.cpp
OpenGlVectorLayerRenderer.cpp
VectorLayerRenderer.cpp
ViewTransform.cpp
)
list(TRANSFORM MWG_ACTIVEX_SHARED_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/"
OUTPUT_VARIABLE MWG_ACTIVEX_SHARED_SOURCES)
set(MWG_ACTIVEX_SHARED_SOURCES "${MWG_ACTIVEX_SHARED_SOURCES}" PARENT_SCOPE)

set(MWG_ACTIVEX_HEADERS
ActiveXModule.h
ComConversion.h
GdalDispatchWindow.h
GdalEventSource.h
GdalOperationDispatcher.h
GdiVectorLayerRenderer.h
MapWinGISControl.h
OpenGlVectorLayerRenderer.h
VectorLayerRenderer.h
VectorRenderBackend.h
ViewTransform.h
resource.h
)

set(MWG_ACTIVEX_SOURCES
ActiveXModule.cpp
GdalEventSource.cpp
MapWinGISControl.cpp
)

set(MWG_ACTIVEX_RESOURCES
MapWinGIS.ActiveX.rc
MapWinGIS.ActiveX.def
MapWinGISControl.rgs
)

# SHARED, not MODULE: keeps the import library and the runtime-DLL handling.
add_library(MapWinGIS.ActiveX SHARED)

target_sources(MapWinGIS.ActiveX PRIVATE
${MWG_ACTIVEX_HEADERS}
${MWG_ACTIVEX_SOURCES}
${MWG_ACTIVEX_SHARED_SOURCES}
${MWG_ACTIVEX_RESOURCES}
"${MapWinGIS.ActiveX.Interface_HEADER}"
"${MapWinGIS.ActiveX.Interface_IID}"
)
source_group("Header Files" FILES ${MWG_ACTIVEX_HEADERS})
source_group("Source Files" FILES ${MWG_ACTIVEX_SOURCES} ${MWG_ACTIVEX_SHARED_SOURCES})
source_group("Resource Files" FILES ${MWG_ACTIVEX_RESOURCES})
source_group("Generated Files" FILES
"${MapWinGIS.ActiveX.Interface_HEADER}"
"${MapWinGIS.ActiveX.Interface_IID}")

# The .rc embeds the generated type library (1 TYPELIB "MapWinGIS.ActiveX.tlb");
# rc's dependency scanner does not see it.
set_source_files_properties(MapWinGIS.ActiveX.rc PROPERTIES
OBJECT_DEPENDS "${MapWinGIS.ActiveX.Interface_TLB};${CMAKE_CURRENT_SOURCE_DIR}/MapWinGISControl.rgs")

target_link_libraries(MapWinGIS.ActiveX PRIVATE
MapWinGIS::Core
MapWinGIS.ActiveX.Interface.Generated
# Explicit Windows libraries (audit). ATL is static: atlbase.h links
# atls.lib through #pragma comment, and OpenGlVectorLayerRenderer.cpp links
# opengl32.lib the same way.
ole32 oleaut32 uuid user32 gdi32 advapi32 kernel32
)

target_compile_definitions(MapWinGIS.ActiveX PRIVATE "$<$<COMPILE_LANGUAGE:C,CXX>:_ATL_APARTMENT_THREADED>")

# MSBuild ResourceCompile: /l 0x0409 and the MIDL output directory on the include path.
target_compile_options(MapWinGIS.ActiveX PRIVATE "$<$<COMPILE_LANGUAGE:RC>:/l0x0409>")

mwg_apply_common_options(MapWinGIS.ActiveX)

set_target_properties(MapWinGIS.ActiveX PROPERTIES
OUTPUT_NAME MapWinGIS
SUFFIX ".ocx"
# The COM entry points are exported through MapWinGIS.ActiveX.def; no
# <target>_EXPORTS macro, as in MSBuild.
DEFINE_SYMBOL ""
FOLDER "src"
)

add_dependencies(MapWinGIS.ActiveX MapWinGIS.ActiveX.Interface)