python-msilib 0.4.2__cp314-cp314-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
msilib/_msi.c ADDED
@@ -0,0 +1,1260 @@
1
+ /* Helper library for MSI creation with Python.
2
+ * Copyright (C) 2005 Martin v. Löwis
3
+ * Licensed to PSF under a contributor agreement.
4
+ */
5
+
6
+ #define PY_SSIZE_T_CLEAN
7
+ #include <Python.h>
8
+ // clang-format off
9
+ #include <windows.h>
10
+ // clang-format on
11
+ #include "include/pythoncapi_compat.h"
12
+ #include <fci.h>
13
+ #include <fcntl.h>
14
+ #include <msi.h>
15
+ #include <msidefs.h>
16
+ #include <msiquery.h>
17
+ #include <rpc.h>
18
+
19
+ /*[clinic input]
20
+ module _msi
21
+ class _msi.Record "msiobj *" "&record_Type"
22
+ class _msi.SummaryInformation "msiobj *" "&summary_Type"
23
+ class _msi.View "msiobj *" "&msiview_Type"
24
+ class _msi.Database "msiobj *" "&msidb_Type"
25
+ [clinic start generated code]*/
26
+ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=89a3605762cf4bdc]*/
27
+
28
+ static PyObject* MSIError;
29
+
30
+ /*[clinic input]
31
+ _msi.UuidCreate
32
+
33
+ Return the string representation of a new unique identifier.
34
+ [clinic start generated code]*/
35
+
36
+ static PyObject* _msi_UuidCreate_impl(PyObject* module)
37
+ /*[clinic end generated code: output=534ecf36f10af98e input=168024ab4b3e832b]*/
38
+ {
39
+ UUID result;
40
+ wchar_t* cresult;
41
+ PyObject* oresult;
42
+
43
+ /* May return ok, local only, and no address.
44
+ For local only, the documentation says we still get a uuid.
45
+ For RPC_S_UUID_NO_ADDRESS, it's not clear whether we can
46
+ use the result. */
47
+ if (UuidCreate(&result) == RPC_S_UUID_NO_ADDRESS) {
48
+ PyErr_SetString(
49
+ PyExc_NotImplementedError, "processing 'no address' result");
50
+ return NULL;
51
+ }
52
+
53
+ if (UuidToStringW(&result, &cresult) == RPC_S_OUT_OF_MEMORY) {
54
+ PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen");
55
+ return NULL;
56
+ }
57
+
58
+ oresult = PyUnicode_FromWideChar(cresult, wcslen(cresult));
59
+ RpcStringFreeW(&cresult);
60
+ return oresult;
61
+ }
62
+
63
+ /* Helper for converting file names from UTF-8 to wchat_t*. */
64
+ static wchar_t* utf8_to_wchar(const char* s, int* err)
65
+ {
66
+ PyObject* obj = PyUnicode_FromString(s);
67
+ if (obj == NULL) {
68
+ if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
69
+ *err = ENOMEM;
70
+ } else {
71
+ *err = EINVAL;
72
+ }
73
+ PyErr_Clear();
74
+ return NULL;
75
+ }
76
+ wchar_t* ws = PyUnicode_AsWideCharString(obj, NULL);
77
+ if (ws == NULL) {
78
+ *err = ENOMEM;
79
+ PyErr_Clear();
80
+ }
81
+ Py_DECREF(obj);
82
+ return ws;
83
+ }
84
+
85
+ /* FCI callback functions */
86
+
87
+ static FNFCIALLOC(cb_alloc) { return PyMem_RawMalloc(cb); }
88
+
89
+ static FNFCIFREE(cb_free) { PyMem_RawFree(memory); }
90
+
91
+ static FNFCIOPEN(cb_open)
92
+ {
93
+ wchar_t* ws = utf8_to_wchar(pszFile, err);
94
+ if (ws == NULL) {
95
+ return -1;
96
+ }
97
+ int result = _wopen(ws, oflag | O_NOINHERIT, pmode);
98
+ PyMem_Free(ws);
99
+ if (result == -1)
100
+ *err = errno;
101
+ return result;
102
+ }
103
+
104
+ static FNFCIREAD(cb_read)
105
+ {
106
+ UINT result = (UINT)_read((int)hf, memory, cb);
107
+ if (result != cb)
108
+ *err = errno;
109
+ return result;
110
+ }
111
+
112
+ static FNFCIWRITE(cb_write)
113
+ {
114
+ UINT result = (UINT)_write((int)hf, memory, cb);
115
+ if (result != cb)
116
+ *err = errno;
117
+ return result;
118
+ }
119
+
120
+ static FNFCICLOSE(cb_close)
121
+ {
122
+ int result = _close((int)hf);
123
+ if (result != 0)
124
+ *err = errno;
125
+ return result;
126
+ }
127
+
128
+ static FNFCISEEK(cb_seek)
129
+ {
130
+ long result = (long)_lseek((int)hf, dist, seektype);
131
+ if (result == -1)
132
+ *err = errno;
133
+ return result;
134
+ }
135
+
136
+ static FNFCIDELETE(cb_delete)
137
+ {
138
+ wchar_t* ws = utf8_to_wchar(pszFile, err);
139
+ if (ws == NULL) {
140
+ return -1;
141
+ }
142
+ int result = _wremove(ws);
143
+ PyMem_Free(ws);
144
+ if (result != 0)
145
+ *err = errno;
146
+ return result;
147
+ }
148
+
149
+ static FNFCIFILEPLACED(cb_fileplaced) { return 0; }
150
+
151
+ static FNFCIGETTEMPFILE(cb_gettempfile)
152
+ {
153
+ char* name = _tempnam("", "tmp");
154
+ if ((name != NULL) && ((int)strlen(name) < cbTempName)) {
155
+ strcpy(pszTempName, name);
156
+ free(name);
157
+ return TRUE;
158
+ }
159
+
160
+ if (name)
161
+ free(name);
162
+ return FALSE;
163
+ }
164
+
165
+ static FNFCISTATUS(cb_status)
166
+ {
167
+ if (pv) {
168
+ PyObject* result
169
+ = PyObject_CallMethod(pv, "status", "iii", typeStatus, cb1, cb2);
170
+ if (result == NULL)
171
+ return -1;
172
+ Py_DECREF(result);
173
+ }
174
+ return 0;
175
+ }
176
+
177
+ static FNFCIGETNEXTCABINET(cb_getnextcabinet)
178
+ {
179
+ if (pv) {
180
+ PyObject* result
181
+ = PyObject_CallMethod(pv, "getnextcabinet", "i", pccab->iCab);
182
+ if (result == NULL)
183
+ return -1;
184
+ if (!PyBytes_Check(result)) {
185
+ PyErr_Format(PyExc_TypeError,
186
+ "Incorrect return type %s from getnextcabinet",
187
+ Py_TYPE(result)->tp_name);
188
+ Py_DECREF(result);
189
+ return FALSE;
190
+ }
191
+ strncpy(pccab->szCab, PyBytes_AsString(result), sizeof(pccab->szCab));
192
+ return TRUE;
193
+ }
194
+ return FALSE;
195
+ }
196
+
197
+ static FNFCIGETOPENINFO(cb_getopeninfo)
198
+ {
199
+ BY_HANDLE_FILE_INFORMATION bhfi;
200
+ FILETIME filetime;
201
+ HANDLE handle;
202
+
203
+ wchar_t* ws = utf8_to_wchar(pszName, err);
204
+ if (ws == NULL) {
205
+ return -1;
206
+ }
207
+
208
+ /* Need Win32 handle to get time stamps */
209
+ handle = CreateFileW(ws, GENERIC_READ, FILE_SHARE_READ, NULL,
210
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
211
+ if (handle == INVALID_HANDLE_VALUE) {
212
+ PyMem_Free(ws);
213
+ return -1;
214
+ }
215
+
216
+ if (GetFileInformationByHandle(handle, &bhfi) == FALSE) {
217
+ CloseHandle(handle);
218
+ PyMem_Free(ws);
219
+ return -1;
220
+ }
221
+
222
+ FileTimeToLocalFileTime(&bhfi.ftLastWriteTime, &filetime);
223
+ FileTimeToDosDateTime(&filetime, pdate, ptime);
224
+
225
+ *pattribs = (int)(bhfi.dwFileAttributes
226
+ & (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH));
227
+
228
+ CloseHandle(handle);
229
+
230
+ int result = _wopen(ws, _O_RDONLY | _O_BINARY | O_NOINHERIT);
231
+ PyMem_Free(ws);
232
+ return result;
233
+ }
234
+
235
+ /*[clinic input]
236
+ _msi.FCICreate
237
+ cabname: str
238
+ the name of the CAB file
239
+ files: object
240
+ a list of tuples, each containing the name of the file on disk,
241
+ and the name of the file inside the CAB file
242
+ /
243
+
244
+ Create a new CAB file.
245
+ [clinic start generated code]*/
246
+
247
+ static PyObject* _msi_FCICreate_impl(
248
+ PyObject* module, const char* cabname, PyObject* files)
249
+ /*[clinic end generated code: output=55dc05728361b799 input=1d2d75fdc8b44b71]*/
250
+ {
251
+ const char* p;
252
+ CCAB ccab;
253
+ HFCI hfci;
254
+ ERF erf;
255
+ Py_ssize_t i;
256
+
257
+ if (!PyList_Check(files)) {
258
+ PyErr_SetString(PyExc_TypeError, "FCICreate expects a list");
259
+ return NULL;
260
+ }
261
+
262
+ ccab.cb = INT_MAX; /* no need to split CAB into multiple media */
263
+ ccab.cbFolderThresh = 1000000; /* flush directory after this many bytes */
264
+ ccab.cbReserveCFData = 0;
265
+ ccab.cbReserveCFFolder = 0;
266
+ ccab.cbReserveCFHeader = 0;
267
+
268
+ ccab.iCab = 1;
269
+ ccab.iDisk = 1;
270
+
271
+ ccab.setID = 0;
272
+ ccab.szDisk[0] = '\0';
273
+
274
+ for (i = 0, p = cabname; *p; p++)
275
+ if (*p == '\\' || *p == '/')
276
+ i = p - cabname + 1;
277
+
278
+ if (i >= sizeof(ccab.szCabPath)
279
+ || strlen(cabname + i) >= sizeof(ccab.szCab)) {
280
+ PyErr_SetString(PyExc_ValueError, "path name too long");
281
+ return 0;
282
+ }
283
+
284
+ if (i > 0) {
285
+ memcpy(ccab.szCabPath, cabname, i);
286
+ ccab.szCabPath[i] = '\0';
287
+ strcpy(ccab.szCab, cabname + i);
288
+ } else {
289
+ strcpy(ccab.szCabPath, ".\\");
290
+ strcpy(ccab.szCab, cabname);
291
+ }
292
+
293
+ hfci = FCICreate(&erf, cb_fileplaced, cb_alloc, cb_free, cb_open, cb_read,
294
+ cb_write, cb_close, cb_seek, cb_delete, cb_gettempfile, &ccab, NULL);
295
+
296
+ if (hfci == NULL) {
297
+ PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper);
298
+ return NULL;
299
+ }
300
+
301
+ for (i = 0; i < PyList_Size(files); i++) {
302
+ PyObject* item = PyList_GetItemRef(files, i);
303
+ char *filename, *cabname;
304
+
305
+ if (!PyArg_ParseTuple(item, "ss", &filename, &cabname)) {
306
+ PyErr_SetString(PyExc_TypeError,
307
+ "FCICreate expects a list of tuples containing two strings");
308
+ FCIDestroy(hfci);
309
+ return NULL;
310
+ }
311
+
312
+ if (!FCIAddFile(hfci, filename, cabname, FALSE, cb_getnextcabinet,
313
+ cb_status, cb_getopeninfo, tcompTYPE_MSZIP))
314
+ goto err;
315
+ }
316
+
317
+ if (!FCIFlushCabinet(hfci, FALSE, cb_getnextcabinet, cb_status))
318
+ goto err;
319
+
320
+ if (!FCIDestroy(hfci))
321
+ goto err;
322
+
323
+ Py_RETURN_NONE;
324
+ err:
325
+ if (erf.fError)
326
+ PyErr_Format(PyExc_ValueError, "FCI error %d",
327
+ erf.erfOper); /* XXX better error type */
328
+ else
329
+ PyErr_SetString(PyExc_ValueError, "FCI general error");
330
+
331
+ FCIDestroy(hfci);
332
+ return NULL;
333
+ }
334
+
335
+ typedef struct msiobj {
336
+ PyObject_HEAD MSIHANDLE h;
337
+ } msiobj;
338
+
339
+ static void msiobj_dealloc(msiobj* msidb)
340
+ {
341
+ MsiCloseHandle(msidb->h);
342
+ msidb->h = 0;
343
+ PyObject_Free(msidb);
344
+ }
345
+
346
+ static PyObject* msierror(int status)
347
+ {
348
+ int code;
349
+ char buf[2000];
350
+ char* res = buf;
351
+ DWORD size = Py_ARRAY_LENGTH(buf);
352
+ MSIHANDLE err = MsiGetLastErrorRecord();
353
+
354
+ if (err == 0) {
355
+ switch (status) {
356
+ case ERROR_ACCESS_DENIED:
357
+ PyErr_SetString(MSIError, "access denied");
358
+ return NULL;
359
+ case ERROR_FUNCTION_FAILED:
360
+ PyErr_SetString(MSIError, "function failed");
361
+ return NULL;
362
+ case ERROR_INVALID_DATA:
363
+ PyErr_SetString(MSIError, "invalid data");
364
+ return NULL;
365
+ case ERROR_INVALID_HANDLE:
366
+ PyErr_SetString(MSIError, "invalid handle");
367
+ return NULL;
368
+ case ERROR_INVALID_STATE:
369
+ PyErr_SetString(MSIError, "invalid state");
370
+ return NULL;
371
+ case ERROR_INVALID_PARAMETER:
372
+ PyErr_SetString(MSIError, "invalid parameter");
373
+ return NULL;
374
+ case ERROR_OPEN_FAILED:
375
+ PyErr_SetString(MSIError, "open failed");
376
+ return NULL;
377
+ case ERROR_CREATE_FAILED:
378
+ PyErr_SetString(MSIError, "create failed");
379
+ return NULL;
380
+ default:
381
+ PyErr_Format(MSIError, "unknown error %x", status);
382
+ return NULL;
383
+ }
384
+ }
385
+
386
+ code = MsiRecordGetInteger(err, 1); /* XXX code */
387
+ if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) {
388
+ res = malloc(size + 1);
389
+ if (res == NULL) {
390
+ MsiCloseHandle(err);
391
+ return PyErr_NoMemory();
392
+ }
393
+ MsiFormatRecord(0, err, res, &size);
394
+ res[size] = '\0';
395
+ }
396
+ MsiCloseHandle(err);
397
+ PyErr_SetString(MSIError, res);
398
+ if (res != buf)
399
+ free(res);
400
+ return NULL;
401
+ }
402
+
403
+ #include "include/_msi.h"
404
+
405
+ /*[clinic input]
406
+ _msi.Database.Close
407
+
408
+ Close the database object.
409
+ [clinic start generated code]*/
410
+
411
+ static PyObject* _msi_Database_Close_impl(msiobj* self)
412
+ /*[clinic end generated code: output=ddf2d7712ea804f1 input=104330ce4a486187]*/
413
+ {
414
+ int status;
415
+ if ((status = MsiCloseHandle(self->h)) != ERROR_SUCCESS) {
416
+ return msierror(status);
417
+ }
418
+ self->h = 0;
419
+ Py_RETURN_NONE;
420
+ }
421
+
422
+ /*************************** Record objects **********************/
423
+
424
+ /*[clinic input]
425
+ _msi.Record.GetFieldCount
426
+
427
+ Return the number of fields of the record.
428
+ [clinic start generated code]*/
429
+
430
+ static PyObject* _msi_Record_GetFieldCount_impl(msiobj* self)
431
+ /*[clinic end generated code: output=112795079c904398 input=5fb9d4071b28897b]*/
432
+ {
433
+ return PyLong_FromLong(MsiRecordGetFieldCount(self->h));
434
+ }
435
+
436
+ /*[clinic input]
437
+ _msi.Record.GetInteger
438
+ field: unsigned_int(bitwise=True)
439
+ /
440
+
441
+ Return the value of field as an integer where possible.
442
+ [clinic start generated code]*/
443
+
444
+ static PyObject* _msi_Record_GetInteger_impl(msiobj* self, unsigned int field)
445
+ /*[clinic end generated code: output=7174ebb6e8ed1c79 input=d19209947e2bfe61]*/
446
+ {
447
+ int status;
448
+
449
+ status = MsiRecordGetInteger(self->h, field);
450
+ if (status == MSI_NULL_INTEGER) {
451
+ PyErr_SetString(MSIError, "could not convert record field to integer");
452
+ return NULL;
453
+ }
454
+ return PyLong_FromLong((long)status);
455
+ }
456
+
457
+ /*[clinic input]
458
+ _msi.Record.GetString
459
+ field: unsigned_int(bitwise=True)
460
+ /
461
+
462
+ Return the value of field as a string where possible.
463
+ [clinic start generated code]*/
464
+
465
+ static PyObject* _msi_Record_GetString_impl(msiobj* self, unsigned int field)
466
+ /*[clinic end generated code: output=f670d1b484cfa47c input=ffa11f21450b77d8]*/
467
+ {
468
+ unsigned int status;
469
+ WCHAR buf[2000];
470
+ WCHAR* res = buf;
471
+ DWORD size = Py_ARRAY_LENGTH(buf);
472
+ PyObject* string;
473
+
474
+ status = MsiRecordGetStringW(self->h, field, res, &size);
475
+ if (status == ERROR_MORE_DATA) {
476
+ res = (WCHAR*)malloc((size + 1) * sizeof(WCHAR));
477
+ if (res == NULL)
478
+ return PyErr_NoMemory();
479
+ status = MsiRecordGetStringW(self->h, field, res, &size);
480
+ }
481
+ if (status != ERROR_SUCCESS)
482
+ return msierror((int)status);
483
+ string = PyUnicode_FromWideChar(res, size);
484
+ if (buf != res)
485
+ free(res);
486
+ return string;
487
+ }
488
+
489
+ /*[clinic input]
490
+ _msi.Record.ClearData
491
+
492
+ Set all fields of the record to 0.
493
+ [clinic start generated code]*/
494
+
495
+ static PyObject* _msi_Record_ClearData_impl(msiobj* self)
496
+ /*[clinic end generated code: output=1891467214b977f4 input=2a911c95aaded102]*/
497
+ {
498
+ int status = MsiRecordClearData(self->h);
499
+ if (status != ERROR_SUCCESS)
500
+ return msierror(status);
501
+
502
+ Py_RETURN_NONE;
503
+ }
504
+
505
+ /*[clinic input]
506
+ _msi.Record.SetString
507
+ field: int
508
+ value: wchar_t
509
+ /
510
+
511
+ Set field to a string value.
512
+ [clinic start generated code]*/
513
+
514
+ static PyObject* _msi_Record_SetString_impl(
515
+ msiobj* self, int field, const wchar_t* value)
516
+ /*[clinic end generated code: output=2e37505b0f11f985 input=fb8ec70a2a6148e0]*/
517
+ {
518
+ int status;
519
+
520
+ if ((status = MsiRecordSetStringW(self->h, field, value)) != ERROR_SUCCESS)
521
+ return msierror(status);
522
+
523
+ Py_RETURN_NONE;
524
+ }
525
+
526
+ /*[clinic input]
527
+ _msi.Record.SetStream
528
+ field: int
529
+ value: wchar_t
530
+ /
531
+
532
+ Set field to the contents of the file named value.
533
+ [clinic start generated code]*/
534
+
535
+ static PyObject* _msi_Record_SetStream_impl(
536
+ msiobj* self, int field, const wchar_t* value)
537
+ /*[clinic end generated code: output=442facac16913b48 input=a07aa19b865e8292]*/
538
+ {
539
+ int status;
540
+
541
+ if ((status = MsiRecordSetStreamW(self->h, field, value)) != ERROR_SUCCESS)
542
+ return msierror(status);
543
+
544
+ Py_RETURN_NONE;
545
+ }
546
+
547
+ /*[clinic input]
548
+ _msi.Record.SetInteger
549
+ field: int
550
+ value: int
551
+ /
552
+
553
+ Set field to an integer value.
554
+ [clinic start generated code]*/
555
+
556
+ static PyObject* _msi_Record_SetInteger_impl(
557
+ msiobj* self, int field, int value)
558
+ /*[clinic end generated code: output=669e8647775d0ce7 input=c571aa775e7e451b]*/
559
+ {
560
+ int status;
561
+
562
+ if ((status = MsiRecordSetInteger(self->h, field, value)) != ERROR_SUCCESS)
563
+ return msierror(status);
564
+
565
+ Py_RETURN_NONE;
566
+ }
567
+
568
+ static PyMethodDef record_methods[]
569
+ = { _MSI_RECORD_GETFIELDCOUNT_METHODDEF, _MSI_RECORD_GETINTEGER_METHODDEF,
570
+ _MSI_RECORD_GETSTRING_METHODDEF, _MSI_RECORD_SETSTRING_METHODDEF,
571
+ _MSI_RECORD_SETSTREAM_METHODDEF, _MSI_RECORD_SETINTEGER_METHODDEF,
572
+ _MSI_RECORD_CLEARDATA_METHODDEF, _MSI_SENTINEL };
573
+
574
+ static PyTypeObject record_Type = {
575
+ PyVarObject_HEAD_INIT(NULL, 0) "_msi.Record", /*tp_name*/
576
+ sizeof(msiobj), /*tp_basicsize*/
577
+ 0, /*tp_itemsize*/
578
+ /* methods */
579
+ (destructor)msiobj_dealloc, /*tp_dealloc*/
580
+ 0, /*tp_vectorcall_offset*/
581
+ 0, /*tp_getattr*/
582
+ 0, /*tp_setattr*/
583
+ 0, /*tp_as_async*/
584
+ 0, /*tp_repr*/
585
+ 0, /*tp_as_number*/
586
+ 0, /*tp_as_sequence*/
587
+ 0, /*tp_as_mapping*/
588
+ 0, /*tp_hash*/
589
+ 0, /*tp_call*/
590
+ 0, /*tp_str*/
591
+ PyObject_GenericGetAttr, /*tp_getattro*/
592
+ PyObject_GenericSetAttr, /*tp_setattro*/
593
+ 0, /*tp_as_buffer*/
594
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
595
+ 0, /*tp_doc*/
596
+ 0, /*tp_traverse*/
597
+ 0, /*tp_clear*/
598
+ 0, /*tp_richcompare*/
599
+ 0, /*tp_weaklistoffset*/
600
+ 0, /*tp_iter*/
601
+ 0, /*tp_iternext*/
602
+ record_methods, /*tp_methods*/
603
+ 0, /*tp_members*/
604
+ 0, /*tp_getset*/
605
+ 0, /*tp_base*/
606
+ 0, /*tp_dict*/
607
+ 0, /*tp_descr_get*/
608
+ 0, /*tp_descr_set*/
609
+ 0, /*tp_dictoffset*/
610
+ 0, /*tp_init*/
611
+ 0, /*tp_alloc*/
612
+ 0, /*tp_new*/
613
+ 0, /*tp_free*/
614
+ 0, /*tp_is_gc*/
615
+ };
616
+
617
+ static PyObject* record_new(MSIHANDLE h)
618
+ {
619
+ msiobj* result = PyObject_New(struct msiobj, &record_Type);
620
+
621
+ if (!result) {
622
+ MsiCloseHandle(h);
623
+ return NULL;
624
+ }
625
+
626
+ result->h = h;
627
+ return (PyObject*)result;
628
+ }
629
+
630
+ /*************************** SummaryInformation objects **************/
631
+
632
+ /*[clinic input]
633
+ _msi.SummaryInformation.GetProperty
634
+ field: int
635
+ the name of the property, one of the PID_* constants
636
+ /
637
+
638
+ Return a property of the summary.
639
+ [clinic start generated code]*/
640
+
641
+ static PyObject* _msi_SummaryInformation_GetProperty_impl(
642
+ msiobj* self, int field)
643
+ /*[clinic end generated code: output=f8946a33ee14f6ef input=f8dfe2c890d6cb8b]*/
644
+ {
645
+ int status;
646
+ PyObject* result;
647
+ UINT type;
648
+ INT ival;
649
+ FILETIME fval;
650
+ char sbuf[1000];
651
+ char* sval = sbuf;
652
+ DWORD ssize = sizeof(sbuf);
653
+
654
+ status = MsiSummaryInfoGetProperty(
655
+ self->h, field, &type, &ival, &fval, sval, &ssize);
656
+ if (status == ERROR_MORE_DATA) {
657
+ ssize++;
658
+ sval = malloc(ssize);
659
+ if (sval == NULL) {
660
+ return PyErr_NoMemory();
661
+ }
662
+ status = MsiSummaryInfoGetProperty(
663
+ self->h, field, &type, &ival, &fval, sval, &ssize);
664
+ }
665
+ if (status != ERROR_SUCCESS) {
666
+ return msierror(status);
667
+ }
668
+
669
+ switch (type) {
670
+ case VT_I2:
671
+ case VT_I4:
672
+ result = PyLong_FromLong(ival);
673
+ break;
674
+ case VT_FILETIME:
675
+ PyErr_SetString(PyExc_NotImplementedError, "FILETIME result");
676
+ result = NULL;
677
+ break;
678
+ case VT_LPSTR:
679
+ result = PyBytes_FromStringAndSize(sval, ssize);
680
+ break;
681
+ case VT_EMPTY:
682
+ result = Py_NewRef(Py_None);
683
+ break;
684
+ default:
685
+ PyErr_Format(PyExc_NotImplementedError, "result of type %d", type);
686
+ result = NULL;
687
+ break;
688
+ }
689
+ if (sval != sbuf)
690
+ free(sval);
691
+ return result;
692
+ }
693
+
694
+ /*[clinic input]
695
+ _msi.SummaryInformation.GetPropertyCount
696
+
697
+ Return the number of summary properties.
698
+ [clinic start generated code]*/
699
+
700
+ static PyObject* _msi_SummaryInformation_GetPropertyCount_impl(msiobj* self)
701
+ /*[clinic end generated code: output=68e94b2aeee92b3d input=2e71e985586d82dc]*/
702
+ {
703
+ int status;
704
+ UINT result;
705
+
706
+ status = MsiSummaryInfoGetPropertyCount(self->h, &result);
707
+ if (status != ERROR_SUCCESS)
708
+ return msierror(status);
709
+
710
+ return PyLong_FromLong(result);
711
+ }
712
+
713
+ /*[clinic input]
714
+ _msi.SummaryInformation.SetProperty
715
+ field: int
716
+ the name of the property, one of the PID_* constants
717
+ value as data: object
718
+ the new value of the property (integer or string)
719
+ /
720
+
721
+ Set a property.
722
+ [clinic start generated code]*/
723
+
724
+ static PyObject* _msi_SummaryInformation_SetProperty_impl(
725
+ msiobj* self, int field, PyObject* data)
726
+ /*[clinic end generated code: output=3d4692c8984bb675 input=f2a7811b905abbed]*/
727
+ {
728
+ int status;
729
+
730
+ if (PyUnicode_Check(data)) {
731
+ WCHAR* value = PyUnicode_AsWideCharString(data, NULL);
732
+ if (value == NULL) {
733
+ return NULL;
734
+ }
735
+ status = MsiSummaryInfoSetPropertyW(
736
+ self->h, field, VT_LPSTR, 0, NULL, value);
737
+ PyMem_Free(value);
738
+ } else if (PyLong_CheckExact(data)) {
739
+ long value = PyLong_AsLong(data);
740
+ if (value == -1 && PyErr_Occurred()) {
741
+ return NULL;
742
+ }
743
+ status = MsiSummaryInfoSetProperty(
744
+ self->h, field, VT_I4, value, NULL, NULL);
745
+ } else {
746
+ PyErr_SetString(PyExc_TypeError, "unsupported type");
747
+ return NULL;
748
+ }
749
+
750
+ if (status != ERROR_SUCCESS)
751
+ return msierror(status);
752
+
753
+ Py_RETURN_NONE;
754
+ }
755
+
756
+ /*[clinic input]
757
+ _msi.SummaryInformation.Persist
758
+
759
+ Write the modified properties to the summary information stream.
760
+ [clinic start generated code]*/
761
+
762
+ static PyObject* _msi_SummaryInformation_Persist_impl(msiobj* self)
763
+ /*[clinic end generated code: output=c564bd17f5e122c9 input=e3dda9d530095ef7]*/
764
+ {
765
+ int status;
766
+
767
+ status = MsiSummaryInfoPersist(self->h);
768
+ if (status != ERROR_SUCCESS)
769
+ return msierror(status);
770
+ Py_RETURN_NONE;
771
+ }
772
+
773
+ static PyMethodDef summary_methods[]
774
+ = { _MSI_SUMMARYINFORMATION_GETPROPERTY_METHODDEF,
775
+ _MSI_SUMMARYINFORMATION_GETPROPERTYCOUNT_METHODDEF,
776
+ _MSI_SUMMARYINFORMATION_SETPROPERTY_METHODDEF,
777
+ _MSI_SUMMARYINFORMATION_PERSIST_METHODDEF, _MSI_SENTINEL };
778
+
779
+ static PyTypeObject summary_Type = {
780
+ PyVarObject_HEAD_INIT(NULL, 0) "_msi.SummaryInformation", /*tp_name*/
781
+ sizeof(msiobj), /*tp_basicsize*/
782
+ 0, /*tp_itemsize*/
783
+ /* methods */
784
+ (destructor)msiobj_dealloc, /*tp_dealloc*/
785
+ 0, /*tp_vectorcall_offset*/
786
+ 0, /*tp_getattr*/
787
+ 0, /*tp_setattr*/
788
+ 0, /*tp_as_async*/
789
+ 0, /*tp_repr*/
790
+ 0, /*tp_as_number*/
791
+ 0, /*tp_as_sequence*/
792
+ 0, /*tp_as_mapping*/
793
+ 0, /*tp_hash*/
794
+ 0, /*tp_call*/
795
+ 0, /*tp_str*/
796
+ PyObject_GenericGetAttr, /*tp_getattro*/
797
+ PyObject_GenericSetAttr, /*tp_setattro*/
798
+ 0, /*tp_as_buffer*/
799
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
800
+ 0, /*tp_doc*/
801
+ 0, /*tp_traverse*/
802
+ 0, /*tp_clear*/
803
+ 0, /*tp_richcompare*/
804
+ 0, /*tp_weaklistoffset*/
805
+ 0, /*tp_iter*/
806
+ 0, /*tp_iternext*/
807
+ summary_methods, /*tp_methods*/
808
+ 0, /*tp_members*/
809
+ 0, /*tp_getset*/
810
+ 0, /*tp_base*/
811
+ 0, /*tp_dict*/
812
+ 0, /*tp_descr_get*/
813
+ 0, /*tp_descr_set*/
814
+ 0, /*tp_dictoffset*/
815
+ 0, /*tp_init*/
816
+ 0, /*tp_alloc*/
817
+ 0, /*tp_new*/
818
+ 0, /*tp_free*/
819
+ 0, /*tp_is_gc*/
820
+ };
821
+
822
+ /*************************** View objects **************/
823
+
824
+ /*[clinic input]
825
+ _msi.View.Execute
826
+ params as oparams: object
827
+ a record describing actual values of the parameter tokens
828
+ in the query or None
829
+ /
830
+
831
+ Execute the SQL query of the view.
832
+ [clinic start generated code]*/
833
+
834
+ static PyObject* _msi_View_Execute(msiobj* self, PyObject* oparams)
835
+ /*[clinic end generated code: output=f0f65fd2900bcb4e input=cb163a15d453348e]*/
836
+ {
837
+ int status;
838
+ MSIHANDLE params = 0;
839
+
840
+ if (!Py_IsNone(oparams)) {
841
+ if (!Py_IS_TYPE(oparams, &record_Type)) {
842
+ PyErr_SetString(
843
+ PyExc_TypeError, "Execute argument must be a record");
844
+ return NULL;
845
+ }
846
+ params = ((msiobj*)oparams)->h;
847
+ }
848
+
849
+ status = MsiViewExecute(self->h, params);
850
+ if (status != ERROR_SUCCESS)
851
+ return msierror(status);
852
+
853
+ Py_RETURN_NONE;
854
+ }
855
+
856
+ /*[clinic input]
857
+ _msi.View.Fetch
858
+
859
+ Return a result record of the query.
860
+ [clinic start generated code]*/
861
+
862
+ static PyObject* _msi_View_Fetch_impl(msiobj* self)
863
+ /*[clinic end generated code: output=ba154a3794537d4e input=7f3e3d06c449001c]*/
864
+ {
865
+ int status;
866
+ MSIHANDLE result;
867
+
868
+ status = MsiViewFetch(self->h, &result);
869
+ if (status == ERROR_NO_MORE_ITEMS) {
870
+ Py_RETURN_NONE;
871
+ } else if (status != ERROR_SUCCESS) {
872
+ return msierror(status);
873
+ }
874
+
875
+ return record_new(result);
876
+ }
877
+
878
+ /*[clinic input]
879
+ _msi.View.GetColumnInfo
880
+ kind: int
881
+ MSICOLINFO_NAMES or MSICOLINFO_TYPES
882
+ /
883
+
884
+ Return a record describing the columns of the view.
885
+ [clinic start generated code]*/
886
+
887
+ static PyObject* _msi_View_GetColumnInfo_impl(msiobj* self, int kind)
888
+ /*[clinic end generated code: output=e7c1697db9403660 input=afedb892bf564a3b]*/
889
+ {
890
+ int status;
891
+ MSIHANDLE result;
892
+
893
+ if ((status = MsiViewGetColumnInfo(self->h, kind, &result))
894
+ != ERROR_SUCCESS)
895
+ return msierror(status);
896
+
897
+ return record_new(result);
898
+ }
899
+
900
+ /*[clinic input]
901
+ _msi.View.Modify
902
+ kind: int
903
+ one of the MSIMODIFY_* constants
904
+ data: object
905
+ a record describing the new data
906
+ /
907
+
908
+ Modify the view.
909
+ [clinic start generated code]*/
910
+
911
+ static PyObject* _msi_View_Modify_impl(msiobj* self, int kind, PyObject* data)
912
+ /*[clinic end generated code: output=69aaf3ce8ddac0ba input=2828de22de0d47b4]*/
913
+ {
914
+ int status;
915
+
916
+ if (!Py_IS_TYPE(data, &record_Type)) {
917
+ PyErr_SetString(PyExc_TypeError, "Modify expects a record object");
918
+ return NULL;
919
+ }
920
+
921
+ if ((status = MsiViewModify(self->h, kind, ((msiobj*)data)->h))
922
+ != ERROR_SUCCESS)
923
+ return msierror(status);
924
+
925
+ Py_RETURN_NONE;
926
+ }
927
+
928
+ /*[clinic input]
929
+ _msi.View.Close
930
+
931
+ Close the view.
932
+ [clinic start generated code]*/
933
+
934
+ static PyObject* _msi_View_Close_impl(msiobj* self)
935
+ /*[clinic end generated code: output=488f7b8645ca104a input=de6927d1308c401c]*/
936
+ {
937
+ int status;
938
+
939
+ if ((status = MsiViewClose(self->h)) != ERROR_SUCCESS)
940
+ return msierror(status);
941
+
942
+ Py_RETURN_NONE;
943
+ }
944
+
945
+ static PyMethodDef view_methods[] = { _MSI_VIEW_EXECUTE_METHODDEF,
946
+ _MSI_VIEW_GETCOLUMNINFO_METHODDEF, _MSI_VIEW_FETCH_METHODDEF,
947
+ _MSI_VIEW_MODIFY_METHODDEF, _MSI_VIEW_CLOSE_METHODDEF, _MSI_SENTINEL };
948
+
949
+ static PyTypeObject msiview_Type = {
950
+ PyVarObject_HEAD_INIT(NULL, 0) "_msi.View", /*tp_name*/
951
+ sizeof(msiobj), /*tp_basicsize*/
952
+ 0, /*tp_itemsize*/
953
+ /* methods */
954
+ (destructor)msiobj_dealloc, /*tp_dealloc*/
955
+ 0, /*tp_vectorcall_offset*/
956
+ 0, /*tp_getattr*/
957
+ 0, /*tp_setattr*/
958
+ 0, /*tp_as_async*/
959
+ 0, /*tp_repr*/
960
+ 0, /*tp_as_number*/
961
+ 0, /*tp_as_sequence*/
962
+ 0, /*tp_as_mapping*/
963
+ 0, /*tp_hash*/
964
+ 0, /*tp_call*/
965
+ 0, /*tp_str*/
966
+ PyObject_GenericGetAttr, /*tp_getattro*/
967
+ PyObject_GenericSetAttr, /*tp_setattro*/
968
+ 0, /*tp_as_buffer*/
969
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
970
+ 0, /*tp_doc*/
971
+ 0, /*tp_traverse*/
972
+ 0, /*tp_clear*/
973
+ 0, /*tp_richcompare*/
974
+ 0, /*tp_weaklistoffset*/
975
+ 0, /*tp_iter*/
976
+ 0, /*tp_iternext*/
977
+ view_methods, /*tp_methods*/
978
+ 0, /*tp_members*/
979
+ 0, /*tp_getset*/
980
+ 0, /*tp_base*/
981
+ 0, /*tp_dict*/
982
+ 0, /*tp_descr_get*/
983
+ 0, /*tp_descr_set*/
984
+ 0, /*tp_dictoffset*/
985
+ 0, /*tp_init*/
986
+ 0, /*tp_alloc*/
987
+ 0, /*tp_new*/
988
+ 0, /*tp_free*/
989
+ 0, /*tp_is_gc*/
990
+ };
991
+
992
+ /*************************** Database objects **************/
993
+
994
+ /*[clinic input]
995
+ _msi.Database.OpenView
996
+ sql: wchar_t
997
+ the SQL statement to execute
998
+ /
999
+
1000
+ Return a view object.
1001
+ [clinic start generated code]*/
1002
+
1003
+ static PyObject* _msi_Database_OpenView_impl(msiobj* self, const wchar_t* sql)
1004
+ /*[clinic end generated code: output=e712e6a11229abfd input=50f1771f37e500df]*/
1005
+ {
1006
+ int status;
1007
+ MSIHANDLE hView;
1008
+ msiobj* result;
1009
+
1010
+ if ((status = MsiDatabaseOpenViewW(self->h, sql, &hView)) != ERROR_SUCCESS)
1011
+ return msierror(status);
1012
+
1013
+ result = PyObject_New(struct msiobj, &msiview_Type);
1014
+ if (!result) {
1015
+ MsiCloseHandle(hView);
1016
+ return NULL;
1017
+ }
1018
+
1019
+ result->h = hView;
1020
+ return (PyObject*)result;
1021
+ }
1022
+
1023
+ /*[clinic input]
1024
+ _msi.Database.Commit
1025
+
1026
+ Commit the changes pending in the current transaction.
1027
+ [clinic start generated code]*/
1028
+
1029
+ static PyObject* _msi_Database_Commit_impl(msiobj* self)
1030
+ /*[clinic end generated code: output=f33021feb8b0cdd8 input=375bb120d402266d]*/
1031
+ {
1032
+ int status;
1033
+
1034
+ if ((status = MsiDatabaseCommit(self->h)) != ERROR_SUCCESS)
1035
+ return msierror(status);
1036
+
1037
+ Py_RETURN_NONE;
1038
+ }
1039
+
1040
+ /*[clinic input]
1041
+ _msi.Database.GetSummaryInformation
1042
+ count: int
1043
+ the maximum number of updated values
1044
+ /
1045
+
1046
+ Return a new summary information object.
1047
+ [clinic start generated code]*/
1048
+
1049
+ static PyObject* _msi_Database_GetSummaryInformation_impl(
1050
+ msiobj* self, int count)
1051
+ /*[clinic end generated code: output=781e51a4ea4da847 input=18a899ead6521735]*/
1052
+ {
1053
+ int status;
1054
+ MSIHANDLE result;
1055
+ msiobj* oresult;
1056
+
1057
+ status = MsiGetSummaryInformation(self->h, NULL, count, &result);
1058
+ if (status != ERROR_SUCCESS)
1059
+ return msierror(status);
1060
+
1061
+ oresult = PyObject_New(struct msiobj, &summary_Type);
1062
+ if (!oresult) {
1063
+ MsiCloseHandle(result);
1064
+ return NULL;
1065
+ }
1066
+
1067
+ oresult->h = result;
1068
+ return (PyObject*)oresult;
1069
+ }
1070
+
1071
+ static PyMethodDef db_methods[]
1072
+ = { _MSI_DATABASE_OPENVIEW_METHODDEF, _MSI_DATABASE_COMMIT_METHODDEF,
1073
+ _MSI_DATABASE_GETSUMMARYINFORMATION_METHODDEF,
1074
+ _MSI_DATABASE_CLOSE_METHODDEF, _MSI_SENTINEL };
1075
+
1076
+ static PyTypeObject msidb_Type = {
1077
+ PyVarObject_HEAD_INIT(NULL, 0) "_msi.Database", /*tp_name*/
1078
+ sizeof(msiobj), /*tp_basicsize*/
1079
+ 0, /*tp_itemsize*/
1080
+ /* methods */
1081
+ (destructor)msiobj_dealloc, /*tp_dealloc*/
1082
+ 0, /*tp_vectorcall_offset*/
1083
+ 0, /*tp_getattr*/
1084
+ 0, /*tp_setattr*/
1085
+ 0, /*tp_as_async*/
1086
+ 0, /*tp_repr*/
1087
+ 0, /*tp_as_number*/
1088
+ 0, /*tp_as_sequence*/
1089
+ 0, /*tp_as_mapping*/
1090
+ 0, /*tp_hash*/
1091
+ 0, /*tp_call*/
1092
+ 0, /*tp_str*/
1093
+ PyObject_GenericGetAttr, /*tp_getattro*/
1094
+ PyObject_GenericSetAttr, /*tp_setattro*/
1095
+ 0, /*tp_as_buffer*/
1096
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
1097
+ 0, /*tp_doc*/
1098
+ 0, /*tp_traverse*/
1099
+ 0, /*tp_clear*/
1100
+ 0, /*tp_richcompare*/
1101
+ 0, /*tp_weaklistoffset*/
1102
+ 0, /*tp_iter*/
1103
+ 0, /*tp_iternext*/
1104
+ db_methods, /*tp_methods*/
1105
+ 0, /*tp_members*/
1106
+ 0, /*tp_getset*/
1107
+ 0, /*tp_base*/
1108
+ 0, /*tp_dict*/
1109
+ 0, /*tp_descr_get*/
1110
+ 0, /*tp_descr_set*/
1111
+ 0, /*tp_dictoffset*/
1112
+ 0, /*tp_init*/
1113
+ 0, /*tp_alloc*/
1114
+ 0, /*tp_new*/
1115
+ 0, /*tp_free*/
1116
+ 0, /*tp_is_gc*/
1117
+ };
1118
+
1119
+ #define Py_NOT_PERSIST(x, flag) \
1120
+ (x != (SIZE_T)(flag) && x != ((SIZE_T)(flag) | MSIDBOPEN_PATCHFILE))
1121
+
1122
+ #define Py_INVALID_PERSIST(x) \
1123
+ (Py_NOT_PERSIST(x, MSIDBOPEN_READONLY) \
1124
+ && Py_NOT_PERSIST(x, MSIDBOPEN_TRANSACT) \
1125
+ && Py_NOT_PERSIST(x, MSIDBOPEN_DIRECT) \
1126
+ && Py_NOT_PERSIST(x, MSIDBOPEN_CREATE) \
1127
+ && Py_NOT_PERSIST(x, MSIDBOPEN_CREATEDIRECT))
1128
+
1129
+ /*[clinic input]
1130
+ _msi.OpenDatabase
1131
+ path: wchar_t
1132
+ the file name of the MSI file
1133
+ persist: int
1134
+ the persistence mode
1135
+ /
1136
+
1137
+ Return a new database object.
1138
+ [clinic start generated code]*/
1139
+
1140
+ static PyObject* _msi_OpenDatabase_impl(
1141
+ PyObject* module, const wchar_t* path, int persist)
1142
+ /*[clinic end generated code: output=d34b7202b745de05 input=1300f3b97659559b]*/
1143
+ {
1144
+ int status;
1145
+ MSIHANDLE h;
1146
+ msiobj* result;
1147
+
1148
+ /* We need to validate that persist is a valid MSIDBOPEN_* value.
1149
+ Otherwise, MsiOpenDatabase may treat the value as a pointer, leading to
1150
+ unexpected behavior. */
1151
+ if (Py_INVALID_PERSIST(persist))
1152
+ return msierror(ERROR_INVALID_PARAMETER);
1153
+ status = MsiOpenDatabaseW(path, (LPCWSTR)(SIZE_T)persist, &h);
1154
+ if (status != ERROR_SUCCESS)
1155
+ return msierror(status);
1156
+
1157
+ result = PyObject_New(struct msiobj, &msidb_Type);
1158
+ if (!result) {
1159
+ MsiCloseHandle(h);
1160
+ return NULL;
1161
+ }
1162
+ result->h = h;
1163
+ return (PyObject*)result;
1164
+ }
1165
+
1166
+ /*[clinic input]
1167
+ _msi.CreateRecord
1168
+ count: int
1169
+ the number of fields of the record
1170
+ /
1171
+
1172
+ Return a new record object.
1173
+ [clinic start generated code]*/
1174
+
1175
+ static PyObject* _msi_CreateRecord_impl(PyObject* module, int count)
1176
+ /*[clinic end generated code: output=0ba0a00beea3e99e input=53f17d5b5d9b077d]*/
1177
+ {
1178
+ MSIHANDLE h;
1179
+
1180
+ h = MsiCreateRecord(count);
1181
+ if (h == 0)
1182
+ return msierror(0);
1183
+
1184
+ return record_new(h);
1185
+ }
1186
+
1187
+ static PyMethodDef msi_methods[] = { _MSI_UUIDCREATE_METHODDEF,
1188
+ _MSI_FCICREATE_METHODDEF, _MSI_OPENDATABASE_METHODDEF,
1189
+ _MSI_CREATERECORD_METHODDEF, _MSI_SENTINEL };
1190
+
1191
+ static char msi_doc[] = "Documentation";
1192
+
1193
+ static struct PyModuleDef _msimodule = { PyModuleDef_HEAD_INIT, "_msi",
1194
+ msi_doc, -1, msi_methods, NULL, NULL, NULL, NULL };
1195
+
1196
+ PyMODINIT_FUNC PyInit__msi(void)
1197
+ {
1198
+ PyObject* m;
1199
+
1200
+ m = PyModule_Create(&_msimodule);
1201
+ if (m == NULL)
1202
+ return NULL;
1203
+
1204
+ PyModule_AddIntConstant(
1205
+ m, "MSIDBOPEN_CREATEDIRECT", (long)(SIZE_T)MSIDBOPEN_CREATEDIRECT);
1206
+ PyModule_AddIntConstant(
1207
+ m, "MSIDBOPEN_CREATE", (long)(SIZE_T)MSIDBOPEN_CREATE);
1208
+ PyModule_AddIntConstant(
1209
+ m, "MSIDBOPEN_DIRECT", (long)(SIZE_T)MSIDBOPEN_DIRECT);
1210
+ PyModule_AddIntConstant(
1211
+ m, "MSIDBOPEN_READONLY", (long)(SIZE_T)MSIDBOPEN_READONLY);
1212
+ PyModule_AddIntConstant(
1213
+ m, "MSIDBOPEN_TRANSACT", (long)(SIZE_T)MSIDBOPEN_TRANSACT);
1214
+ PyModule_AddIntConstant(
1215
+ m, "MSIDBOPEN_PATCHFILE", (long)(SIZE_T)MSIDBOPEN_PATCHFILE);
1216
+
1217
+ PyModule_AddIntMacro(m, MSICOLINFO_NAMES);
1218
+ PyModule_AddIntMacro(m, MSICOLINFO_TYPES);
1219
+
1220
+ PyModule_AddIntMacro(m, MSIMODIFY_SEEK);
1221
+ PyModule_AddIntMacro(m, MSIMODIFY_REFRESH);
1222
+ PyModule_AddIntMacro(m, MSIMODIFY_INSERT);
1223
+ PyModule_AddIntMacro(m, MSIMODIFY_UPDATE);
1224
+ PyModule_AddIntMacro(m, MSIMODIFY_ASSIGN);
1225
+ PyModule_AddIntMacro(m, MSIMODIFY_REPLACE);
1226
+ PyModule_AddIntMacro(m, MSIMODIFY_MERGE);
1227
+ PyModule_AddIntMacro(m, MSIMODIFY_DELETE);
1228
+ PyModule_AddIntMacro(m, MSIMODIFY_INSERT_TEMPORARY);
1229
+ PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE);
1230
+ PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_NEW);
1231
+ PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_FIELD);
1232
+ PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_DELETE);
1233
+
1234
+ PyModule_AddIntMacro(m, PID_CODEPAGE);
1235
+ PyModule_AddIntMacro(m, PID_TITLE);
1236
+ PyModule_AddIntMacro(m, PID_SUBJECT);
1237
+ PyModule_AddIntMacro(m, PID_AUTHOR);
1238
+ PyModule_AddIntMacro(m, PID_KEYWORDS);
1239
+ PyModule_AddIntMacro(m, PID_COMMENTS);
1240
+ PyModule_AddIntMacro(m, PID_TEMPLATE);
1241
+ PyModule_AddIntMacro(m, PID_LASTAUTHOR);
1242
+ PyModule_AddIntMacro(m, PID_REVNUMBER);
1243
+ PyModule_AddIntMacro(m, PID_LASTPRINTED);
1244
+ PyModule_AddIntMacro(m, PID_CREATE_DTM);
1245
+ PyModule_AddIntMacro(m, PID_LASTSAVE_DTM);
1246
+ PyModule_AddIntMacro(m, PID_PAGECOUNT);
1247
+ PyModule_AddIntMacro(m, PID_WORDCOUNT);
1248
+ PyModule_AddIntMacro(m, PID_CHARCOUNT);
1249
+ PyModule_AddIntMacro(m, PID_APPNAME);
1250
+ PyModule_AddIntMacro(m, PID_SECURITY);
1251
+
1252
+ MSIError = PyErr_NewException("_msi.MSIError", NULL, NULL);
1253
+ if (!MSIError)
1254
+ return NULL;
1255
+ PyModule_AddObject(m, "MSIError", MSIError);
1256
+ #ifdef Py_GIL_DISABLED
1257
+ PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
1258
+ #endif
1259
+ return m;
1260
+ }