Skip to content

Commit 5d22632

Browse files
committed
Add database read functions to Msi.java
1 parent e96f301 commit 5d22632

File tree

3 files changed

+295
-0
lines changed

3 files changed

+295
-0
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Next Release (5.14.0)
77

88
Features
99
--------
10+
* [#1537](https://github.com/java-native-access/jna/pull/1537): Add MSI database access functions - [@russellbanks](https://github.com/russellbanks)
1011

1112
Bug Fixes
1213
---------

contrib/platform/src/com/sun/jna/platform/win32/Msi.java

+238
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
package com.sun.jna.platform.win32;
2424

2525
import com.sun.jna.Native;
26+
import com.sun.jna.Pointer;
27+
import com.sun.jna.platform.win32.WinBase.FILETIME;
2628
import com.sun.jna.ptr.IntByReference;
29+
import com.sun.jna.ptr.PointerByReference;
2730
import com.sun.jna.win32.StdCallLibrary;
2831
import com.sun.jna.win32.W32APIOptions;
2932

@@ -104,6 +107,36 @@ public interface Msi extends StdCallLibrary {
104107
*/
105108
int INSTALLSTATE_DEFAULT = 5;
106109

110+
/**
111+
* Create a new database, direct mode read/write.
112+
*/
113+
static final String MSIDBOPEN_CREATEDIRECT = "MSIDBOPEN_CREATEDIRECT";
114+
115+
/**
116+
* Create a new database, transact mode read/write.
117+
*/
118+
static final String MSIDBOPEN_CREATE = "MSIDBOPEN_CREATE";
119+
120+
/**
121+
* Open a database direct read/write without transaction.
122+
*/
123+
static final String MSIDBOPEN_DIRECT = "MSIDBOPEN_DIRECT";
124+
125+
/**
126+
* Open a database read-only, no persistent changes.
127+
*/
128+
static final String MSIDBOPEN_READONLY = "MSIDBOPEN_READONLY";
129+
130+
/**
131+
* Open a database read/write in transaction mode.
132+
*/
133+
static final String MSIDBOPEN_TRANSACT = "MSIDBOPEN_TRANSACT";
134+
135+
/**
136+
* Add this flag to indicate a patch file.
137+
*/
138+
static final String MSIDBOPEN_PATCHFILE = "MSIDBOPEN_PATCHFILE";
139+
107140
/**
108141
* The MsiGetComponentPath function returns the full path to an installed component. If the key path for the
109142
* component is a registry key then the registry key is returned.
@@ -218,4 +251,209 @@ public interface Msi extends StdCallLibrary {
218251
* ERROR_SUCCESS - A value was enumerated.
219252
*/
220253
int MsiEnumComponents(WinDef.DWORD iComponentIndex, char[] lpComponentBuf);
254+
255+
/**
256+
* The MsiCloseHandle function closes an open installation handle.
257+
*
258+
* @param hAny
259+
* Specifies any open installation handle.
260+
*
261+
* @return
262+
* ERROR_INVALID_HANDLE - An invalid handle was passed to the function.
263+
* ERROR_SUCCESS - The function succeeded.
264+
*/
265+
int MsiCloseHandle(Pointer hAny);
266+
267+
/**
268+
* The MsiDatabaseOpenView function prepares a database query and creates a view object. This function
269+
* returns a handle that should be closed using {@link #MsiCloseHandle}.
270+
*
271+
* @param hDatabase
272+
* Handle to the database to which you want to open a view object.
273+
*
274+
* @param szQuery
275+
* Specifies a SQL query string for querying the database.
276+
*
277+
* @param phView
278+
* Pointer to a handle for the returned view.
279+
*
280+
* @return
281+
* ERROR_BAD_QUERY_SYNTAX - An invalid SQL query string was passed to the function.
282+
* ERROR_INVALID_HANDLE - An invalid or inactive handle was supplied.
283+
* ERROR_SUCCESS - The function succeeded, and the handle is to a view object.
284+
*/
285+
int MsiDatabaseOpenView(Pointer hDatabase, String szQuery, PointerByReference phView);
286+
287+
/**
288+
* The MsiGetSummaryInformation function obtains a handle to the _SummaryInformation stream for an installer
289+
* database. This function returns a handle that should be closed using {@link #MsiCloseHandle}.
290+
*
291+
* @param hDatabase
292+
* Handle to the database.
293+
*
294+
* @param szDatabasePath
295+
* Specifies the path to the database.
296+
*
297+
* @param uiUpdateCount
298+
* Specifies the maximum number of updated values.
299+
*
300+
* @param phSummaryInfo
301+
* Pointer to the location from which to receive the summary information handle.
302+
*
303+
* @return
304+
* ERROR_INSTALL_PACKAGE_INVALID - The installation package is invalid.
305+
* ERROR_INVALID_HANDLE - An invalid or inactive handle was supplied.
306+
* ERROR_INVALID_PARAMETER - An invalid parameter was passed to the function.
307+
* ERROR_SUCCESS - The function succeeded.
308+
*/
309+
int MsiGetSummaryInformation(Pointer hDatabase, String szDatabasePath, int uiUpdateCount,
310+
PointerByReference phSummaryInfo);
311+
312+
/**
313+
* The MsiOpenDatabase function opens a database file for data access. This function returns a handle that should be
314+
* closed using {@link #MsiCloseHandle}.
315+
*
316+
* @param szDatabasePath
317+
* Specifies the full path or relative path to the database file.
318+
*
319+
* @param szPersist
320+
* Receives the full path to the file or the persistence mode. You can use the persist parameter to direct the
321+
* persistent output to a new file or to specify one of the following predefined persistence modes:
322+
* {@link #MSIDBOPEN_CREATEDIRECT} - Create a new database, direct mode read/write.
323+
* {@link #MSIDBOPEN_CREATE} - Create a new database, transact mode read/write.
324+
* {@link #MSIDBOPEN_DIRECT} - Open a database direct read/write without transaction.
325+
* {@link #MSIDBOPEN_READONLY} - Open a database read-only, no persistent changes.
326+
* {@link #MSIDBOPEN_TRANSACT} - Open a database read/write in transaction mode.
327+
* {@link #MSIDBOPEN_PATCHFILE} - Add this flag to indicate a patch file.
328+
*
329+
* @param phDatabase
330+
* Pointer to the location of the returned database handle.
331+
*
332+
* @return
333+
* ERROR_CREATE_FAILED - The database could not be created.
334+
* ERROR_INVALID_PARAMETER - One of the parameters was invalid.
335+
* ERROR_OPEN_FAILED - The database could not be opened as requested.
336+
* ERROR_SUCCESS - The function succeeded.
337+
*/
338+
int MsiOpenDatabase(String szDatabasePath, String szPersist, PointerByReference phDatabase);
339+
340+
/**
341+
* The MsiRecordGetString function returns the string value of a record field.
342+
*
343+
* @param hRecord
344+
* Handle to the record.
345+
*
346+
* @param iField
347+
* Specifies the field requested.
348+
*
349+
* @param szValueBuf
350+
* Pointer to the buffer that receives the null terminated string containing the value of the record field. Do not
351+
* attempt to determine the size of the buffer by passing in a null (value=0) for szValueBuf. You can get the size
352+
* of the buffer by passing in an empty string (for example ""). The function then returns ERROR_MORE_DATA and
353+
* pcchValueBuf contains the required buffer size in TCHARs, not including the terminating null character. On
354+
* return of ERROR_SUCCESS, pcchValueBuf contains the number of TCHARs written to the buffer, not including the
355+
* terminating null character.
356+
*
357+
* @param pcchValueBuf
358+
* Pointer to the variable that specifies the size, in TCHARs, of the buffer pointed to by the variable
359+
* szValueBuf. When the function returns ERROR_SUCCESS, this variable contains the size of the data copied to
360+
* szValueBuf, not including the terminating null character. If szValueBuf is not large enough, the function
361+
* returns ERROR_MORE_DATA and stores the required size, not including the terminating null character, in the
362+
* variable pointed to by pcchValueBuf.
363+
*
364+
* @return
365+
* ERROR_INVALID_HANDLE - An invalid or inactive handle was supplied.
366+
* ERROR_INVALID_PARAMETER - An invalid parameter was supplied.
367+
* ERROR_MORE_DATA - The provided buffer was too small to hold the entire value.
368+
* ERROR_SUCCESS - The function succeeded.
369+
*/
370+
int MsiRecordGetString(Pointer hRecord, int iField, char[] szValueBuf, IntByReference pcchValueBuf);
371+
372+
/**
373+
* The MsiSummaryInfoGetProperty function gets a single property from the summary information stream.
374+
*
375+
* @param hSummaryInfo
376+
* Handle to summary information.
377+
*
378+
* @param uiProperty
379+
* Specifies the property ID of the summary property. This parameter can be a property ID listed in the Summary
380+
* Information Stream Property Set. This function does not return values for PID_DICTIONARY OR PID_THUMBNAIL
381+
* property.
382+
*
383+
* @param puiDataType
384+
* Receives the returned property type. This parameter can be a type listed in the Summary Information Stream
385+
* Property Set.
386+
*
387+
* @param piValue
388+
* Receives the returned integer property data.
389+
*
390+
* @param pftValue
391+
* Pointer to a file value.
392+
*
393+
* @param szValueBuf
394+
* Pointer to the buffer that receives the null terminated summary information property value. Do not attempt to
395+
* determine the size of the buffer by passing in a null (value=0) for szValueBuf. You can get the size of the
396+
* buffer by passing in an empty string (for example ""). The function then returns ERROR_MORE_DATA and
397+
* pcchValueBuf contains the required buffer size in TCHARs, not including the terminating null character. On
398+
* return of ERROR_SUCCESS, pcchValueBuf contains the number of TCHARs written to the buffer, not including the
399+
* terminating null character. This parameter is an empty string if there are no errors.
400+
*
401+
* @param pcchValueBuf
402+
* Pointer to the variable that specifies the size, in TCHARs, of the buffer pointed to by the variable
403+
* szValueBuf. When the function returns ERROR_SUCCESS, this variable contains the size of the data copied to
404+
* szValueBuf, not including the terminating null character. If szValueBuf is not large enough, the function
405+
* returns ERROR_MORE_DATA and stores the required size, not including the terminating null character, in the
406+
* variable pointed to by pcchValueBuf.
407+
*
408+
* @return
409+
* ERROR_INVALID_HANDLE - An invalid or inactive handle was supplied.
410+
* ERROR_INVALID_PARAMETER - An invalid parameter was passed to the function.
411+
* ERROR_MORE_DATA - The buffer passed in was too small to hold the entire value.
412+
* ERROR_SUCCESS - The function succeeded.
413+
* ERROR_UNKNOWN_PROPERTY - The property is unknown.
414+
*/
415+
int MsiSummaryInfoGetProperty(Pointer hSummaryInfo, int uiProperty, IntByReference puiDataType,
416+
IntByReference piValue, FILETIME pftValue, char[] szValueBuf, IntByReference pcchValueBuf);
417+
418+
/**
419+
* The MsiViewExecute function executes a SQL view query and supplies any required parameters. The query uses
420+
* the question mark token to represent parameters as described in SQL Syntax. The values of these parameters
421+
* are passed in as the corresponding fields of a parameter record.
422+
* <p>
423+
* Note: In low memory situations, this function can raise a STATUS_NO_MEMORY exception.
424+
*
425+
* @param hView
426+
* Handle to the view upon which to execute the query.
427+
*
428+
* @param hRecord
429+
* Handle to a record that supplies the parameters. This parameter contains values to replace the parameter
430+
* tokens in the SQL query. It is optional, so hRecord can be zero.
431+
*
432+
* @return
433+
* ERROR_FUNCTION_FAILED - A view could not be executed.
434+
* ERROR_INVALID_HANDLE - An invalid or inactive handle was supplied.
435+
* ERROR_SUCCESS - The function succeeded.
436+
*/
437+
int MsiViewExecute(Pointer hView, Pointer hRecord);
438+
439+
/**
440+
* The MsiViewFetch function fetches the next sequential record from the view. This function returns a handle that
441+
* should be closed using {@link #MsiCloseHandle}.
442+
* <p>
443+
* Note: In low memory situations, this function can raise a STATUS_NO_MEMORY exception.
444+
*
445+
* @param hView
446+
* Handle to the view to fetch from.
447+
*
448+
* @param phRecord
449+
* Pointer to the handle for the fetched record.
450+
*
451+
* @return
452+
* ERROR_FUNCTION_FAILED - An error occurred during fetching.
453+
* ERROR_INVALID_HANDLE - An invalid or inactive handle was supplied.
454+
* ERROR_INVALID_HANDLE_STATE - The handle was in an invalid state.
455+
* ERROR_NO_MORE_ITEMS - No records remain, and a null handle is returned.
456+
* ERROR_SUCCESS - The function succeeded, and a handle to the record is returned.
457+
*/
458+
int MsiViewFetch(Pointer hView, PointerByReference phRecord);
221459
}

contrib/platform/test/com/sun/jna/platform/win32/MsiTest.java

+56
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424

2525
import java.util.Arrays;
2626

27+
import com.sun.jna.platform.win32.WinBase.FILETIME;
2728
import com.sun.jna.ptr.IntByReference;
29+
import com.sun.jna.ptr.PointerByReference;
2830

2931
import junit.framework.TestCase;
3032

@@ -90,4 +92,58 @@ public void testMsiGetComponentPathW() {
9092
String path = new String(pathBuffer, 0, pathBufferSize.getValue()).trim();
9193
assertFalse("Path is empty", path.isEmpty());
9294
}
95+
96+
public void testMsiOpenDatabaseW() {
97+
PointerByReference phDatabase = new PointerByReference();
98+
assertEquals(WinError.ERROR_INVALID_PARAMETER, Msi.INSTANCE.MsiOpenDatabase("", Msi.MSIDBOPEN_READONLY, phDatabase));
99+
}
100+
101+
public void testMsiCloseHandle() {
102+
PointerByReference handle = new PointerByReference();
103+
assertEquals(WinError.ERROR_INVALID_HANDLE, Msi.INSTANCE.MsiCloseHandle(handle.getPointer()));
104+
}
105+
106+
public void testMsiDatabaseOpenViewW() {
107+
PointerByReference hDatabase = new PointerByReference();
108+
PointerByReference phView = new PointerByReference();
109+
assertEquals(WinError.ERROR_INVALID_HANDLE, Msi.INSTANCE.MsiDatabaseOpenView(hDatabase.getPointer(), "", phView));
110+
}
111+
112+
public void testMsiRecordGetStringW() {
113+
PointerByReference hRecord = new PointerByReference();
114+
IntByReference pcchValueBuf = new IntByReference();
115+
char[] szValueBuf = new char[40];
116+
pcchValueBuf.setValue(40);
117+
assertEquals(WinError.ERROR_INVALID_HANDLE, Msi.INSTANCE.MsiRecordGetString(hRecord.getPointer(), 0, szValueBuf, pcchValueBuf));
118+
}
119+
120+
public void testMsiViewFetch() {
121+
PointerByReference hView = new PointerByReference();
122+
PointerByReference phRecord = new PointerByReference();
123+
assertEquals(WinError.ERROR_INVALID_HANDLE, Msi.INSTANCE.MsiViewFetch(hView.getPointer(), phRecord));
124+
}
125+
126+
127+
public void testMsiViewExecute() {
128+
PointerByReference hView = new PointerByReference();
129+
PointerByReference hRecord = new PointerByReference();
130+
assertEquals(WinError.ERROR_INVALID_HANDLE, Msi.INSTANCE.MsiViewExecute(hView.getPointer(), hRecord.getPointer()));
131+
}
132+
133+
public void testMsiGetSummaryInformationW() {
134+
PointerByReference hDatabase = new PointerByReference();
135+
PointerByReference phSummaryInfo = new PointerByReference();
136+
assertEquals(WinError.ERROR_INVALID_HANDLE, Msi.INSTANCE.MsiGetSummaryInformation(hDatabase.getPointer(), "", 0, phSummaryInfo));
137+
}
138+
139+
public void testMsiSummaryInfoGetProperty() {
140+
PointerByReference hSummaryInfo = new PointerByReference();
141+
IntByReference puiDataType = new IntByReference();
142+
IntByReference piValue = new IntByReference();
143+
FILETIME pftValue = new FILETIME();
144+
char[] szValueBuf = new char[40];
145+
IntByReference pcchValueBuf = new IntByReference();
146+
pcchValueBuf.setValue(40);
147+
assertEquals(WinError.ERROR_INVALID_HANDLE, Msi.INSTANCE.MsiSummaryInfoGetProperty(hSummaryInfo.getPointer(), 7, puiDataType, piValue, pftValue, szValueBuf, pcchValueBuf));
148+
}
93149
}

0 commit comments

Comments
 (0)