Skip to content
This repository was archived by the owner on May 24, 2026. It is now read-only.

Commit 6986e63

Browse files
authored
Merge pull request #3 from velopack/cs/msi-interop
Create win32 msi.dll interop layer
2 parents 690dd6c + 85fe557 commit 6986e63

16 files changed

Lines changed: 4958 additions & 1 deletion

.github/workflows/build.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ jobs:
7373
cp builddir/libmsi.dll libmsi-win-${{ matrix.arch }}.dll
7474
cp builddir/libmsi.dll.a libmsi-win-${{ matrix.arch }}.dll.lib
7575
76+
- name: Collect msi-interop artifacts
77+
shell: msys2 {0}
78+
run: |
79+
cp builddir/libmsi-interop.dll msi-interop-win-${{ matrix.arch }}.dll
80+
cp builddir/libmsi-interop.dll.a msi-interop-win-${{ matrix.arch }}.dll.lib || true
81+
7682
- uses: actions/upload-artifact@v4
7783
with:
7884
name: build-win-${{ matrix.arch }}
@@ -81,6 +87,8 @@ jobs:
8187
libmsi-win-${{ matrix.arch }}.lib
8288
libmsi-win-${{ matrix.arch }}.dll
8389
libmsi-win-${{ matrix.arch }}.dll.lib
90+
msi-interop-win-${{ matrix.arch }}.dll
91+
msi-interop-win-${{ matrix.arch }}.dll.lib
8492
retention-days: 1
8593

8694
linux:
@@ -135,6 +143,10 @@ jobs:
135143
cp builddir/libmsi.a libmsi-linux-${{ matrix.arch }}.a
136144
cp builddir/libmsi.so libmsi-linux-${{ matrix.arch }}.so
137145
146+
- name: Collect msi-interop artifacts
147+
run: |
148+
cp builddir/libmsi-interop.so msi-interop-linux-${{ matrix.arch }}.so
149+
138150
- name: Collect generated header
139151
if: matrix.arch == 'x64'
140152
run: cp builddir/libmsi-enums.h libmsi-enums-generated.h
@@ -146,6 +158,7 @@ jobs:
146158
wixl-linux-${{ matrix.arch }}
147159
libmsi-linux-${{ matrix.arch }}.a
148160
libmsi-linux-${{ matrix.arch }}.so
161+
msi-interop-linux-${{ matrix.arch }}.so
149162
libmsi-enums-generated.h
150163
retention-days: 1
151164

@@ -200,13 +213,18 @@ jobs:
200213
cp builddir/libmsi-1.0.a libmsi-macos-${{ matrix.arch }}.a
201214
cp builddir/libmsi.dylib libmsi-macos-${{ matrix.arch }}.dylib
202215
216+
- name: Collect msi-interop artifacts
217+
run: |
218+
cp builddir/libmsi-interop.dylib msi-interop-macos-${{ matrix.arch }}.dylib
219+
203220
- uses: actions/upload-artifact@v4
204221
with:
205222
name: build-macos-${{ matrix.arch }}
206223
path: |
207224
wixl-macos-${{ matrix.arch }}
208225
libmsi-macos-${{ matrix.arch }}.a
209226
libmsi-macos-${{ matrix.arch }}.dylib
227+
msi-interop-macos-${{ matrix.arch }}.dylib
210228
retention-days: 1
211229

212230
package:
@@ -235,6 +253,12 @@ jobs:
235253
file libmsi-osx-universal.dylib
236254
rm libmsi-macos-arm64.dylib libmsi-macos-x64.dylib
237255
256+
- name: Create macOS universal msi-interop dylib
257+
run: |
258+
lipo -create msi-interop-macos-arm64.dylib msi-interop-macos-x64.dylib -output msi-interop-osx-universal.dylib
259+
file msi-interop-osx-universal.dylib
260+
rm msi-interop-macos-arm64.dylib msi-interop-macos-x64.dylib
261+
238262
- name: Package wixl
239263
run: |
240264
mkdir -p build-wixl
@@ -260,6 +284,16 @@ jobs:
260284
mv libmsi-macos-arm64.a libmsi-macos-x64.a build-libmsi/static/
261285
ls -laR build-libmsi/
262286
287+
- name: Package msi-interop
288+
run: |
289+
mkdir -p build-msi-interop/include build-msi-interop/shared
290+
cp msi-interop/msi_interop.h msi-interop/msi_cab.h build-msi-interop/include/
291+
mv msi-interop-win-*.dll build-msi-interop/shared/
292+
mv msi-interop-win-*.dll.lib build-msi-interop/shared/
293+
mv msi-interop-linux-*.so build-msi-interop/shared/
294+
mv msi-interop-osx-universal.dylib build-msi-interop/shared/
295+
ls -laR build-msi-interop/
296+
263297
- uses: actions/upload-artifact@v4
264298
with:
265299
name: build-wixl
@@ -269,3 +303,8 @@ jobs:
269303
with:
270304
name: build-libmsi
271305
path: build-libmsi/**/*
306+
307+
- uses: actions/upload-artifact@v4
308+
with:
309+
name: build-msi-interop
310+
path: build-msi-interop/**/*

