blob: 5b68bc2e2f947a9a3fe8d3dceeb9894f78cb46b7 [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;
21 char *cresult;
22 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
33 if (UuidToString(&result, &cresult) == RPC_S_OUT_OF_MEMORY) {
34 PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen");
35 return NULL;
36 }
37
Christian Heimes72b710a2008-05-26 13:28:38 +000038 oresult = PyBytes_FromString(cresult);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +000039 RpcStringFree(&cresult);
40 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*
342record_cleardata(msiobj* record, PyObject *args)
343{
344 int status = MsiRecordClearData(record->h);
345 if (status != ERROR_SUCCESS)
346 return msierror(status);
347
348 Py_INCREF(Py_None);
349 return Py_None;
350}
351
352static PyObject*
353record_setstring(msiobj* record, PyObject *args)
354{
355 int status;
356 int field;
357 char *data;
358
359 if (!PyArg_ParseTuple(args, "is:SetString", &field, &data))
360 return NULL;
361
362 if ((status = MsiRecordSetString(record->h, field, data)) != ERROR_SUCCESS)
363 return msierror(status);
364
365 Py_INCREF(Py_None);
366 return Py_None;
367}
368
369static PyObject*
370record_setstream(msiobj* record, PyObject *args)
371{
372 int status;
373 int field;
374 char *data;
375
376 if (!PyArg_ParseTuple(args, "is:SetStream", &field, &data))
377 return NULL;
378
379 if ((status = MsiRecordSetStream(record->h, field, data)) != ERROR_SUCCESS)
380 return msierror(status);
381
382 Py_INCREF(Py_None);
383 return Py_None;
384}
385
386static PyObject*
387record_setinteger(msiobj* record, PyObject *args)
388{
389 int status;
390 int field;
391 int data;
392
393 if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data))
394 return NULL;
395
396 if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS)
397 return msierror(status);
398
399 Py_INCREF(Py_None);
400 return Py_None;
401}
402
403
404
405static PyMethodDef record_methods[] = {
406 { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS,
407 PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")},
408 { "SetString", (PyCFunction)record_setstring, METH_VARARGS,
409 PyDoc_STR("SetString(field,str) -> None\nWraps MsiRecordSetString")},
410 { "SetStream", (PyCFunction)record_setstream, METH_VARARGS,
411 PyDoc_STR("SetStream(field,filename) -> None\nWraps MsiRecordSetInteger")},
412 { "SetInteger", (PyCFunction)record_setinteger, METH_VARARGS,
413 PyDoc_STR("SetInteger(field,int) -> None\nWraps MsiRecordSetInteger")},
414 { "ClearData", (PyCFunction)record_cleardata, METH_NOARGS,
415 PyDoc_STR("ClearData() -> int\nWraps MsiRecordGClearData")},
416 { NULL, NULL }
417};
418
419static PyTypeObject record_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000420 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000421 "_msi.Record", /*tp_name*/
422 sizeof(msiobj), /*tp_basicsize*/
423 0, /*tp_itemsize*/
424 /* methods */
425 (destructor)msiobj_dealloc, /*tp_dealloc*/
426 0, /*tp_print*/
427 0, /*tp_getattr*/
428 0, /*tp_setattr*/
429 0, /*tp_compare*/
430 0, /*tp_repr*/
431 0, /*tp_as_number*/
432 0, /*tp_as_sequence*/
433 0, /*tp_as_mapping*/
434 0, /*tp_hash*/
435 0, /*tp_call*/
436 0, /*tp_str*/
437 PyObject_GenericGetAttr,/*tp_getattro*/
438 PyObject_GenericSetAttr,/*tp_setattro*/
439 0, /*tp_as_buffer*/
440 Py_TPFLAGS_DEFAULT, /*tp_flags*/
441 0, /*tp_doc*/
442 0, /*tp_traverse*/
443 0, /*tp_clear*/
444 0, /*tp_richcompare*/
445 0, /*tp_weaklistoffset*/
446 0, /*tp_iter*/
447 0, /*tp_iternext*/
448 record_methods, /*tp_methods*/
449 0, /*tp_members*/
450 0, /*tp_getset*/
451 0, /*tp_base*/
452 0, /*tp_dict*/
453 0, /*tp_descr_get*/
454 0, /*tp_descr_set*/
455 0, /*tp_dictoffset*/
456 0, /*tp_init*/
457 0, /*tp_alloc*/
458 0, /*tp_new*/
459 0, /*tp_free*/
460 0, /*tp_is_gc*/
461};
462
463static PyObject*
464record_new(MSIHANDLE h)
465{
466 msiobj *result = PyObject_NEW(struct msiobj, &record_Type);
467
468 if (!result) {
469 MsiCloseHandle(h);
470 return NULL;
471 }
472
473 result->h = h;
474 return (PyObject*)result;
475}
476
477/*************************** SummaryInformation objects **************/
478
479static PyObject*
480summary_getproperty(msiobj* si, PyObject *args)
481{
482 int status;
483 int field;
484 PyObject *result;
485 UINT type;
486 INT ival;
487 FILETIME fval;
488 char sbuf[1000];
489 char *sval = sbuf;
490 DWORD ssize = sizeof(sval);
491
492 if (!PyArg_ParseTuple(args, "i:GetProperty", &field))
493 return NULL;
494
495 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
496 &fval, sval, &ssize);
Thomas Wouters89f507f2006-12-13 04:49:30 +0000497 if (status == ERROR_MORE_DATA) {
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000498 sval = malloc(ssize);
499 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
500 &fval, sval, &ssize);
501 }
502
503 switch(type) {
504 case VT_I2: case VT_I4:
Christian Heimes217cfd12007-12-02 14:31:20 +0000505 return PyLong_FromLong(ival);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000506 case VT_FILETIME:
507 PyErr_SetString(PyExc_NotImplementedError, "FILETIME result");
508 return NULL;
509 case VT_LPSTR:
Christian Heimes72b710a2008-05-26 13:28:38 +0000510 result = PyBytes_FromStringAndSize(sval, ssize);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000511 if (sval != sbuf)
512 free(sval);
513 return result;
514 }
515 PyErr_Format(PyExc_NotImplementedError, "result of type %d", type);
516 return NULL;
517}
518
519static PyObject*
520summary_getpropertycount(msiobj* si, PyObject *args)
521{
522 int status;
523 UINT result;
524
525 status = MsiSummaryInfoGetPropertyCount(si->h, &result);
526 if (status != ERROR_SUCCESS)
527 return msierror(status);
528
Christian Heimes217cfd12007-12-02 14:31:20 +0000529 return PyLong_FromLong(result);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000530}
531
532static PyObject*
533summary_setproperty(msiobj* si, PyObject *args)
534{
535 int status;
536 int field;
537 PyObject* data;
538
539 if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data))
540 return NULL;
541
Christian Heimes72b710a2008-05-26 13:28:38 +0000542 if (PyBytes_Check(data)) {
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000543 status = MsiSummaryInfoSetProperty(si->h, field, VT_LPSTR,
Christian Heimes72b710a2008-05-26 13:28:38 +0000544 0, NULL, PyBytes_AsString(data));
Martin v. Löwisd1a1d1e2007-12-04 22:10:37 +0000545 } else if (PyLong_CheckExact(data)) {
546 long value = PyLong_AsLong(data);
547 if (value == -1 && PyErr_Occurred()) {
548 return NULL;
549 }
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000550 status = MsiSummaryInfoSetProperty(si->h, field, VT_I4,
Martin v. Löwisd1a1d1e2007-12-04 22:10:37 +0000551 value, NULL, NULL);
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000552 } else {
553 PyErr_SetString(PyExc_TypeError, "unsupported type");
554 return NULL;
555 }
556
557 if (status != ERROR_SUCCESS)
558 return msierror(status);
559
560 Py_INCREF(Py_None);
561 return Py_None;
562}
563
564
565static PyObject*
566summary_persist(msiobj* si, PyObject *args)
567{
568 int status;
569
570 status = MsiSummaryInfoPersist(si->h);
571 if (status != ERROR_SUCCESS)
572 return msierror(status);
573 Py_INCREF(Py_None);
574 return Py_None;
575}
576
577static PyMethodDef summary_methods[] = {
578 { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS,
579 PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")},
580 { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS,
581 PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")},
582 { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS,
583 PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")},
584 { "Persist", (PyCFunction)summary_persist, METH_NOARGS,
585 PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")},
586 { NULL, NULL }
587};
588
589static PyTypeObject summary_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000590 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000591 "_msi.SummaryInformation", /*tp_name*/
592 sizeof(msiobj), /*tp_basicsize*/
593 0, /*tp_itemsize*/
594 /* methods */
595 (destructor)msiobj_dealloc, /*tp_dealloc*/
596 0, /*tp_print*/
597 0, /*tp_getattr*/
598 0, /*tp_setattr*/
599 0, /*tp_compare*/
600 0, /*tp_repr*/
601 0, /*tp_as_number*/
602 0, /*tp_as_sequence*/
603 0, /*tp_as_mapping*/
604 0, /*tp_hash*/
605 0, /*tp_call*/
606 0, /*tp_str*/
607 PyObject_GenericGetAttr,/*tp_getattro*/
608 PyObject_GenericSetAttr,/*tp_setattro*/
609 0, /*tp_as_buffer*/
610 Py_TPFLAGS_DEFAULT, /*tp_flags*/
611 0, /*tp_doc*/
612 0, /*tp_traverse*/
613 0, /*tp_clear*/
614 0, /*tp_richcompare*/
615 0, /*tp_weaklistoffset*/
616 0, /*tp_iter*/
617 0, /*tp_iternext*/
618 summary_methods, /*tp_methods*/
619 0, /*tp_members*/
620 0, /*tp_getset*/
621 0, /*tp_base*/
622 0, /*tp_dict*/
623 0, /*tp_descr_get*/
624 0, /*tp_descr_set*/
625 0, /*tp_dictoffset*/
626 0, /*tp_init*/
627 0, /*tp_alloc*/
628 0, /*tp_new*/
629 0, /*tp_free*/
630 0, /*tp_is_gc*/
631};
632
633/*************************** View objects **************/
634
635static PyObject*
636view_execute(msiobj *view, PyObject*args)
637{
638 int status;
639 MSIHANDLE params = 0;
640 PyObject *oparams = Py_None;
641
642 if (!PyArg_ParseTuple(args, "O:Execute", &oparams))
643 return NULL;
644
645 if (oparams != Py_None) {
646 if (oparams->ob_type != &record_Type) {
647 PyErr_SetString(PyExc_TypeError, "Execute argument must be a record");
648 return NULL;
649 }
650 params = ((msiobj*)oparams)->h;
651 }
652
653 status = MsiViewExecute(view->h, params);
654 if (status != ERROR_SUCCESS)
655 return msierror(status);
656
657 Py_INCREF(Py_None);
658 return Py_None;
659}
660
661static PyObject*
662view_fetch(msiobj *view, PyObject*args)
663{
664 int status;
665 MSIHANDLE result;
666
667 if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS)
668 return msierror(status);
669
670 return record_new(result);
671}
672
673static PyObject*
674view_getcolumninfo(msiobj *view, PyObject *args)
675{
676 int status;
677 int kind;
678 MSIHANDLE result;
679
680 if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind))
681 return NULL;
682
683 if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS)
684 return msierror(status);
685
686 return record_new(result);
687}
688
689static PyObject*
690view_modify(msiobj *view, PyObject *args)
691{
692 int kind;
693 PyObject *data;
694 int status;
695
696 if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data))
697 return NULL;
698
699 if (data->ob_type != &record_Type) {
700 PyErr_SetString(PyExc_TypeError, "Modify expects a record object");
701 return NULL;
702 }
703
704 if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS)
705 return msierror(status);
706
707 Py_INCREF(Py_None);
708 return Py_None;
709}
710
711static PyObject*
712view_close(msiobj *view, PyObject*args)
713{
714 int status;
715
716 if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS)
717 return msierror(status);
718
719 Py_INCREF(Py_None);
720 return Py_None;
721}
722
723static PyMethodDef view_methods[] = {
724 { "Execute", (PyCFunction)view_execute, METH_VARARGS,
725 PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")},
726 { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS,
727 PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")},
728 { "Fetch", (PyCFunction)view_fetch, METH_NOARGS,
729 PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")},
730 { "Modify", (PyCFunction)view_modify, METH_VARARGS,
731 PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")},
732 { "Close", (PyCFunction)view_close, METH_NOARGS,
733 PyDoc_STR("Close() -> result\nWraps MsiViewClose")},
734 { NULL, NULL }
735};
736
737static PyTypeObject msiview_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000738 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000739 "_msi.View", /*tp_name*/
740 sizeof(msiobj), /*tp_basicsize*/
741 0, /*tp_itemsize*/
742 /* methods */
743 (destructor)msiobj_dealloc, /*tp_dealloc*/
744 0, /*tp_print*/
745 0, /*tp_getattr*/
746 0, /*tp_setattr*/
747 0, /*tp_compare*/
748 0, /*tp_repr*/
749 0, /*tp_as_number*/
750 0, /*tp_as_sequence*/
751 0, /*tp_as_mapping*/
752 0, /*tp_hash*/
753 0, /*tp_call*/
754 0, /*tp_str*/
755 PyObject_GenericGetAttr,/*tp_getattro*/
756 PyObject_GenericSetAttr,/*tp_setattro*/
757 0, /*tp_as_buffer*/
758 Py_TPFLAGS_DEFAULT, /*tp_flags*/
759 0, /*tp_doc*/
760 0, /*tp_traverse*/
761 0, /*tp_clear*/
762 0, /*tp_richcompare*/
763 0, /*tp_weaklistoffset*/
764 0, /*tp_iter*/
765 0, /*tp_iternext*/
766 view_methods, /*tp_methods*/
767 0, /*tp_members*/
768 0, /*tp_getset*/
769 0, /*tp_base*/
770 0, /*tp_dict*/
771 0, /*tp_descr_get*/
772 0, /*tp_descr_set*/
773 0, /*tp_dictoffset*/
774 0, /*tp_init*/
775 0, /*tp_alloc*/
776 0, /*tp_new*/
777 0, /*tp_free*/
778 0, /*tp_is_gc*/
779};
780
781/*************************** Database objects **************/
782
783static PyObject*
784msidb_openview(msiobj *msidb, PyObject *args)
785{
786 int status;
787 char *sql;
788 MSIHANDLE hView;
789 msiobj *result;
790
791 if (!PyArg_ParseTuple(args, "s:OpenView", &sql))
792 return NULL;
793
794 if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS)
795 return msierror(status);
796
797 result = PyObject_NEW(struct msiobj, &msiview_Type);
798 if (!result) {
799 MsiCloseHandle(hView);
800 return NULL;
801 }
802
803 result->h = hView;
804 return (PyObject*)result;
805}
806
807static PyObject*
808msidb_commit(msiobj *msidb, PyObject *args)
809{
810 int status;
811
812 if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS)
813 return msierror(status);
814
815 Py_INCREF(Py_None);
816 return Py_None;
817}
818
819static PyObject*
820msidb_getsummaryinformation(msiobj *db, PyObject *args)
821{
822 int status;
823 int count;
824 MSIHANDLE result;
825 msiobj *oresult;
826
827 if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count))
828 return NULL;
829
830 status = MsiGetSummaryInformation(db->h, NULL, count, &result);
831 if (status != ERROR_SUCCESS)
832 return msierror(status);
833
834 oresult = PyObject_NEW(struct msiobj, &summary_Type);
835 if (!result) {
836 MsiCloseHandle(result);
837 return NULL;
838 }
839
840 oresult->h = result;
841 return (PyObject*)oresult;
842}
843
844static PyMethodDef db_methods[] = {
845 { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS,
846 PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")},
847 { "Commit", (PyCFunction)msidb_commit, METH_NOARGS,
848 PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")},
849 { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS,
850 PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")},
851 { NULL, NULL }
852};
853
854static PyTypeObject msidb_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000855 PyVarObject_HEAD_INIT(NULL, 0)
Martin v. Löwisfbab90e2006-03-05 13:36:04 +0000856 "_msi.Database", /*tp_name*/
857 sizeof(msiobj), /*tp_basicsize*/
858 0, /*tp_itemsize*/
859 /* methods */
860 (destructor)msiobj_dealloc, /*tp_dealloc*/
861 0, /*tp_print*/
862 0, /*tp_getattr*/
863 0, /*tp_setattr*/
864 0, /*tp_compare*/
865 0, /*tp_repr*/
866 0, /*tp_as_number*/
867 0, /*tp_as_sequence*/
868 0, /*tp_as_mapping*/
869 0, /*tp_hash*/
870 0, /*tp_call*/
871 0, /*tp_str*/
872 PyObject_GenericGetAttr,/*tp_getattro*/
873 PyObject_GenericSetAttr,/*tp_setattro*/
874 0, /*tp_as_buffer*/
875 Py_TPFLAGS_DEFAULT, /*tp_flags*/
876 0, /*tp_doc*/
877 0, /*tp_traverse*/
878 0, /*tp_clear*/
879 0, /*tp_richcompare*/
880 0, /*tp_weaklistoffset*/
881 0, /*tp_iter*/
882 0, /*tp_iternext*/
883 db_methods, /*tp_methods*/
884 0, /*tp_members*/
885 0, /*tp_getset*/
886 0, /*tp_base*/
887 0, /*tp_dict*/
888 0, /*tp_descr_get*/
889 0, /*tp_descr_set*/
890 0, /*tp_dictoffset*/
891 0, /*tp_init*/
892 0, /*tp_alloc*/
893 0, /*tp_new*/
894 0, /*tp_free*/
895 0, /*tp_is_gc*/
896};
897
898static PyObject* msiopendb(PyObject *obj, PyObject *args)
899{
900 int status;
901 char *path;
902 int persist;
903 MSIHANDLE h;
904 msiobj *result;
905
906 if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist))
907 return NULL;
908
909 status = MsiOpenDatabase(path, (LPCSTR)persist, &h);
910 if (status != ERROR_SUCCESS)
911 return msierror(status);
912
913 result = PyObject_NEW(struct msiobj, &msidb_Type);
914 if (!result) {
915 MsiCloseHandle(h);
916 return NULL;
917 }
918 result->h = h;
919 return (PyObject*)result;
920}
921
922static PyObject*
923createrecord(PyObject *o, PyObject *args)
924{
925 int count;
926 MSIHANDLE h;
927
928 if (!PyArg_ParseTuple(args, "i:CreateRecord", &count))
929 return NULL;
930
931 h = MsiCreateRecord(count);
932 if (h == 0)
933 return msierror(0);
934
935 return record_new(h);
936}
937
938
939static PyMethodDef msi_methods[] = {
940 {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS,
941 PyDoc_STR("UuidCreate() -> string")},
942 {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS,
943 PyDoc_STR("fcicreate(cabname,files) -> None")},
944 {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS,
945 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")},
946 {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS,
947 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")},
948 {NULL, NULL} /* sentinel */
949};
950
951static char msi_doc[] = "Documentation";
952
953PyMODINIT_FUNC
954init_msi(void)
955{
956 PyObject *m;
957
958 m = Py_InitModule3("_msi", msi_methods, msi_doc);
959 if (m == NULL)
960 return;
961
962 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (int)MSIDBOPEN_CREATEDIRECT);
963 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (int)MSIDBOPEN_CREATE);
964 PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (int)MSIDBOPEN_DIRECT);
965 PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (int)MSIDBOPEN_READONLY);
966 PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT);
967 PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE);
968
969 PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES);
970 PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES);
971
972 PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK);
973 PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH);
974 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT);
975 PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE);
976 PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN);
977 PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE);
978 PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE);
979 PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE);
980 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY);
981 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE);
982 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW);
983 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD);
984 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE);
985
986 PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE);
987 PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE);
988 PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT);
989 PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR);
990 PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS);
991 PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS);
992 PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE);
993 PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR);
994 PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER);
995 PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED);
996 PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM);
997 PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM);
998 PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT);
999 PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT);
1000 PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT);
1001 PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME);
1002 PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY);
1003
1004 MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL);
1005 if (!MSIError)
1006 return;
1007 PyModule_AddObject(m, "MSIError", MSIError);
1008}