blob: f129293bb2cf60dc4bc6d64441ad2b33f83feadb [file] [log] [blame]
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001/* Helper library for MSI creation with Python.
2 * 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;
Hirokazu Yamamotoab058ed2008-08-17 07:26:26 +000021 unsigned short *cresult;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000022 PyObject *oresult;
23
24 /* 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) {
29 PyErr_SetString(PyExc_NotImplementedError, "processing 'no address' result");
30 return NULL;
31 }
32
Martin v. Löwis371bb502008-08-16 13:02:57 +000033 if (UuidToStringW(&result, &cresult) == RPC_S_OUT_OF_MEMORY) {
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000034 PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen");
35 return NULL;
36 }
37
Martin v. Löwis371bb502008-08-16 13:02:57 +000038 oresult = PyUnicode_FromUnicode(cresult, wcslen(cresult));
39 RpcStringFreeW(&cresult);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000040 return oresult;
41
42}
43
44/* FCI callback functions */
45
46static FNFCIALLOC(cb_alloc)
47{
48 return malloc(cb);
49}
50
51static FNFCIFREE(cb_free)
52{
53 free(memory);
54}
55
56static FNFCIOPEN(cb_open)
57{
58 int result = _open(pszFile, oflag, pmode);
59 if (result == -1)
60 *err = errno;
61 return result;
62}
63
64static FNFCIREAD(cb_read)
65{
66 UINT result = (UINT)_read(hf, memory, cb);
67 if (result != cb)
68 *err = errno;
69 return result;
70}
71
72static FNFCIWRITE(cb_write)
73{
74 UINT result = (UINT)_write(hf, memory, cb);
75 if (result != cb)
76 *err = errno;
77 return result;
78}
79
80static FNFCICLOSE(cb_close)
81{
82 int result = _close(hf);
83 if (result != 0)
84 *err = errno;
85 return result;
86}
87
88static FNFCISEEK(cb_seek)
89{
90 long result = (long)_lseek(hf, dist, seektype);
91 if (result == -1)
92 *err = errno;
93 return result;
94}
95
96static FNFCIDELETE(cb_delete)
97{
98 int result = remove(pszFile);
99 if (result != 0)
100 *err = errno;
101 return result;
102}
103
104static FNFCIFILEPLACED(cb_fileplaced)
105{
106 return 0;
107}
108
109static FNFCIGETTEMPFILE(cb_gettempfile)
110{
111 char *name = _tempnam("", "tmp");
112 if ((name != NULL) && ((int)strlen(name) < cbTempName)) {
113 strcpy(pszTempName, name);
114 free(name);
115 return TRUE;
116 }
117
118 if (name) free(name);
119 return FALSE;
120}
121
122static FNFCISTATUS(cb_status)
123{
124 if (pv) {
125 PyObject *result = PyObject_CallMethod(pv, "status", "iii", typeStatus, cb1, cb2);
126 if (result == NULL)
127 return -1;
128 Py_DECREF(result);
129 }
130 return 0;
131}
132
133static FNFCIGETNEXTCABINET(cb_getnextcabinet)
134{
135 if (pv) {
136 PyObject *result = PyObject_CallMethod(pv, "getnextcabinet", "i", pccab->iCab);
137 if (result == NULL)
138 return -1;
Christian Heimes72b710a2008-05-26 13:28:38 +0000139 if (!PyBytes_Check(result)) {
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000140 PyErr_Format(PyExc_TypeError,
141 "Incorrect return type %s from getnextcabinet",
142 result->ob_type->tp_name);
143 Py_DECREF(result);
144 return FALSE;
145 }
Christian Heimes72b710a2008-05-26 13:28:38 +0000146 strncpy(pccab->szCab, PyBytes_AsString(result), sizeof(pccab->szCab));
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000147 return TRUE;
148 }
149 return FALSE;
150}
151
152static FNFCIGETOPENINFO(cb_getopeninfo)
153{
154 BY_HANDLE_FILE_INFORMATION bhfi;
155 FILETIME filetime;
156 HANDLE handle;
157
158 /* Need Win32 handle to get time stamps */
159 handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
160 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
161 if (handle == INVALID_HANDLE_VALUE)
162 return -1;
163
164 if (GetFileInformationByHandle(handle, &bhfi) == FALSE)
165 {
166 CloseHandle(handle);
167 return -1;
168 }
169
170 FileTimeToLocalFileTime(&bhfi.ftLastWriteTime, &filetime);
171 FileTimeToDosDateTime(&filetime, pdate, ptime);
172
173 *pattribs = (int)(bhfi.dwFileAttributes &
174 (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH));
175
176 CloseHandle(handle);
177
178 return _open(pszName, _O_RDONLY | _O_BINARY);
179}
180
181static PyObject* fcicreate(PyObject* obj, PyObject* args)
182{
Christian Heimes0bd4e112008-02-12 22:59:25 +0000183 char *cabname, *p;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000184 PyObject *files;
185 CCAB ccab;
186 HFCI hfci;
187 ERF erf;
Christian Heimes0bd4e112008-02-12 22:59:25 +0000188 Py_ssize_t i;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000189
190
191 if (!PyArg_ParseTuple(args, "sO:FCICreate", &cabname, &files))
192 return NULL;
193
194 if (!PyList_Check(files)) {
195 PyErr_SetString(PyExc_TypeError, "FCICreate expects a list");
196 return NULL;
197 }
198
199 ccab.cb = INT_MAX; /* no need to split CAB into multiple media */
200 ccab.cbFolderThresh = 1000000; /* flush directory after this many bytes */
201 ccab.cbReserveCFData = 0;
202 ccab.cbReserveCFFolder = 0;
203 ccab.cbReserveCFHeader = 0;
204
205 ccab.iCab = 1;
206 ccab.iDisk = 1;
207
208 ccab.setID = 0;
209 ccab.szDisk[0] = '\0';
210
Christian Heimes0bd4e112008-02-12 22:59:25 +0000211 for (i = 0, p = cabname; *p; p = CharNext(p))
212 if (*p == '\\' || *p == '/')
213 i = p - cabname + 1;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000214
Christian Heimes0bd4e112008-02-12 22:59:25 +0000215 if (i >= sizeof(ccab.szCabPath) ||
216 strlen(cabname+i) >= sizeof(ccab.szCab)) {
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000217 PyErr_SetString(PyExc_ValueError, "path name too long");
218 return 0;
219 }
220
Christian Heimes0bd4e112008-02-12 22:59:25 +0000221 if (i > 0) {
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000222 memcpy(ccab.szCabPath, cabname, i);
223 ccab.szCabPath[i] = '\0';
224 strcpy(ccab.szCab, cabname+i);
225 } else {
Christian Heimes0bd4e112008-02-12 22:59:25 +0000226 strcpy(ccab.szCabPath, ".\\");
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000227 strcpy(ccab.szCab, cabname);
228 }
229
230 hfci = FCICreate(&erf, cb_fileplaced, cb_alloc, cb_free,
231 cb_open, cb_read, cb_write, cb_close, cb_seek, cb_delete,
232 cb_gettempfile, &ccab, NULL);
233
234 if (hfci == NULL) {
235 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper);
236 return NULL;
237 }
238
239 for (i=0; i < PyList_GET_SIZE(files); i++) {
240 PyObject *item = PyList_GET_ITEM(files, i);
241 char *filename, *cabname;
242 if (!PyArg_ParseTuple(item, "ss", &filename, &cabname))
243 goto err;
244 if (!FCIAddFile(hfci, filename, cabname, FALSE,
245 cb_getnextcabinet, cb_status, cb_getopeninfo,
246 tcompTYPE_MSZIP))
247 goto err;
248 }
249
250 if (!FCIFlushCabinet(hfci, FALSE, cb_getnextcabinet, cb_status))
251 goto err;
252
253 if (!FCIDestroy(hfci))
254 goto err;
255
256 Py_INCREF(Py_None);
257 return Py_None;
258err:
259 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
260 FCIDestroy(hfci);
261 return NULL;
262}
263
264typedef struct msiobj{
265 PyObject_HEAD
266 MSIHANDLE h;
267}msiobj;
268
269static void
270msiobj_dealloc(msiobj* msidb)
271{
272 MsiCloseHandle(msidb->h);
273 msidb->h = 0;
274}
275
276static PyObject*
277msiobj_close(msiobj* msidb, PyObject *args)
278{
279 MsiCloseHandle(msidb->h);
280 msidb->h = 0;
281 Py_INCREF(Py_None);
282 return Py_None;
283}
284
285static PyObject*
286msierror(int status)
287{
288 int code;
289 char buf[2000];
290 char *res = buf;
291 DWORD size = sizeof(buf);
292 MSIHANDLE err = MsiGetLastErrorRecord();
293
294 if (err == 0) {
295 switch(status) {
296 case ERROR_ACCESS_DENIED:
297 PyErr_SetString(MSIError, "access denied");
298 return NULL;
299 case ERROR_FUNCTION_FAILED:
300 PyErr_SetString(MSIError, "function failed");
301 return NULL;
302 case ERROR_INVALID_DATA:
303 PyErr_SetString(MSIError, "invalid data");
304 return NULL;
305 case ERROR_INVALID_HANDLE:
306 PyErr_SetString(MSIError, "invalid handle");
307 return NULL;
308 case ERROR_INVALID_STATE:
309 PyErr_SetString(MSIError, "invalid state");
310 return NULL;
311 case ERROR_INVALID_PARAMETER:
312 PyErr_SetString(MSIError, "invalid parameter");
313 return NULL;
314 default:
315 PyErr_Format(MSIError, "unknown error %x", status);
316 return NULL;
317 }
318 }
319
320 code = MsiRecordGetInteger(err, 1); /* XXX code */
321 if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) {
322 res = malloc(size+1);
323 MsiFormatRecord(0, err, res, &size);
324 res[size]='\0';
325 }
326 MsiCloseHandle(err);
327 PyErr_SetString(MSIError, res);
328 if (res != buf)
329 free(res);
330 return NULL;
331}
332
333/*************************** Record objects **********************/
334
335static PyObject*
336record_getfieldcount(msiobj* record, PyObject* args)
337{
Christian Heimes217cfd12007-12-02 14:31:20 +0000338 return PyLong_FromLong(MsiRecordGetFieldCount(record->h));
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000339}
340
341static PyObject*
Martin v. Löwise95593e2008-06-02 10:08:54 +0000342record_getinteger(msiobj* record, PyObject* args)
343{
344 unsigned int field;
345 int status;
346
347 if (!PyArg_ParseTuple(args, "I:GetInteger", &field))
348 return NULL;
349 status = MsiRecordGetInteger(record->h, field);
350 if (status == MSI_NULL_INTEGER){
351 PyErr_SetString(MSIError, "could not convert record field to integer");
352 return NULL;
353 }
Martin v. Löwis704d8b12008-06-02 11:32:23 +0000354 return PyLong_FromLong((long) status);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000355}
356
357static PyObject*
358record_getstring(msiobj* record, PyObject* args)
359{
360 unsigned int field;
361 unsigned int status;
Martin v. Löwis371bb502008-08-16 13:02:57 +0000362 WCHAR buf[2000];
363 WCHAR *res = buf;
Martin v. Löwise95593e2008-06-02 10:08:54 +0000364 DWORD size = sizeof(buf);
365 PyObject* string;
366
367 if (!PyArg_ParseTuple(args, "I:GetString", &field))
368 return NULL;
Martin v. Löwis371bb502008-08-16 13:02:57 +0000369 status = MsiRecordGetStringW(record->h, field, res, &size);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000370 if (status == ERROR_MORE_DATA) {
Martin v. Löwis371bb502008-08-16 13:02:57 +0000371 res = (WCHAR*) malloc((size + 1)*sizeof(WCHAR));
Martin v. Löwise95593e2008-06-02 10:08:54 +0000372 if (res == NULL)
373 return PyErr_NoMemory();
Martin v. Löwis371bb502008-08-16 13:02:57 +0000374 status = MsiRecordGetStringW(record->h, field, res, &size);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000375 }
376 if (status != ERROR_SUCCESS)
377 return msierror((int) status);
Martin v. Löwis371bb502008-08-16 13:02:57 +0000378 string = PyUnicode_FromUnicode(res, size);
Martin v. Löwise95593e2008-06-02 10:08:54 +0000379 if (buf != res)
380 free(res);
381 return string;
382}
383
384static PyObject*
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000385record_cleardata(msiobj* record, PyObject *args)
386{
387 int status = MsiRecordClearData(record->h);
388 if (status != ERROR_SUCCESS)
389 return msierror(status);
390
391 Py_INCREF(Py_None);
392 return Py_None;
393}
394
395static PyObject*
396record_setstring(msiobj* record, PyObject *args)
397{
398 int status;
399 int field;
Martin v. Löwis371bb502008-08-16 13:02:57 +0000400 Py_UNICODE *data;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000401
Martin v. Löwis371bb502008-08-16 13:02:57 +0000402 if (!PyArg_ParseTuple(args, "iu:SetString", &field, &data))
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000403 return NULL;
404
Martin v. Löwis371bb502008-08-16 13:02:57 +0000405 if ((status = MsiRecordSetStringW(record->h, field, data)) != ERROR_SUCCESS)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000406 return msierror(status);
407
408 Py_INCREF(Py_None);
409 return Py_None;
410}
411
412static PyObject*
413record_setstream(msiobj* record, PyObject *args)
414{
415 int status;
416 int field;
Martin v. Löwis371bb502008-08-16 13:02:57 +0000417 Py_UNICODE *data;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000418
Martin v. Löwis371bb502008-08-16 13:02:57 +0000419 if (!PyArg_ParseTuple(args, "iu:SetStream", &field, &data))
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000420 return NULL;
421
Martin v. Löwis371bb502008-08-16 13:02:57 +0000422 if ((status = MsiRecordSetStreamW(record->h, field, data)) != ERROR_SUCCESS)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000423 return msierror(status);
424
425 Py_INCREF(Py_None);
426 return Py_None;
427}
428
429static PyObject*
430record_setinteger(msiobj* record, PyObject *args)
431{
432 int status;
433 int field;
434 int data;
435
436 if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data))
437 return NULL;
438
439 if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS)
440 return msierror(status);
441
442 Py_INCREF(Py_None);
443 return Py_None;
444}
445
446
447
448static PyMethodDef record_methods[] = {
449 { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS,
450 PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")},
Martin v. Löwise95593e2008-06-02 10:08:54 +0000451 { "GetInteger", (PyCFunction)record_getinteger, METH_VARARGS,
452 PyDoc_STR("GetInteger(field) -> int\nWraps MsiRecordGetInteger")},
453 { "GetString", (PyCFunction)record_getstring, METH_VARARGS,
454 PyDoc_STR("GetString(field) -> string\nWraps MsiRecordGetString")},
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000455 { "SetString", (PyCFunction)record_setstring, METH_VARARGS,
456 PyDoc_STR("SetString(field,str) -> None\nWraps MsiRecordSetString")},
457 { "SetStream", (PyCFunction)record_setstream, METH_VARARGS,
458 PyDoc_STR("SetStream(field,filename) -> None\nWraps MsiRecordSetInteger")},
459 { "SetInteger", (PyCFunction)record_setinteger, METH_VARARGS,
460 PyDoc_STR("SetInteger(field,int) -> None\nWraps MsiRecordSetInteger")},
461 { "ClearData", (PyCFunction)record_cleardata, METH_NOARGS,
462 PyDoc_STR("ClearData() -> int\nWraps MsiRecordGClearData")},
463 { NULL, NULL }
464};
465
466static PyTypeObject record_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000467 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000468 "_msi.Record", /*tp_name*/
469 sizeof(msiobj), /*tp_basicsize*/
470 0, /*tp_itemsize*/
471 /* methods */
472 (destructor)msiobj_dealloc, /*tp_dealloc*/
473 0, /*tp_print*/
474 0, /*tp_getattr*/
475 0, /*tp_setattr*/
476 0, /*tp_compare*/
477 0, /*tp_repr*/
478 0, /*tp_as_number*/
479 0, /*tp_as_sequence*/
480 0, /*tp_as_mapping*/
481 0, /*tp_hash*/
482 0, /*tp_call*/
483 0, /*tp_str*/
484 PyObject_GenericGetAttr,/*tp_getattro*/
485 PyObject_GenericSetAttr,/*tp_setattro*/
486 0, /*tp_as_buffer*/
487 Py_TPFLAGS_DEFAULT, /*tp_flags*/
488 0, /*tp_doc*/
489 0, /*tp_traverse*/
490 0, /*tp_clear*/
491 0, /*tp_richcompare*/
492 0, /*tp_weaklistoffset*/
493 0, /*tp_iter*/
494 0, /*tp_iternext*/
495 record_methods, /*tp_methods*/
496 0, /*tp_members*/
497 0, /*tp_getset*/
498 0, /*tp_base*/
499 0, /*tp_dict*/
500 0, /*tp_descr_get*/
501 0, /*tp_descr_set*/
502 0, /*tp_dictoffset*/
503 0, /*tp_init*/
504 0, /*tp_alloc*/
505 0, /*tp_new*/
506 0, /*tp_free*/
507 0, /*tp_is_gc*/
508};
509
510static PyObject*
511record_new(MSIHANDLE h)
512{
513 msiobj *result = PyObject_NEW(struct msiobj, &record_Type);
514
515 if (!result) {
516 MsiCloseHandle(h);
517 return NULL;
518 }
519
520 result->h = h;
521 return (PyObject*)result;
522}
523
524/*************************** SummaryInformation objects **************/
525
526static PyObject*
527summary_getproperty(msiobj* si, PyObject *args)
528{
529 int status;
530 int field;
531 PyObject *result;
532 UINT type;
533 INT ival;
534 FILETIME fval;
535 char sbuf[1000];
536 char *sval = sbuf;
537 DWORD ssize = sizeof(sval);
538
539 if (!PyArg_ParseTuple(args, "i:GetProperty", &field))
540 return NULL;
541
542 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
543 &fval, sval, &ssize);
Thomas Wouters89f507f2006-12-13 04:49:30 +0000544 if (status == ERROR_MORE_DATA) {
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000545 sval = malloc(ssize);
546 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
547 &fval, sval, &ssize);
548 }
549
550 switch(type) {
551 case VT_I2: case VT_I4:
Christian Heimes217cfd12007-12-02 14:31:20 +0000552 return PyLong_FromLong(ival);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000553 case VT_FILETIME:
554 PyErr_SetString(PyExc_NotImplementedError, "FILETIME result");
555 return NULL;
556 case VT_LPSTR:
Christian Heimes72b710a2008-05-26 13:28:38 +0000557 result = PyBytes_FromStringAndSize(sval, ssize);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000558 if (sval != sbuf)
559 free(sval);
560 return result;
561 }
562 PyErr_Format(PyExc_NotImplementedError, "result of type %d", type);
563 return NULL;
564}
565
566static PyObject*
567summary_getpropertycount(msiobj* si, PyObject *args)
568{
569 int status;
570 UINT result;
571
572 status = MsiSummaryInfoGetPropertyCount(si->h, &result);
573 if (status != ERROR_SUCCESS)
574 return msierror(status);
575
Christian Heimes217cfd12007-12-02 14:31:20 +0000576 return PyLong_FromLong(result);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000577}
578
579static PyObject*
580summary_setproperty(msiobj* si, PyObject *args)
581{
582 int status;
583 int field;
584 PyObject* data;
585
586 if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data))
587 return NULL;
588
Martin v. Löwis371bb502008-08-16 13:02:57 +0000589 if (PyUnicode_Check(data)) {
590 status = MsiSummaryInfoSetPropertyW(si->h, field, VT_LPSTR,
591 0, NULL, PyUnicode_AsUnicode(data));
Martin v. Löwisd1a1d1e2007-12-04 22:10:37 +0000592 } else if (PyLong_CheckExact(data)) {
593 long value = PyLong_AsLong(data);
594 if (value == -1 && PyErr_Occurred()) {
595 return NULL;
596 }
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000597 status = MsiSummaryInfoSetProperty(si->h, field, VT_I4,
Martin v. Löwisd1a1d1e2007-12-04 22:10:37 +0000598 value, NULL, NULL);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000599 } else {
600 PyErr_SetString(PyExc_TypeError, "unsupported type");
601 return NULL;
602 }
603
604 if (status != ERROR_SUCCESS)
605 return msierror(status);
606
607 Py_INCREF(Py_None);
608 return Py_None;
609}
610
611
612static PyObject*
613summary_persist(msiobj* si, PyObject *args)
614{
615 int status;
616
617 status = MsiSummaryInfoPersist(si->h);
618 if (status != ERROR_SUCCESS)
619 return msierror(status);
620 Py_INCREF(Py_None);
621 return Py_None;
622}
623
624static PyMethodDef summary_methods[] = {
625 { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS,
626 PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")},
627 { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS,
628 PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")},
629 { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS,
630 PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")},
631 { "Persist", (PyCFunction)summary_persist, METH_NOARGS,
632 PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")},
633 { NULL, NULL }
634};
635
636static PyTypeObject summary_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000637 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000638 "_msi.SummaryInformation", /*tp_name*/
639 sizeof(msiobj), /*tp_basicsize*/
640 0, /*tp_itemsize*/
641 /* methods */
642 (destructor)msiobj_dealloc, /*tp_dealloc*/
643 0, /*tp_print*/
644 0, /*tp_getattr*/
645 0, /*tp_setattr*/
646 0, /*tp_compare*/
647 0, /*tp_repr*/
648 0, /*tp_as_number*/
649 0, /*tp_as_sequence*/
650 0, /*tp_as_mapping*/
651 0, /*tp_hash*/
652 0, /*tp_call*/
653 0, /*tp_str*/
654 PyObject_GenericGetAttr,/*tp_getattro*/
655 PyObject_GenericSetAttr,/*tp_setattro*/
656 0, /*tp_as_buffer*/
657 Py_TPFLAGS_DEFAULT, /*tp_flags*/
658 0, /*tp_doc*/
659 0, /*tp_traverse*/
660 0, /*tp_clear*/
661 0, /*tp_richcompare*/
662 0, /*tp_weaklistoffset*/
663 0, /*tp_iter*/
664 0, /*tp_iternext*/
665 summary_methods, /*tp_methods*/
666 0, /*tp_members*/
667 0, /*tp_getset*/
668 0, /*tp_base*/
669 0, /*tp_dict*/
670 0, /*tp_descr_get*/
671 0, /*tp_descr_set*/
672 0, /*tp_dictoffset*/
673 0, /*tp_init*/
674 0, /*tp_alloc*/
675 0, /*tp_new*/
676 0, /*tp_free*/
677 0, /*tp_is_gc*/
678};
679
680/*************************** View objects **************/
681
682static PyObject*
683view_execute(msiobj *view, PyObject*args)
684{
685 int status;
686 MSIHANDLE params = 0;
687 PyObject *oparams = Py_None;
688
689 if (!PyArg_ParseTuple(args, "O:Execute", &oparams))
690 return NULL;
691
692 if (oparams != Py_None) {
693 if (oparams->ob_type != &record_Type) {
694 PyErr_SetString(PyExc_TypeError, "Execute argument must be a record");
695 return NULL;
696 }
697 params = ((msiobj*)oparams)->h;
698 }
699
700 status = MsiViewExecute(view->h, params);
701 if (status != ERROR_SUCCESS)
702 return msierror(status);
703
704 Py_INCREF(Py_None);
705 return Py_None;
706}
707
708static PyObject*
709view_fetch(msiobj *view, PyObject*args)
710{
711 int status;
712 MSIHANDLE result;
713
714 if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS)
715 return msierror(status);
716
717 return record_new(result);
718}
719
720static PyObject*
721view_getcolumninfo(msiobj *view, PyObject *args)
722{
723 int status;
724 int kind;
725 MSIHANDLE result;
726
727 if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind))
728 return NULL;
729
730 if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS)
731 return msierror(status);
732
733 return record_new(result);
734}
735
736static PyObject*
737view_modify(msiobj *view, PyObject *args)
738{
739 int kind;
740 PyObject *data;
741 int status;
742
743 if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data))
744 return NULL;
745
746 if (data->ob_type != &record_Type) {
747 PyErr_SetString(PyExc_TypeError, "Modify expects a record object");
748 return NULL;
749 }
750
751 if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS)
752 return msierror(status);
753
754 Py_INCREF(Py_None);
755 return Py_None;
756}
757
758static PyObject*
759view_close(msiobj *view, PyObject*args)
760{
761 int status;
762
763 if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS)
764 return msierror(status);
765
766 Py_INCREF(Py_None);
767 return Py_None;
768}
769
770static PyMethodDef view_methods[] = {
771 { "Execute", (PyCFunction)view_execute, METH_VARARGS,
772 PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")},
773 { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS,
774 PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")},
775 { "Fetch", (PyCFunction)view_fetch, METH_NOARGS,
776 PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")},
777 { "Modify", (PyCFunction)view_modify, METH_VARARGS,
778 PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")},
779 { "Close", (PyCFunction)view_close, METH_NOARGS,
780 PyDoc_STR("Close() -> result\nWraps MsiViewClose")},
781 { NULL, NULL }
782};
783
784static PyTypeObject msiview_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000785 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000786 "_msi.View", /*tp_name*/
787 sizeof(msiobj), /*tp_basicsize*/
788 0, /*tp_itemsize*/
789 /* methods */
790 (destructor)msiobj_dealloc, /*tp_dealloc*/
791 0, /*tp_print*/
792 0, /*tp_getattr*/
793 0, /*tp_setattr*/
794 0, /*tp_compare*/
795 0, /*tp_repr*/
796 0, /*tp_as_number*/
797 0, /*tp_as_sequence*/
798 0, /*tp_as_mapping*/
799 0, /*tp_hash*/
800 0, /*tp_call*/
801 0, /*tp_str*/
802 PyObject_GenericGetAttr,/*tp_getattro*/
803 PyObject_GenericSetAttr,/*tp_setattro*/
804 0, /*tp_as_buffer*/
805 Py_TPFLAGS_DEFAULT, /*tp_flags*/
806 0, /*tp_doc*/
807 0, /*tp_traverse*/
808 0, /*tp_clear*/
809 0, /*tp_richcompare*/
810 0, /*tp_weaklistoffset*/
811 0, /*tp_iter*/
812 0, /*tp_iternext*/
813 view_methods, /*tp_methods*/
814 0, /*tp_members*/
815 0, /*tp_getset*/
816 0, /*tp_base*/
817 0, /*tp_dict*/
818 0, /*tp_descr_get*/
819 0, /*tp_descr_set*/
820 0, /*tp_dictoffset*/
821 0, /*tp_init*/
822 0, /*tp_alloc*/
823 0, /*tp_new*/
824 0, /*tp_free*/
825 0, /*tp_is_gc*/
826};
827
828/*************************** Database objects **************/
829
830static PyObject*
831msidb_openview(msiobj *msidb, PyObject *args)
832{
833 int status;
834 char *sql;
835 MSIHANDLE hView;
836 msiobj *result;
837
838 if (!PyArg_ParseTuple(args, "s:OpenView", &sql))
839 return NULL;
840
841 if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS)
842 return msierror(status);
843
844 result = PyObject_NEW(struct msiobj, &msiview_Type);
845 if (!result) {
846 MsiCloseHandle(hView);
847 return NULL;
848 }
849
850 result->h = hView;
851 return (PyObject*)result;
852}
853
854static PyObject*
855msidb_commit(msiobj *msidb, PyObject *args)
856{
857 int status;
858
859 if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS)
860 return msierror(status);
861
862 Py_INCREF(Py_None);
863 return Py_None;
864}
865
866static PyObject*
867msidb_getsummaryinformation(msiobj *db, PyObject *args)
868{
869 int status;
870 int count;
871 MSIHANDLE result;
872 msiobj *oresult;
873
874 if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count))
875 return NULL;
876
877 status = MsiGetSummaryInformation(db->h, NULL, count, &result);
878 if (status != ERROR_SUCCESS)
879 return msierror(status);
880
881 oresult = PyObject_NEW(struct msiobj, &summary_Type);
882 if (!result) {
883 MsiCloseHandle(result);
884 return NULL;
885 }
886
887 oresult->h = result;
888 return (PyObject*)oresult;
889}
890
891static PyMethodDef db_methods[] = {
892 { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS,
893 PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")},
894 { "Commit", (PyCFunction)msidb_commit, METH_NOARGS,
895 PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")},
896 { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS,
897 PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")},
898 { NULL, NULL }
899};
900
901static PyTypeObject msidb_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000902 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000903 "_msi.Database", /*tp_name*/
904 sizeof(msiobj), /*tp_basicsize*/
905 0, /*tp_itemsize*/
906 /* methods */
907 (destructor)msiobj_dealloc, /*tp_dealloc*/
908 0, /*tp_print*/
909 0, /*tp_getattr*/
910 0, /*tp_setattr*/
911 0, /*tp_compare*/
912 0, /*tp_repr*/
913 0, /*tp_as_number*/
914 0, /*tp_as_sequence*/
915 0, /*tp_as_mapping*/
916 0, /*tp_hash*/
917 0, /*tp_call*/
918 0, /*tp_str*/
919 PyObject_GenericGetAttr,/*tp_getattro*/
920 PyObject_GenericSetAttr,/*tp_setattro*/
921 0, /*tp_as_buffer*/
922 Py_TPFLAGS_DEFAULT, /*tp_flags*/
923 0, /*tp_doc*/
924 0, /*tp_traverse*/
925 0, /*tp_clear*/
926 0, /*tp_richcompare*/
927 0, /*tp_weaklistoffset*/
928 0, /*tp_iter*/
929 0, /*tp_iternext*/
930 db_methods, /*tp_methods*/
931 0, /*tp_members*/
932 0, /*tp_getset*/
933 0, /*tp_base*/
934 0, /*tp_dict*/
935 0, /*tp_descr_get*/
936 0, /*tp_descr_set*/
937 0, /*tp_dictoffset*/
938 0, /*tp_init*/
939 0, /*tp_alloc*/
940 0, /*tp_new*/
941 0, /*tp_free*/
942 0, /*tp_is_gc*/
943};
944
945static PyObject* msiopendb(PyObject *obj, PyObject *args)
946{
947 int status;
948 char *path;
949 int persist;
950 MSIHANDLE h;
951 msiobj *result;
952
953 if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist))
954 return NULL;
955
956 status = MsiOpenDatabase(path, (LPCSTR)persist, &h);
957 if (status != ERROR_SUCCESS)
958 return msierror(status);
959
960 result = PyObject_NEW(struct msiobj, &msidb_Type);
961 if (!result) {
962 MsiCloseHandle(h);
963 return NULL;
964 }
965 result->h = h;
966 return (PyObject*)result;
967}
968
969static PyObject*
970createrecord(PyObject *o, PyObject *args)
971{
972 int count;
973 MSIHANDLE h;
974
975 if (!PyArg_ParseTuple(args, "i:CreateRecord", &count))
976 return NULL;
977
978 h = MsiCreateRecord(count);
979 if (h == 0)
980 return msierror(0);
981
982 return record_new(h);
983}
984
985
986static PyMethodDef msi_methods[] = {
987 {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS,
988 PyDoc_STR("UuidCreate() -> string")},
989 {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS,
990 PyDoc_STR("fcicreate(cabname,files) -> None")},
991 {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS,
992 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")},
993 {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS,
994 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")},
995 {NULL, NULL} /* sentinel */
996};
997
998static char msi_doc[] = "Documentation";
999
Martin v. Löwis1a214512008-06-11 05:26:20 +00001000
1001static struct PyModuleDef _msimodule = {
1002 PyModuleDef_HEAD_INIT,
1003 "_msi",
1004 msi_doc,
1005 -1,
1006 msi_methods,
1007 NULL,
1008 NULL,
1009 NULL,
1010 NULL
1011};
1012
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001013PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001014PyInit__msi(void)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001015{
1016 PyObject *m;
1017
Martin v. Löwis1a214512008-06-11 05:26:20 +00001018 m = PyModule_Create(&_msimodule);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001019 if (m == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001020 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001021
1022 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (int)MSIDBOPEN_CREATEDIRECT);
1023 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (int)MSIDBOPEN_CREATE);
1024 PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (int)MSIDBOPEN_DIRECT);
1025 PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (int)MSIDBOPEN_READONLY);
1026 PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT);
1027 PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE);
1028
1029 PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES);
1030 PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES);
1031
1032 PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK);
1033 PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH);
1034 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT);
1035 PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE);
1036 PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN);
1037 PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE);
1038 PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE);
1039 PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE);
1040 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY);
1041 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE);
1042 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW);
1043 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD);
1044 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE);
1045
1046 PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE);
1047 PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE);
1048 PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT);
1049 PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR);
1050 PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS);
1051 PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS);
1052 PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE);
1053 PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR);
1054 PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER);
1055 PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED);
1056 PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM);
1057 PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM);
1058 PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT);
1059 PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT);
1060 PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT);
1061 PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME);
1062 PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY);
1063
1064 MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL);
1065 if (!MSIError)
Martin v. Löwis1a214512008-06-11 05:26:20 +00001066 return NULL;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001067 PyModule_AddObject(m, "MSIError", MSIError);
Amaury Forgeot d'Arcbf9e9662008-06-17 21:39:46 +00001068 return m;
Martin v. Löwisfbab90e2006-03-05 13:36:04 +00001069}