.github/workflows/release.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,16 @@ jobs:
5454
name: build-libmsi
5555
path: libmsi
5656

57+
- uses: actions/download-artifact@v4
58+
with:
59+
name: build-msi-interop
60+
path: msi-interop
61+
5762
- name: Create release archives
5863
run: |
5964
zip -r wixl.zip wixl/
6065
zip -r libmsi.zip libmsi/
66+
zip -r msi-interop.zip msi-interop/
6167
6268
- name: Create GitHub Release
6369
env:
@@ -68,4 +74,5 @@ jobs:
6874
--title "${{ steps.version.outputs.version }}" \
6975
--generate-notes \
7076
wixl.zip \
71-
libmsi.zip
77+
libmsi.zip \
78+
msi-interop.zip

meson.build

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ if host_machine.system() == 'linux'
405405
'libeconf/lib/mergefiles.c',
406406
'libeconf/lib/readconfig.c',
407407
include_directories: include_directories('libeconf/include', 'libeconf/lib'),
408+
pic: true,
408409
)
409410
platform_link_deps = [libeconf]
410411
platform_link_args = ['-static']
@@ -425,6 +426,39 @@ else
425426
platform_link_args = []
426427
endif
427428

429+
# --- msi-interop shared library (Win32 MSI API compatibility layer) ---
430+
msi_interop_sources = [
431+
'msi-interop/handle_table.c',
432+
'msi-interop/string_utils.c',
433+
'msi-interop/database.c',
434+
'msi-interop/query.c',
435+
'msi-interop/record.c',
436+
'msi-interop/summary.c',
437+
'msi-interop/file_utils.c',
438+
'msi-interop/msi_cab.c',
439+
]
440+
441+
msi_interop_inc = include_directories('msi-interop')
442+
443+
if host_machine.system() == 'linux'
444+
msi_interop_deps = libmsi_shared_deps
445+
msi_interop_link_with = []
446+
else
447+
msi_interop_deps = [glib, gio, gobject, libxml, zlib]
448+
msi_interop_link_with = []
449+
endif
450+
451+
msi_interop_shared = shared_library('msi-interop',
452+
msi_interop_sources,
453+
libmsi_enums[1],
454+
objects: [libmsi.extract_all_objects(), libgsf.extract_all_objects(), libgcab.extract_all_objects()],
455+
include_directories: [inc_dirs, gsf_inc_dirs, gcab_inc_dirs, msi_interop_inc],
456+
dependencies: msi_interop_deps,
457+
link_with: msi_interop_link_with,
458+
link_args: libmsi_shared_link_args,
459+
gnu_symbol_visibility: 'hidden',
460+
)
461+
428462
# --- wixl common library (util.vala) ---
429463
libcommon = static_library('common',
430464
'msitools/tools/wixl/util.vala',

msi-interop/NOT_IMPLEMENTED.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# MSI Interop - Not Implemented Functions
2+
3+
These functions from the Windows MSI API (Msi.h / MsiQuery.h) are declared and exported
4+
by msi-interop but return `ERROR_CALL_NOT_IMPLEMENTED` (or equivalent error value).
5+
They cannot be meaningfully implemented because they require the Windows Installer Service,
6+
which is a system service that manages installed products, features, and components on the machine.
7+
8+
libmsi only provides MSI database file manipulation capabilities (open, query, modify, commit).
9+
It does not implement the Windows Installer engine.
10+
11+
## Implemented Functions (Database Authoring API)
12+
13+
The following functions ARE fully implemented via libmsi:
14+
15+
- MsiOpenDatabaseA/W, MsiDatabaseCommit, MsiGetDatabaseState
16+
- MsiDatabaseOpenViewA/W, MsiViewExecute, MsiViewFetch, MsiViewModify
17+
- MsiViewGetColumnInfo, MsiViewClose, MsiViewGetErrorA/W
18+
- MsiCreateRecord, MsiRecordIsNull, MsiRecordDataSize
19+
- MsiRecordSetInteger, MsiRecordSetStringA/W, MsiRecordGetInteger, MsiRecordGetStringA/W
20+
- MsiRecordGetFieldCount, MsiRecordSetStreamA/W, MsiRecordReadStream, MsiRecordClearData
21+
- MsiGetSummaryInformationA/W, MsiSummaryInfoGetPropertyCount
22+
- MsiSummaryInfoSetPropertyA/W, MsiSummaryInfoGetPropertyA/W, MsiSummaryInfoPersist
23+
- MsiCloseHandle, MsiCloseAllHandles, MsiGetLastErrorRecord
24+
- MsiFormatRecordA/W, MsiVerifyPackageA/W
25+
- MsiDatabaseGetPrimaryKeysA/W, MsiDatabaseIsTablePersistentA/W
26+
- MsiDatabaseImportA/W, MsiDatabaseExportA/W
27+
- MsiDatabaseMergeA/W, MsiDatabaseApplyTransformA/W
28+
29+
## Not Implemented - Categories
30+
31+
### Product/Feature/Component State Queries
32+
33+
These functions query the installation state of products, features, and components as
34+
tracked by the Windows Installer Service in its internal registration database (registry).
35+
libmsi has no access to this data.
36+
37+
- MsiQueryProductStateA/W
38+
- MsiGetProductInfoA/W
39+
- MsiGetProductInfoExA/W
40+
- MsiGetProductCodeA/W
41+
- MsiGetUserInfoA/W
42+
- MsiCollectUserInfoA/W
43+
- MsiQueryFeatureStateA/W
44+
- MsiQueryFeatureStateExA/W
45+
- MsiUseFeatureA/W
46+
- MsiUseFeatureExA/W
47+
- MsiGetFeatureUsageA/W
48+
- MsiGetComponentPathA/W
49+
- MsiGetComponentPathExA/W
50+
- MsiQueryComponentStateA/W
51+
- MsiLocateComponentA/W
52+
- MsiIsProductElevatedA/W
53+
- MsiGetProductPropertyA/W
54+
- MsiGetFeatureInfoA/W
55+
56+
### Installation/Configuration
57+
58+
These functions trigger product installation, configuration, or reinstallation through
59+
the Windows Installer engine. They execute installation sequences, run custom actions,
60+
and modify the system. libmsi cannot perform any of these operations.
61+
62+
- MsiInstallProductA/W
63+
- MsiConfigureProductA/W
64+
- MsiConfigureProductExA/W
65+
- MsiReinstallProductA/W
66+
- MsiConfigureFeatureA/W
67+
- MsiReinstallFeatureA/W
68+
- MsiInstallMissingComponentA/W
69+
- MsiInstallMissingFileA/W
70+
71+
### Advertising
72+
73+
These functions manage Windows Installer advertisement scripts, which allow products to
74+
be "advertised" (registered for on-demand installation) without being fully installed.
75+
This is a Windows Installer Service feature with no equivalent in libmsi.
76+
77+
- MsiAdvertiseProductA/W
78+
- MsiAdvertiseProductExA/W
79+
- MsiProcessAdvertiseScriptA/W
80+
- MsiAdvertiseScriptA/W
81+
- MsiGetProductInfoFromScriptA/W
82+
83+
### Patch Management
84+
85+
These functions apply, enumerate, and manage patches (.msp files) through the Windows
86+
Installer Service, which tracks patch application state in its registration database.
87+
libmsi does not implement patch application logic.
88+
89+
- MsiApplyPatchA/W
90+
- MsiGetPatchInfoA/W
91+
- MsiEnumPatchesA/W
92+
- MsiRemovePatchesA/W
93+
- MsiExtractPatchXMLDataA/W
94+
- MsiGetPatchInfoExA/W
95+
- MsiApplyMultiplePatchesA/W
96+
- MsiDeterminePatchSequenceA/W
97+
- MsiDetermineApplicablePatchesA/W
98+
- MsiEnumPatchesExA/W
99+
- MsiGetPatchFileListA/W
100+
101+
### Enumeration (Products, Features, Components)
102+
103+
These functions enumerate installed products, features, components, and their relationships
104+
as registered in the Windows Installer Service database. libmsi has no access to the
105+
system's product registration data.
106+
107+
- MsiEnumProductsA/W
108+
- MsiEnumProductsExA/W
109+
- MsiEnumRelatedProductsA/W
110+
- MsiEnumFeaturesA/W
111+
- MsiEnumComponentsA/W
112+
- MsiEnumComponentsExA/W
113+
- MsiEnumClientsA/W
114+
- MsiEnumClientsExA/W
115+
- MsiEnumComponentQualifiersA/W
116+
117+
### Source List Management
118+
119+
These functions manage the source list for installed products, controlling where the
120+
Windows Installer Service looks for installation media. This data is stored in the
121+
system registry by the installer service.
122+
123+
- MsiSourceListClearAllA/W
124+
- MsiSourceListAddSourceA/W
125+
- MsiSourceListForceResolutionA/W
126+
- MsiSourceListAddSourceExA/W
127+
- MsiSourceListAddMediaDiskA/W
128+
- MsiSourceListClearSourceA/W
129+
- MsiSourceListClearMediaDiskA/W
130+
- MsiSourceListClearAllExA/W
131+
- MsiSourceListForceResolutionExA/W
132+
- MsiSourceListSetInfoA/W
133+
- MsiSourceListGetInfoA/W
134+
- MsiSourceListEnumSourcesA/W
135+
- MsiSourceListEnumMediaDisksA/W
136+
137+
### UI Functions
138+
139+
These functions configure the Windows Installer UI subsystem, including setting the
140+
UI level, registering external UI handlers, and enabling logging. They are meaningless
141+
without the Windows Installer engine running an installation session.
142+
143+
- MsiSetInternalUI
144+
- MsiSetExternalUIA/W
145+
- MsiSetExternalUIRecord
146+
- MsiEnableLogA/W
147+
- MsiEnableUIPreview
148+
- MsiPreviewDialogA/W
149+
- MsiPreviewBillboardA/W
150+
151+
### Install Session Functions
152+
153+
These functions operate on an active installation session (MSIHANDLE to an install session)
154+
managed by the Windows Installer engine. They are used by custom actions during installation
155+
to query and modify the installation state. libmsi does not create or manage install sessions.
156+
157+
- MsiGetActiveDatabase
158+
- MsiSetPropertyA/W
159+
- MsiGetPropertyA/W
160+
- MsiGetLanguage
161+
- MsiGetMode
162+
- MsiSetMode
163+
- MsiDoActionA/W
164+
- MsiSequenceA/W
165+
- MsiProcessMessage
166+
- MsiEvaluateConditionA/W
167+
- MsiGetFeatureStateA/W
168+
- MsiSetFeatureStateA/W
169+
- MsiSetFeatureAttributesA/W
170+
- MsiGetComponentStateA/W
171+
- MsiSetComponentStateA/W
172+
- MsiGetFeatureCostA/W
173+
- MsiEnumComponentCostsA/W
174+
- MsiSetInstallLevel
175+
- MsiGetFeatureValidStatesA/W
176+
- MsiGetSourcePathA/W
177+
- MsiGetTargetPathA/W
178+
- MsiSetTargetPathA/W
179+
- MsiVerifyDiskSpace
180+
181+
### Package/Product Opening
182+
183+
These functions open an installed product or package through the Windows Installer Service,
184+
creating an installation session. Unlike MsiOpenDatabase (which opens the .msi file directly),
185+
these functions interact with the installer service to resolve product registration.
186+
187+
- MsiOpenProductA/W
188+
- MsiOpenPackageA/W
189+
- MsiOpenPackageExA/W
190+
191+
### Utility Functions
192+
193+
These functions provide utility operations that depend on Windows-specific APIs
194+
(file version resources, cryptographic signature verification, shell shortcuts)
195+
rather than MSI database content.
196+
197+
- MsiGetFileVersionA/W - requires Windows version resource APIs (GetFileVersionInfo)
198+
- MsiGetFileHashA/W - requires Windows file hashing APIs
199+
- MsiGetFileSignatureInformationA/W - requires Windows cryptographic certificate APIs (returns E_NOTIMPL)
200+
- MsiGetShortcutTargetA/W - requires Windows shell shortcut (IShellLink) APIs
201+
- MsiNotifySidChangeA/W - requires Windows Installer Service SID migration
202+
203+
### Transform Generation
204+
205+
These functions generate transform files (.mst) by comparing two databases, and create
206+
transform summary information. While libmsi can apply transforms, it does not expose
207+
the transform generation functionality.
208+
209+
- MsiDatabaseGenerateTransformA/W
210+
- MsiCreateTransformSummaryInfoA/W
211+
212+
### Transaction Management
213+
214+
These functions manage multi-package installation transactions, a feature of the Windows
215+
Installer engine that allows atomic installation of multiple packages.
216+
217+
- MsiBeginTransactionA/W
218+
- MsiEndTransaction
219+
- MsiJoinTransaction

0 commit comments

Comments
 (0)