blob: 60a0c3aebb1e77b4fdbe31711e9adfde12cfe411 [file] [log] [blame]
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001/* Helper library for MSI creation with Python.
Florent Xiclunac934f322010-09-03 23:47:32 +00002 * Copyright (C) 2005 Martin v. Löwis
Martin v. Löwisdd860ca2006-03-05 13:39:10 +00003 * Licensed to PSF under a contributor agreement.
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00004 */
5
6#include <Python.h>
7#include <fci.h>
8#include <fcntl.h>
9#include <windows.h>
10#include <msi.h>
11#include <msiquery.h>
12#include <msidefs.h>
13#include <rpc.h>
14
15static PyObject *MSIError;
16
17static PyObject*
18uuidcreate(PyObject* obj, PyObject*args)
19{
20 UUID result;
Victor Stinner9d3b93b2011-11-22 02:27:30 +010021 wchar_t *cresult;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000022 PyObject *oresult;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000023
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000024 /* May return ok, local only, and no address.
25 For local only, the documentation says we still get a uuid.
26 For RPC_S_UUID_NO_ADDRESS, it's not clear whether we can
27 use the result. */
28 if (UuidCreate(&result) == RPC_S_UUID_NO_ADDRESS) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000029 PyErr_SetString(PyExc_NotImplementedError, "processing 'no address' result");
30 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000031 }
32
Martin v. Löwis371bb502008-08-16 13:02:57 +000033 if (UuidToStringW(&result, &cresult) == RPC_S_OUT_OF_MEMORY) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000034 PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen");
35 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000036 }
37
Victor Stinner9d3b93b2011-11-22 02:27:30 +010038 oresult = PyUnicode_FromWideChar(cresult, wcslen(cresult));
Martin v. Löwis371bb502008-08-16 13:02:57 +000039 RpcStringFreeW(&cresult);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000040 return oresult;
41
42}
43
Serhiy Storchakaba67d732020-06-30 11:56:03 +030044/* Helper for converting file names from UTF-8 to wchat_t*. */
45static wchar_t *
46utf8_to_wchar(const char *s, int *err)
47{
48 PyObject *obj = PyUnicode_FromString(s);
49 if (obj == NULL) {
50 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
51 *err = ENOMEM;
52 }
53 else {
54 *err = EINVAL;
55 }
56 PyErr_Clear();
57 return NULL;
58 }
59 wchar_t *ws = PyUnicode_AsWideCharString(obj, NULL);
60 if (ws == NULL) {
61 *err = ENOMEM;
62 PyErr_Clear();
63 }
64 Py_DECREF(obj);
65 return ws;
66}
67
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000068/* FCI callback functions */
69
70static FNFCIALLOC(cb_alloc)
71{
Serhiy Storchakaba67d732020-06-30 11:56:03 +030072 return PyMem_RawMalloc(cb);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000073}
74
75static FNFCIFREE(cb_free)
76{
Serhiy Storchakaba67d732020-06-30 11:56:03 +030077 PyMem_RawFree(memory);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000078}
79
80static FNFCIOPEN(cb_open)
81{
Serhiy Storchakaba67d732020-06-30 11:56:03 +030082 wchar_t *ws = utf8_to_wchar(pszFile, err);
83 if (ws == NULL) {
84 return -1;
85 }
86 int result = _wopen(ws, oflag | O_NOINHERIT, pmode);
87 PyMem_Free(ws);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000088 if (result == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000089 *err = errno;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000090 return result;
91}
92
93static FNFCIREAD(cb_read)
94{
Victor Stinner67158282013-11-20 00:14:49 +010095 UINT result = (UINT)_read((int)hf, memory, cb);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000096 if (result != cb)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000097 *err = errno;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000098 return result;
99}
100
101static FNFCIWRITE(cb_write)
102{
Victor Stinner67158282013-11-20 00:14:49 +0100103 UINT result = (UINT)_write((int)hf, memory, cb);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000104 if (result != cb)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000105 *err = errno;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000106 return result;
107}
108
109static FNFCICLOSE(cb_close)
110{
Victor Stinner67158282013-11-20 00:14:49 +0100111 int result = _close((int)hf);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000112 if (result != 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 *err = errno;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000114 return result;
115}
116
117static FNFCISEEK(cb_seek)
118{
Victor Stinner67158282013-11-20 00:14:49 +0100119 long result = (long)_lseek((int)hf, dist, seektype);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000120 if (result == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000121 *err = errno;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000122 return result;
123}
124
125static FNFCIDELETE(cb_delete)
126{
Serhiy Storchakaba67d732020-06-30 11:56:03 +0300127 wchar_t *ws = utf8_to_wchar(pszFile, err);
128 if (ws == NULL) {
129 return -1;
130 }
131 int result = _wremove(ws);
132 PyMem_Free(ws);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000133 if (result != 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000134 *err = errno;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000135 return result;
136}
137
138static FNFCIFILEPLACED(cb_fileplaced)
139{
140 return 0;
141}
142
143static FNFCIGETTEMPFILE(cb_gettempfile)
144{
145 char *name = _tempnam("", "tmp");
146 if ((name != NULL) && ((int)strlen(name) < cbTempName)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 strcpy(pszTempName, name);
148 free(name);
149 return TRUE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000150 }
151
152 if (name) free(name);
153 return FALSE;
154}
155
156static FNFCISTATUS(cb_status)
157{
158 if (pv) {
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200159 _Py_IDENTIFIER(status);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200160
161 PyObject *result = _PyObject_CallMethodId(pv, &PyId_status, "iii", typeStatus, cb1, cb2);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 if (result == NULL)
163 return -1;
164 Py_DECREF(result);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000165 }
166 return 0;
167}
168
169static FNFCIGETNEXTCABINET(cb_getnextcabinet)
170{
171 if (pv) {
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200172 _Py_IDENTIFIER(getnextcabinet);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200173
174 PyObject *result = _PyObject_CallMethodId(pv, &PyId_getnextcabinet, "i", pccab->iCab);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 if (result == NULL)
176 return -1;
177 if (!PyBytes_Check(result)) {
178 PyErr_Format(PyExc_TypeError,
179 "Incorrect return type %s from getnextcabinet",
180 result->ob_type->tp_name);
181 Py_DECREF(result);
182 return FALSE;
183 }
184 strncpy(pccab->szCab, PyBytes_AsString(result), sizeof(pccab->szCab));
185 return TRUE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000186 }
187 return FALSE;
188}
189
190static FNFCIGETOPENINFO(cb_getopeninfo)
191{
192 BY_HANDLE_FILE_INFORMATION bhfi;
193 FILETIME filetime;
194 HANDLE handle;
195
Serhiy Storchakaba67d732020-06-30 11:56:03 +0300196 wchar_t *ws = utf8_to_wchar(pszName, err);
197 if (ws == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000198 return -1;
Serhiy Storchakaba67d732020-06-30 11:56:03 +0300199 }
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000200
Serhiy Storchakaba67d732020-06-30 11:56:03 +0300201 /* Need Win32 handle to get time stamps */
202 handle = CreateFileW(ws, GENERIC_READ, FILE_SHARE_READ, NULL,
203 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
204 if (handle == INVALID_HANDLE_VALUE) {
205 PyMem_Free(ws);
206 return -1;
207 }
208
209 if (GetFileInformationByHandle(handle, &bhfi) == FALSE) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 CloseHandle(handle);
Serhiy Storchakaba67d732020-06-30 11:56:03 +0300211 PyMem_Free(ws);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 return -1;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000213 }
214
215 FileTimeToLocalFileTime(&bhfi.ftLastWriteTime, &filetime);
216 FileTimeToDosDateTime(&filetime, pdate, ptime);
217
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000218 *pattribs = (int)(bhfi.dwFileAttributes &
219 (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH));
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000220
221 CloseHandle(handle);
222
Serhiy Storchakaba67d732020-06-30 11:56:03 +0300223 int result = _wopen(ws, _O_RDONLY | _O_BINARY | O_NOINHERIT);
224 PyMem_Free(ws);
225 return result;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000226}
227
228static PyObject* fcicreate(PyObject* obj, PyObject* args)
229{
Christian Heimes0bd4e112008-02-12 22:59:25 +0000230 char *cabname, *p;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000231 PyObject *files;
232 CCAB ccab;
233 HFCI hfci;
234 ERF erf;
Christian Heimes0bd4e112008-02-12 22:59:25 +0000235 Py_ssize_t i;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000236
237
238 if (!PyArg_ParseTuple(args, "sO:FCICreate", &cabname, &files))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000240
241 if (!PyList_Check(files)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 PyErr_SetString(PyExc_TypeError, "FCICreate expects a list");
243 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000244 }
245
246 ccab.cb = INT_MAX; /* no need to split CAB into multiple media */
247 ccab.cbFolderThresh = 1000000; /* flush directory after this many bytes */
248 ccab.cbReserveCFData = 0;
249 ccab.cbReserveCFFolder = 0;
250 ccab.cbReserveCFHeader = 0;
251
252 ccab.iCab = 1;
253 ccab.iDisk = 1;
254
255 ccab.setID = 0;
256 ccab.szDisk[0] = '\0';
257
Serhiy Storchakaba67d732020-06-30 11:56:03 +0300258 for (i = 0, p = cabname; *p; p++)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 if (*p == '\\' || *p == '/')
260 i = p - cabname + 1;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000261
Christian Heimes0bd4e112008-02-12 22:59:25 +0000262 if (i >= sizeof(ccab.szCabPath) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 strlen(cabname+i) >= sizeof(ccab.szCab)) {
264 PyErr_SetString(PyExc_ValueError, "path name too long");
265 return 0;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000266 }
267
Christian Heimes0bd4e112008-02-12 22:59:25 +0000268 if (i > 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 memcpy(ccab.szCabPath, cabname, i);
270 ccab.szCabPath[i] = '\0';
271 strcpy(ccab.szCab, cabname+i);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000272 } else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 strcpy(ccab.szCabPath, ".\\");
274 strcpy(ccab.szCab, cabname);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000275 }
276
277 hfci = FCICreate(&erf, cb_fileplaced, cb_alloc, cb_free,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 cb_open, cb_read, cb_write, cb_close, cb_seek, cb_delete,
279 cb_gettempfile, &ccab, NULL);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000280
281 if (hfci == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper);
283 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000284 }
285
286 for (i=0; i < PyList_GET_SIZE(files); i++) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 PyObject *item = PyList_GET_ITEM(files, i);
288 char *filename, *cabname;
Zachary Ware0a29e892015-05-18 00:47:15 -0500289
290 if (!PyArg_ParseTuple(item, "ss", &filename, &cabname)) {
291 PyErr_SetString(PyExc_TypeError, "FCICreate expects a list of tuples containing two strings");
292 FCIDestroy(hfci);
293 return NULL;
294 }
295
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296 if (!FCIAddFile(hfci, filename, cabname, FALSE,
297 cb_getnextcabinet, cb_status, cb_getopeninfo,
298 tcompTYPE_MSZIP))
299 goto err;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000300 }
301
302 if (!FCIFlushCabinet(hfci, FALSE, cb_getnextcabinet, cb_status))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 goto err;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000304
305 if (!FCIDestroy(hfci))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 goto err;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000307
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200308 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000309err:
Zachary Ware0a29e892015-05-18 00:47:15 -0500310 if(erf.fError)
311 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
312 else
313 PyErr_SetString(PyExc_ValueError, "FCI general error");
314
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000315 FCIDestroy(hfci);
316 return NULL;
317}
318
319typedef struct msiobj{
320 PyObject_HEAD
321 MSIHANDLE h;
322}msiobj;
323
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324static void
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000325msiobj_dealloc(msiobj* msidb)
326{
327 MsiCloseHandle(msidb->h);
328 msidb->h = 0;
Zackery Spytzcb04f752017-11-07 03:03:09 -0700329 PyObject_Del(msidb);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000330}
331
332static PyObject*
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000333msierror(int status)
334{
335 int code;
336 char buf[2000];
337 char *res = buf;
338 DWORD size = sizeof(buf);
339 MSIHANDLE err = MsiGetLastErrorRecord();
340
341 if (err == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000342 switch(status) {
343 case ERROR_ACCESS_DENIED:
344 PyErr_SetString(MSIError, "access denied");
345 return NULL;
346 case ERROR_FUNCTION_FAILED:
347 PyErr_SetString(MSIError, "function failed");
348 return NULL;
349 case ERROR_INVALID_DATA:
350 PyErr_SetString(MSIError, "invalid data");
351 return NULL;
352 case ERROR_INVALID_HANDLE:
353 PyErr_SetString(MSIError, "invalid handle");
354 return NULL;
355 case ERROR_INVALID_STATE:
356 PyErr_SetString(MSIError, "invalid state");
357 return NULL;
358 case ERROR_INVALID_PARAMETER:
359 PyErr_SetString(MSIError, "invalid parameter");
360 return NULL;
Berker Peksag4864a612017-11-24 12:53:58 +0300361 case ERROR_OPEN_FAILED:
362 PyErr_SetString(MSIError, "open failed");
363 return NULL;
364 case ERROR_CREATE_FAILED:
365 PyErr_SetString(MSIError, "create failed");
366 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 default:
368 PyErr_Format(MSIError, "unknown error %x", status);
369 return NULL;
370 }
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000371 }
372
373 code = MsiRecordGetInteger(err, 1); /* XXX code */
374 if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000375 res = malloc(size+1);
Zackery Spytz4e519372018-09-07 16:02:56 -0600376 if (res == NULL) {
377 MsiCloseHandle(err);
378 return PyErr_NoMemory();
379 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000380 MsiFormatRecord(0, err, res, &size);
381 res[size]='\0';
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000382 }
383 MsiCloseHandle(err);
384 PyErr_SetString(MSIError, res);
385 if (res != buf)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 free(res);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000387 return NULL;
388}
389
Berker Peksaga9356542017-11-07 15:58:53 +0300390static PyObject*
391msidb_close(msiobj* msidb, PyObject *args)
392{
393 int status;
394 if ((status = MsiCloseHandle(msidb->h)) != ERROR_SUCCESS) {
395 return msierror(status);
396 }
397 msidb->h = 0;
398 Py_RETURN_NONE;
399}
400
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000401/*************************** Record objects **********************/
402
403static PyObject*
404record_getfieldcount(msiobj* record, PyObject* args)
405{
Christian Heimes217cfd12007-12-02 14:31:20 +0000406 return PyLong_FromLong(MsiRecordGetFieldCount(record->h));
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000407}
408
409static PyObject*
Martin v. Löwise95593e2008-06-02 10:08:54 +0000410record_getinteger(msiobj* record, PyObject* args)
411{
412 unsigned int field;
413 int status;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414
Martin v. Löwise95593e2008-06-02 10:08:54 +0000415 if (!PyArg_ParseTuple(args, "I:GetInteger", &field))
416 return NULL;
417 status = MsiRecordGetInteger(record->h, field);
418 if (status == MSI_NULL_INTEGER){
419 PyErr_SetString(MSIError, "could not convert record field to integer");
420 return NULL;
421 }
Martin v. Löwis704d8b12008-06-02 11:32:23 +0000422 return PyLong_FromLong((long) status);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000423}
424
425static PyObject*
426record_getstring(msiobj* record, PyObject* args)
427{
428 unsigned int field;
429 unsigned int status;
Martin v. Löwis371bb502008-08-16 13:02:57 +0000430 WCHAR buf[2000];
431 WCHAR *res = buf;
Martin v. Löwise95593e2008-06-02 10:08:54 +0000432 DWORD size = sizeof(buf);
433 PyObject* string;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000434
Martin v. Löwise95593e2008-06-02 10:08:54 +0000435 if (!PyArg_ParseTuple(args, "I:GetString", &field))
436 return NULL;
Martin v. Löwis371bb502008-08-16 13:02:57 +0000437 status = MsiRecordGetStringW(record->h, field, res, &size);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000438 if (status == ERROR_MORE_DATA) {
Martin v. Löwis371bb502008-08-16 13:02:57 +0000439 res = (WCHAR*) malloc((size + 1)*sizeof(WCHAR));
Martin v. Löwise95593e2008-06-02 10:08:54 +0000440 if (res == NULL)
441 return PyErr_NoMemory();
Martin v. Löwis371bb502008-08-16 13:02:57 +0000442 status = MsiRecordGetStringW(record->h, field, res, &size);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000443 }
444 if (status != ERROR_SUCCESS)
445 return msierror((int) status);
Victor Stinner9d3b93b2011-11-22 02:27:30 +0100446 string = PyUnicode_FromWideChar(res, size);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000447 if (buf != res)
448 free(res);
449 return string;
450}
451
452static PyObject*
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000453record_cleardata(msiobj* record, PyObject *args)
454{
455 int status = MsiRecordClearData(record->h);
456 if (status != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000458
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200459 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000460}
461
462static PyObject*
463record_setstring(msiobj* record, PyObject *args)
464{
465 int status;
466 int field;
Victor Stinner9d3b93b2011-11-22 02:27:30 +0100467 wchar_t *data;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000468
Martin v. Löwis371bb502008-08-16 13:02:57 +0000469 if (!PyArg_ParseTuple(args, "iu:SetString", &field, &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000471
Martin v. Löwis371bb502008-08-16 13:02:57 +0000472 if ((status = MsiRecordSetStringW(record->h, field, data)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000473 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000474
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200475 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000476}
477
478static PyObject*
479record_setstream(msiobj* record, PyObject *args)
480{
481 int status;
482 int field;
Victor Stinner9d3b93b2011-11-22 02:27:30 +0100483 wchar_t *data;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000484
Martin v. Löwis371bb502008-08-16 13:02:57 +0000485 if (!PyArg_ParseTuple(args, "iu:SetStream", &field, &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000486 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000487
Martin v. Löwis371bb502008-08-16 13:02:57 +0000488 if ((status = MsiRecordSetStreamW(record->h, field, data)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000490
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200491 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000492}
493
494static PyObject*
495record_setinteger(msiobj* record, PyObject *args)
496{
497 int status;
498 int field;
499 int data;
500
501 if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000502 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000503
504 if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000505 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000506
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200507 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000508}
509
510
511
512static PyMethodDef record_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000513 { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS,
514 PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")},
Martin v. Löwise95593e2008-06-02 10:08:54 +0000515 { "GetInteger", (PyCFunction)record_getinteger, METH_VARARGS,
516 PyDoc_STR("GetInteger(field) -> int\nWraps MsiRecordGetInteger")},
517 { "GetString", (PyCFunction)record_getstring, METH_VARARGS,
518 PyDoc_STR("GetString(field) -> string\nWraps MsiRecordGetString")},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000519 { "SetString", (PyCFunction)record_setstring, METH_VARARGS,
520 PyDoc_STR("SetString(field,str) -> None\nWraps MsiRecordSetString")},
521 { "SetStream", (PyCFunction)record_setstream, METH_VARARGS,
522 PyDoc_STR("SetStream(field,filename) -> None\nWraps MsiRecordSetInteger")},
523 { "SetInteger", (PyCFunction)record_setinteger, METH_VARARGS,
524 PyDoc_STR("SetInteger(field,int) -> None\nWraps MsiRecordSetInteger")},
525 { "ClearData", (PyCFunction)record_cleardata, METH_NOARGS,
526 PyDoc_STR("ClearData() -> int\nWraps MsiRecordGClearData")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000527 { NULL, NULL }
528};
529
530static PyTypeObject record_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000531 PyVarObject_HEAD_INIT(NULL, 0)
532 "_msi.Record", /*tp_name*/
533 sizeof(msiobj), /*tp_basicsize*/
534 0, /*tp_itemsize*/
535 /* methods */
536 (destructor)msiobj_dealloc, /*tp_dealloc*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200537 0, /*tp_vectorcall_offset*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000538 0, /*tp_getattr*/
539 0, /*tp_setattr*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200540 0, /*tp_as_async*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000541 0, /*tp_repr*/
542 0, /*tp_as_number*/
543 0, /*tp_as_sequence*/
544 0, /*tp_as_mapping*/
545 0, /*tp_hash*/
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000546 0, /*tp_call*/
547 0, /*tp_str*/
548 PyObject_GenericGetAttr,/*tp_getattro*/
549 PyObject_GenericSetAttr,/*tp_setattro*/
550 0, /*tp_as_buffer*/
551 Py_TPFLAGS_DEFAULT, /*tp_flags*/
552 0, /*tp_doc*/
553 0, /*tp_traverse*/
554 0, /*tp_clear*/
555 0, /*tp_richcompare*/
556 0, /*tp_weaklistoffset*/
557 0, /*tp_iter*/
558 0, /*tp_iternext*/
559 record_methods, /*tp_methods*/
560 0, /*tp_members*/
561 0, /*tp_getset*/
562 0, /*tp_base*/
563 0, /*tp_dict*/
564 0, /*tp_descr_get*/
565 0, /*tp_descr_set*/
566 0, /*tp_dictoffset*/
567 0, /*tp_init*/
568 0, /*tp_alloc*/
569 0, /*tp_new*/
570 0, /*tp_free*/
571 0, /*tp_is_gc*/
572};
573
574static PyObject*
575record_new(MSIHANDLE h)
576{
Victor Stinner92055202020-04-08 00:38:15 +0200577 msiobj *result = PyObject_New(struct msiobj, &record_Type);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000578
579 if (!result) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000580 MsiCloseHandle(h);
581 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000582 }
583
584 result->h = h;
585 return (PyObject*)result;
586}
587
588/*************************** SummaryInformation objects **************/
589
590static PyObject*
591summary_getproperty(msiobj* si, PyObject *args)
592{
593 int status;
594 int field;
595 PyObject *result;
596 UINT type;
597 INT ival;
598 FILETIME fval;
599 char sbuf[1000];
600 char *sval = sbuf;
Tzu-ping Chung2de576e2019-02-03 01:13:23 +0800601 DWORD ssize = sizeof(sbuf);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000602
603 if (!PyArg_ParseTuple(args, "i:GetProperty", &field))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000604 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000605
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000606 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
607 &fval, sval, &ssize);
Thomas Wouters89f507f2006-12-13 04:49:30 +0000608 if (status == ERROR_MORE_DATA) {
Tzu-ping Chung2de576e2019-02-03 01:13:23 +0800609 ssize++;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 sval = malloc(ssize);
Zackery Spytz4e519372018-09-07 16:02:56 -0600611 if (sval == NULL) {
612 return PyErr_NoMemory();
613 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000614 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
615 &fval, sval, &ssize);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000616 }
Zackery Spytz549e55a2019-05-31 18:16:20 -0600617 if (status != ERROR_SUCCESS) {
618 return msierror(status);
619 }
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000620
621 switch(type) {
Tzu-ping Chung2de576e2019-02-03 01:13:23 +0800622 case VT_I2:
623 case VT_I4:
624 result = PyLong_FromLong(ival);
625 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000626 case VT_FILETIME:
627 PyErr_SetString(PyExc_NotImplementedError, "FILETIME result");
Tzu-ping Chung2de576e2019-02-03 01:13:23 +0800628 result = NULL;
629 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000630 case VT_LPSTR:
631 result = PyBytes_FromStringAndSize(sval, ssize);
Tzu-ping Chung2de576e2019-02-03 01:13:23 +0800632 break;
Berker Peksag19fb1342017-11-24 18:11:18 +0300633 case VT_EMPTY:
Tzu-ping Chung2de576e2019-02-03 01:13:23 +0800634 Py_INCREF(Py_None);
635 result = Py_None;
636 break;
637 default:
638 PyErr_Format(PyExc_NotImplementedError, "result of type %d", type);
639 result = NULL;
640 break;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000641 }
Tzu-ping Chung2de576e2019-02-03 01:13:23 +0800642 if (sval != sbuf)
643 free(sval);
644 return result;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000645}
646
647static PyObject*
648summary_getpropertycount(msiobj* si, PyObject *args)
649{
650 int status;
651 UINT result;
652
653 status = MsiSummaryInfoGetPropertyCount(si->h, &result);
654 if (status != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000655 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000656
Christian Heimes217cfd12007-12-02 14:31:20 +0000657 return PyLong_FromLong(result);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000658}
659
660static PyObject*
661summary_setproperty(msiobj* si, PyObject *args)
662{
663 int status;
664 int field;
665 PyObject* data;
666
667 if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000668 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000669
Martin v. Löwis371bb502008-08-16 13:02:57 +0000670 if (PyUnicode_Check(data)) {
Serhiy Storchakaccdc09e2017-06-28 09:55:22 +0300671 const WCHAR *value = _PyUnicode_AsUnicode(data);
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300672 if (value == NULL) {
673 return NULL;
674 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000675 status = MsiSummaryInfoSetPropertyW(si->h, field, VT_LPSTR,
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300676 0, NULL, value);
Martin v. Löwisd1a1d1e2007-12-04 22:10:37 +0000677 } else if (PyLong_CheckExact(data)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000678 long value = PyLong_AsLong(data);
679 if (value == -1 && PyErr_Occurred()) {
680 return NULL;
681 }
682 status = MsiSummaryInfoSetProperty(si->h, field, VT_I4,
683 value, NULL, NULL);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000684 } else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000685 PyErr_SetString(PyExc_TypeError, "unsupported type");
686 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000687 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000688
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000689 if (status != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000690 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000691
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200692 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000693}
694
695
696static PyObject*
697summary_persist(msiobj* si, PyObject *args)
698{
699 int status;
700
701 status = MsiSummaryInfoPersist(si->h);
702 if (status != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000703 return msierror(status);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200704 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000705}
706
707static PyMethodDef summary_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000708 { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS,
709 PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")},
710 { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS,
711 PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")},
712 { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS,
713 PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")},
714 { "Persist", (PyCFunction)summary_persist, METH_NOARGS,
715 PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000716 { NULL, NULL }
717};
718
719static PyTypeObject summary_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000720 PyVarObject_HEAD_INIT(NULL, 0)
721 "_msi.SummaryInformation", /*tp_name*/
722 sizeof(msiobj), /*tp_basicsize*/
723 0, /*tp_itemsize*/
724 /* methods */
725 (destructor)msiobj_dealloc, /*tp_dealloc*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200726 0, /*tp_vectorcall_offset*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000727 0, /*tp_getattr*/
728 0, /*tp_setattr*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200729 0, /*tp_as_async*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000730 0, /*tp_repr*/
731 0, /*tp_as_number*/
732 0, /*tp_as_sequence*/
733 0, /*tp_as_mapping*/
734 0, /*tp_hash*/
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000735 0, /*tp_call*/
736 0, /*tp_str*/
737 PyObject_GenericGetAttr,/*tp_getattro*/
738 PyObject_GenericSetAttr,/*tp_setattro*/
739 0, /*tp_as_buffer*/
740 Py_TPFLAGS_DEFAULT, /*tp_flags*/
741 0, /*tp_doc*/
742 0, /*tp_traverse*/
743 0, /*tp_clear*/
744 0, /*tp_richcompare*/
745 0, /*tp_weaklistoffset*/
746 0, /*tp_iter*/
747 0, /*tp_iternext*/
748 summary_methods, /*tp_methods*/
749 0, /*tp_members*/
750 0, /*tp_getset*/
751 0, /*tp_base*/
752 0, /*tp_dict*/
753 0, /*tp_descr_get*/
754 0, /*tp_descr_set*/
755 0, /*tp_dictoffset*/
756 0, /*tp_init*/
757 0, /*tp_alloc*/
758 0, /*tp_new*/
759 0, /*tp_free*/
760 0, /*tp_is_gc*/
761};
762
763/*************************** View objects **************/
764
765static PyObject*
766view_execute(msiobj *view, PyObject*args)
767{
768 int status;
769 MSIHANDLE params = 0;
770 PyObject *oparams = Py_None;
771
772 if (!PyArg_ParseTuple(args, "O:Execute", &oparams))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000773 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000774
775 if (oparams != Py_None) {
776 if (oparams->ob_type != &record_Type) {
777 PyErr_SetString(PyExc_TypeError, "Execute argument must be a record");
778 return NULL;
779 }
780 params = ((msiobj*)oparams)->h;
781 }
782
783 status = MsiViewExecute(view->h, params);
784 if (status != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000785 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000786
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200787 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000788}
789
790static PyObject*
791view_fetch(msiobj *view, PyObject*args)
792{
793 int status;
794 MSIHANDLE result;
795
Berker Peksagbdb83152017-11-23 15:47:30 +0300796 status = MsiViewFetch(view->h, &result);
797 if (status == ERROR_NO_MORE_ITEMS) {
798 Py_RETURN_NONE;
799 } else if (status != ERROR_SUCCESS) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000800 return msierror(status);
Berker Peksagbdb83152017-11-23 15:47:30 +0300801 }
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000802
803 return record_new(result);
804}
805
806static PyObject*
807view_getcolumninfo(msiobj *view, PyObject *args)
808{
809 int status;
810 int kind;
811 MSIHANDLE result;
812
813 if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000814 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000815
816 if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000817 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000818
819 return record_new(result);
820}
821
822static PyObject*
823view_modify(msiobj *view, PyObject *args)
824{
825 int kind;
826 PyObject *data;
827 int status;
828
829 if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000830 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000831
832 if (data->ob_type != &record_Type) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000833 PyErr_SetString(PyExc_TypeError, "Modify expects a record object");
834 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000835 }
836
837 if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000838 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000839
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200840 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000841}
842
843static PyObject*
844view_close(msiobj *view, PyObject*args)
845{
846 int status;
847
848 if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000849 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000850
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200851 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000852}
853
854static PyMethodDef view_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000855 { "Execute", (PyCFunction)view_execute, METH_VARARGS,
856 PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000857 { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000858 PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000859 { "Fetch", (PyCFunction)view_fetch, METH_NOARGS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000860 PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000861 { "Modify", (PyCFunction)view_modify, METH_VARARGS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000862 PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000863 { "Close", (PyCFunction)view_close, METH_NOARGS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000864 PyDoc_STR("Close() -> result\nWraps MsiViewClose")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000865 { NULL, NULL }
866};
867
868static PyTypeObject msiview_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000869 PyVarObject_HEAD_INIT(NULL, 0)
870 "_msi.View", /*tp_name*/
871 sizeof(msiobj), /*tp_basicsize*/
872 0, /*tp_itemsize*/
873 /* methods */
874 (destructor)msiobj_dealloc, /*tp_dealloc*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200875 0, /*tp_vectorcall_offset*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000876 0, /*tp_getattr*/
877 0, /*tp_setattr*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200878 0, /*tp_as_async*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000879 0, /*tp_repr*/
880 0, /*tp_as_number*/
881 0, /*tp_as_sequence*/
882 0, /*tp_as_mapping*/
883 0, /*tp_hash*/
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000884 0, /*tp_call*/
885 0, /*tp_str*/
886 PyObject_GenericGetAttr,/*tp_getattro*/
887 PyObject_GenericSetAttr,/*tp_setattro*/
888 0, /*tp_as_buffer*/
889 Py_TPFLAGS_DEFAULT, /*tp_flags*/
890 0, /*tp_doc*/
891 0, /*tp_traverse*/
892 0, /*tp_clear*/
893 0, /*tp_richcompare*/
894 0, /*tp_weaklistoffset*/
895 0, /*tp_iter*/
896 0, /*tp_iternext*/
897 view_methods, /*tp_methods*/
898 0, /*tp_members*/
899 0, /*tp_getset*/
900 0, /*tp_base*/
901 0, /*tp_dict*/
902 0, /*tp_descr_get*/
903 0, /*tp_descr_set*/
904 0, /*tp_dictoffset*/
905 0, /*tp_init*/
906 0, /*tp_alloc*/
907 0, /*tp_new*/
908 0, /*tp_free*/
909 0, /*tp_is_gc*/
910};
911
912/*************************** Database objects **************/
913
914static PyObject*
915msidb_openview(msiobj *msidb, PyObject *args)
916{
917 int status;
Serhiy Storchaka55939b12020-06-25 11:37:12 +0300918 const wchar_t *sql;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000919 MSIHANDLE hView;
920 msiobj *result;
921
Serhiy Storchaka55939b12020-06-25 11:37:12 +0300922 if (!PyArg_ParseTuple(args, "u:OpenView", &sql))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000923 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000924
Serhiy Storchaka55939b12020-06-25 11:37:12 +0300925 if ((status = MsiDatabaseOpenViewW(msidb->h, sql, &hView)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000926 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000927
Victor Stinner92055202020-04-08 00:38:15 +0200928 result = PyObject_New(struct msiobj, &msiview_Type);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000929 if (!result) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000930 MsiCloseHandle(hView);
931 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000932 }
933
934 result->h = hView;
935 return (PyObject*)result;
936}
937
938static PyObject*
939msidb_commit(msiobj *msidb, PyObject *args)
940{
941 int status;
942
943 if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000944 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000945
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200946 Py_RETURN_NONE;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000947}
948
949static PyObject*
950msidb_getsummaryinformation(msiobj *db, PyObject *args)
951{
952 int status;
953 int count;
954 MSIHANDLE result;
955 msiobj *oresult;
956
957 if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000958 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000959
960 status = MsiGetSummaryInformation(db->h, NULL, count, &result);
961 if (status != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000962 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000963
Victor Stinner92055202020-04-08 00:38:15 +0200964 oresult = PyObject_New(struct msiobj, &summary_Type);
Zackery Spytzbf94cc72019-03-07 11:20:13 -0700965 if (!oresult) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000966 MsiCloseHandle(result);
967 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000968 }
969
970 oresult->h = result;
971 return (PyObject*)oresult;
972}
973
974static PyMethodDef db_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000975 { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS,
976 PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000977 { "Commit", (PyCFunction)msidb_commit, METH_NOARGS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000978 PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")},
979 { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS,
980 PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")},
Berker Peksaga9356542017-11-07 15:58:53 +0300981 { "Close", (PyCFunction)msidb_close, METH_NOARGS,
982 PyDoc_STR("Close() -> None\nWraps MsiCloseHandle")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000983 { NULL, NULL }
984};
985
986static PyTypeObject msidb_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000987 PyVarObject_HEAD_INIT(NULL, 0)
988 "_msi.Database", /*tp_name*/
989 sizeof(msiobj), /*tp_basicsize*/
990 0, /*tp_itemsize*/
991 /* methods */
992 (destructor)msiobj_dealloc, /*tp_dealloc*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200993 0, /*tp_vectorcall_offset*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000994 0, /*tp_getattr*/
995 0, /*tp_setattr*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200996 0, /*tp_as_async*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000997 0, /*tp_repr*/
998 0, /*tp_as_number*/
999 0, /*tp_as_sequence*/
1000 0, /*tp_as_mapping*/
1001 0, /*tp_hash*/
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001002 0, /*tp_call*/
1003 0, /*tp_str*/
1004 PyObject_GenericGetAttr,/*tp_getattro*/
1005 PyObject_GenericSetAttr,/*tp_setattro*/
1006 0, /*tp_as_buffer*/
1007 Py_TPFLAGS_DEFAULT, /*tp_flags*/
1008 0, /*tp_doc*/
1009 0, /*tp_traverse*/
1010 0, /*tp_clear*/
1011 0, /*tp_richcompare*/
1012 0, /*tp_weaklistoffset*/
1013 0, /*tp_iter*/
1014 0, /*tp_iternext*/
1015 db_methods, /*tp_methods*/
1016 0, /*tp_members*/
1017 0, /*tp_getset*/
1018 0, /*tp_base*/
1019 0, /*tp_dict*/
1020 0, /*tp_descr_get*/
1021 0, /*tp_descr_set*/
1022 0, /*tp_dictoffset*/
1023 0, /*tp_init*/
1024 0, /*tp_alloc*/
1025 0, /*tp_new*/
1026 0, /*tp_free*/
1027 0, /*tp_is_gc*/
1028};
1029
Steve Dower6ceda632016-09-09 11:56:34 -07001030#define Py_NOT_PERSIST(x, flag) \
Segev Finer679b5662017-07-27 01:17:57 +03001031 (x != (SIZE_T)(flag) && \
1032 x != ((SIZE_T)(flag) | MSIDBOPEN_PATCHFILE))
Steve Dower6ceda632016-09-09 11:56:34 -07001033
1034#define Py_INVALID_PERSIST(x) \
1035 (Py_NOT_PERSIST(x, MSIDBOPEN_READONLY) && \
1036 Py_NOT_PERSIST(x, MSIDBOPEN_TRANSACT) && \
1037 Py_NOT_PERSIST(x, MSIDBOPEN_DIRECT) && \
1038 Py_NOT_PERSIST(x, MSIDBOPEN_CREATE) && \
1039 Py_NOT_PERSIST(x, MSIDBOPEN_CREATEDIRECT))
1040
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001041static PyObject* msiopendb(PyObject *obj, PyObject *args)
1042{
1043 int status;
Serhiy Storchaka55939b12020-06-25 11:37:12 +03001044 const wchar_t *path;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001045 int persist;
1046 MSIHANDLE h;
1047 msiobj *result;
Serhiy Storchaka55939b12020-06-25 11:37:12 +03001048 if (!PyArg_ParseTuple(args, "ui:MSIOpenDatabase", &path, &persist))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001049 return NULL;
Steve Dower6ceda632016-09-09 11:56:34 -07001050 /* We need to validate that persist is a valid MSIDBOPEN_* value. Otherwise,
1051 MsiOpenDatabase may treat the value as a pointer, leading to unexpected
1052 behavior. */
1053 if (Py_INVALID_PERSIST(persist))
1054 return msierror(ERROR_INVALID_PARAMETER);
Serhiy Storchaka55939b12020-06-25 11:37:12 +03001055 status = MsiOpenDatabaseW(path, (LPCWSTR)(SIZE_T)persist, &h);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001056 if (status != ERROR_SUCCESS)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001057 return msierror(status);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001058
Victor Stinner92055202020-04-08 00:38:15 +02001059 result = PyObject_New(struct msiobj, &msidb_Type);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001060 if (!result) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001061 MsiCloseHandle(h);
1062 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001063 }
1064 result->h = h;
1065 return (PyObject*)result;
1066}
1067
1068static PyObject*
1069createrecord(PyObject *o, PyObject *args)
1070{
1071 int count;
1072 MSIHANDLE h;
1073
1074 if (!PyArg_ParseTuple(args, "i:CreateRecord", &count))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001075 return NULL;
1076
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001077 h = MsiCreateRecord(count);
1078 if (h == 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001079 return msierror(0);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001080
1081 return record_new(h);
1082}
1083
1084
1085static PyMethodDef msi_methods[] = {
1086 {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001087 PyDoc_STR("UuidCreate() -> string")},
1088 {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS,
1089 PyDoc_STR("fcicreate(cabname,files) -> None")},
1090 {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS,
1091 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")},
1092 {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS,
1093 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")},
1094 {NULL, NULL} /* sentinel */
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001095};
1096
1097static char msi_doc[] = "Documentation";
1098
Martin v. Löwis1a214512008-06-11 05:26:20 +00001099
1100static struct PyModuleDef _msimodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001101 PyModuleDef_HEAD_INIT,
1102 "_msi",
1103 msi_doc,
1104 -1,
1105 msi_methods,
1106 NULL,
1107 NULL,
1108 NULL,
1109 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001110};
1111
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001112PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001113PyInit__msi(void)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001114{
1115 PyObject *m;
1116
Martin v. Löwis1a214512008-06-11 05:26:20 +00001117 m = PyModule_Create(&_msimodule);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001118 if (m == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001119 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001120
Segev Finer679b5662017-07-27 01:17:57 +03001121 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (long)(SIZE_T)MSIDBOPEN_CREATEDIRECT);
1122 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (long)(SIZE_T)MSIDBOPEN_CREATE);
1123 PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (long)(SIZE_T)MSIDBOPEN_DIRECT);
1124 PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (long)(SIZE_T)MSIDBOPEN_READONLY);
1125 PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (long)(SIZE_T)MSIDBOPEN_TRANSACT);
1126 PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (long)(SIZE_T)MSIDBOPEN_PATCHFILE);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001127
Charles-Francois Natali74ca8862013-05-20 19:13:19 +02001128 PyModule_AddIntMacro(m, MSICOLINFO_NAMES);
1129 PyModule_AddIntMacro(m, MSICOLINFO_TYPES);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001130
Charles-Francois Natali74ca8862013-05-20 19:13:19 +02001131 PyModule_AddIntMacro(m, MSIMODIFY_SEEK);
1132 PyModule_AddIntMacro(m, MSIMODIFY_REFRESH);
1133 PyModule_AddIntMacro(m, MSIMODIFY_INSERT);
1134 PyModule_AddIntMacro(m, MSIMODIFY_UPDATE);
1135 PyModule_AddIntMacro(m, MSIMODIFY_ASSIGN);
1136 PyModule_AddIntMacro(m, MSIMODIFY_REPLACE);
1137 PyModule_AddIntMacro(m, MSIMODIFY_MERGE);
1138 PyModule_AddIntMacro(m, MSIMODIFY_DELETE);
1139 PyModule_AddIntMacro(m, MSIMODIFY_INSERT_TEMPORARY);
1140 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE);
1141 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_NEW);
1142 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_FIELD);
1143 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_DELETE);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001144
Charles-Francois Natali74ca8862013-05-20 19:13:19 +02001145 PyModule_AddIntMacro(m, PID_CODEPAGE);
1146 PyModule_AddIntMacro(m, PID_TITLE);
1147 PyModule_AddIntMacro(m, PID_SUBJECT);
1148 PyModule_AddIntMacro(m, PID_AUTHOR);
1149 PyModule_AddIntMacro(m, PID_KEYWORDS);
1150 PyModule_AddIntMacro(m, PID_COMMENTS);
1151 PyModule_AddIntMacro(m, PID_TEMPLATE);
1152 PyModule_AddIntMacro(m, PID_LASTAUTHOR);
1153 PyModule_AddIntMacro(m, PID_REVNUMBER);
1154 PyModule_AddIntMacro(m, PID_LASTPRINTED);
1155 PyModule_AddIntMacro(m, PID_CREATE_DTM);
1156 PyModule_AddIntMacro(m, PID_LASTSAVE_DTM);
1157 PyModule_AddIntMacro(m, PID_PAGECOUNT);
1158 PyModule_AddIntMacro(m, PID_WORDCOUNT);
1159 PyModule_AddIntMacro(m, PID_CHARCOUNT);
1160 PyModule_AddIntMacro(m, PID_APPNAME);
1161 PyModule_AddIntMacro(m, PID_SECURITY);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001162
1163 MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL);
1164 if (!MSIError)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001165 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001166 PyModule_AddObject(m, "MSIError", MSIError);
Amaury Forgeot d'Arcbf9e9662008-06-17 21:39:46 +00001167 return m;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001168}