Fix issue number in comment.
[python.git] / PC / _msi.c
blob58b253061564962c767e8b83fd6361f1bd8db0aa
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 */
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>
15 static PyObject *MSIError;
17 static PyObject*
18 uuidcreate(PyObject* obj, PyObject*args)
20 UUID result;
21 char *cresult;
22 PyObject *oresult;
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;
33 if (UuidToString(&result, &cresult) == RPC_S_OUT_OF_MEMORY) {
34 PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen");
35 return NULL;
38 oresult = PyString_FromString(cresult);
39 RpcStringFree(&cresult);
40 return oresult;
44 /* FCI callback functions */
46 static FNFCIALLOC(cb_alloc)
48 return malloc(cb);
51 static FNFCIFREE(cb_free)
53 free(memory);
56 static FNFCIOPEN(cb_open)
58 int result = _open(pszFile, oflag, pmode);
59 if (result == -1)
60 *err = errno;
61 return result;
64 static FNFCIREAD(cb_read)
66 UINT result = (UINT)_read(hf, memory, cb);
67 if (result != cb)
68 *err = errno;
69 return result;
72 static FNFCIWRITE(cb_write)
74 UINT result = (UINT)_write(hf, memory, cb);
75 if (result != cb)
76 *err = errno;
77 return result;
80 static FNFCICLOSE(cb_close)
82 int result = _close(hf);
83 if (result != 0)
84 *err = errno;
85 return result;
88 static FNFCISEEK(cb_seek)
90 long result = (long)_lseek(hf, dist, seektype);
91 if (result == -1)
92 *err = errno;
93 return result;
96 static FNFCIDELETE(cb_delete)
98 int result = remove(pszFile);
99 if (result != 0)
100 *err = errno;
101 return result;
104 static FNFCIFILEPLACED(cb_fileplaced)
106 return 0;
109 static FNFCIGETTEMPFILE(cb_gettempfile)
111 char *name = _tempnam("", "tmp");
112 if ((name != NULL) && ((int)strlen(name) < cbTempName)) {
113 strcpy(pszTempName, name);
114 free(name);
115 return TRUE;
118 if (name) free(name);
119 return FALSE;
122 static FNFCISTATUS(cb_status)
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);
130 return 0;
133 static FNFCIGETNEXTCABINET(cb_getnextcabinet)
135 if (pv) {
136 PyObject *result = PyObject_CallMethod(pv, "getnextcabinet", "i", pccab->iCab);
137 if (result == NULL)
138 return -1;
139 if (!PyString_Check(result)) {
140 PyErr_Format(PyExc_TypeError,
141 "Incorrect return type %s from getnextcabinet",
142 result->ob_type->tp_name);
143 Py_DECREF(result);
144 return FALSE;
146 strncpy(pccab->szCab, PyString_AsString(result), sizeof(pccab->szCab));
147 return TRUE;
149 return FALSE;
152 static FNFCIGETOPENINFO(cb_getopeninfo)
154 BY_HANDLE_FILE_INFORMATION bhfi;
155 FILETIME filetime;
156 HANDLE handle;
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;
164 if (GetFileInformationByHandle(handle, &bhfi) == FALSE)
166 CloseHandle(handle);
167 return -1;
170 FileTimeToLocalFileTime(&bhfi.ftLastWriteTime, &filetime);
171 FileTimeToDosDateTime(&filetime, pdate, ptime);
173 *pattribs = (int)(bhfi.dwFileAttributes &
174 (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH));
176 CloseHandle(handle);
178 return _open(pszName, _O_RDONLY | _O_BINARY);
181 static PyObject* fcicreate(PyObject* obj, PyObject* args)
183 char *cabname, *p;
184 PyObject *files;
185 CCAB ccab;
186 HFCI hfci;
187 ERF erf;
188 Py_ssize_t i;
191 if (!PyArg_ParseTuple(args, "sO:FCICreate", &cabname, &files))
192 return NULL;
194 if (!PyList_Check(files)) {
195 PyErr_SetString(PyExc_TypeError, "FCICreate expects a list");
196 return NULL;
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;
205 ccab.iCab = 1;
206 ccab.iDisk = 1;
208 ccab.setID = 0;
209 ccab.szDisk[0] = '\0';
211 for (i = 0, p = cabname; *p; p = CharNext(p))
212 if (*p == '\\' || *p == '/')
213 i = p - cabname + 1;
215 if (i >= sizeof(ccab.szCabPath) ||
216 strlen(cabname+i) >= sizeof(ccab.szCab)) {
217 PyErr_SetString(PyExc_ValueError, "path name too long");
218 return 0;
221 if (i > 0) {
222 memcpy(ccab.szCabPath, cabname, i);
223 ccab.szCabPath[i] = '\0';
224 strcpy(ccab.szCab, cabname+i);
225 } else {
226 strcpy(ccab.szCabPath, ".\\");
227 strcpy(ccab.szCab, cabname);
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);
234 if (hfci == NULL) {
235 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper);
236 return NULL;
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;
250 if (!FCIFlushCabinet(hfci, FALSE, cb_getnextcabinet, cb_status))
251 goto err;
253 if (!FCIDestroy(hfci))
254 goto err;
256 Py_INCREF(Py_None);
257 return Py_None;
258 err:
259 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
260 FCIDestroy(hfci);
261 return NULL;
264 typedef struct msiobj{
265 PyObject_HEAD
266 MSIHANDLE h;
267 }msiobj;
269 static void
270 msiobj_dealloc(msiobj* msidb)
272 MsiCloseHandle(msidb->h);
273 msidb->h = 0;
276 static PyObject*
277 msiobj_close(msiobj* msidb, PyObject *args)
279 MsiCloseHandle(msidb->h);
280 msidb->h = 0;
281 Py_INCREF(Py_None);
282 return Py_None;
285 static PyObject*
286 msierror(int status)
288 int code;
289 char buf[2000];
290 char *res = buf;
291 DWORD size = sizeof(buf);
292 MSIHANDLE err = MsiGetLastErrorRecord();
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;
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';
326 MsiCloseHandle(err);
327 PyErr_SetString(MSIError, res);
328 if (res != buf)
329 free(res);
330 return NULL;
333 /*************************** Record objects **********************/
335 static PyObject*
336 record_getfieldcount(msiobj* record, PyObject* args)
338 return PyInt_FromLong(MsiRecordGetFieldCount(record->h));
341 static PyObject*
342 record_getinteger(msiobj* record, PyObject* args)
344 unsigned int field;
345 int status;
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;
354 return PyInt_FromLong((long) status);
357 static PyObject*
358 record_getstring(msiobj* record, PyObject* args)
360 unsigned int field;
361 unsigned int status;
362 char buf[2000];
363 char *res = buf;
364 DWORD size = sizeof(buf);
365 PyObject* string;
367 if (!PyArg_ParseTuple(args, "I:GetString", &field))
368 return NULL;
369 status = MsiRecordGetString(record->h, field, res, &size);
370 if (status == ERROR_MORE_DATA) {
371 res = (char*) malloc(size + 1);
372 if (res == NULL)
373 return PyErr_NoMemory();
374 status = MsiRecordGetString(record->h, field, res, &size);
376 if (status != ERROR_SUCCESS)
377 return msierror((int) status);
378 string = PyString_FromString(res);
379 if (buf != res)
380 free(res);
381 return string;
384 static PyObject*
385 record_cleardata(msiobj* record, PyObject *args)
387 int status = MsiRecordClearData(record->h);
388 if (status != ERROR_SUCCESS)
389 return msierror(status);
391 Py_INCREF(Py_None);
392 return Py_None;
395 static PyObject*
396 record_setstring(msiobj* record, PyObject *args)
398 int status;
399 int field;
400 char *data;
402 if (!PyArg_ParseTuple(args, "is:SetString", &field, &data))
403 return NULL;
405 if ((status = MsiRecordSetString(record->h, field, data)) != ERROR_SUCCESS)
406 return msierror(status);
408 Py_INCREF(Py_None);
409 return Py_None;
412 static PyObject*
413 record_setstream(msiobj* record, PyObject *args)
415 int status;
416 int field;
417 char *data;
419 if (!PyArg_ParseTuple(args, "is:SetStream", &field, &data))
420 return NULL;
422 if ((status = MsiRecordSetStream(record->h, field, data)) != ERROR_SUCCESS)
423 return msierror(status);
425 Py_INCREF(Py_None);
426 return Py_None;
429 static PyObject*
430 record_setinteger(msiobj* record, PyObject *args)
432 int status;
433 int field;
434 int data;
436 if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data))
437 return NULL;
439 if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS)
440 return msierror(status);
442 Py_INCREF(Py_None);
443 return Py_None;
448 static PyMethodDef record_methods[] = {
449 { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS,
450 PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")},
451 { "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")},
455 { "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 }
466 static PyTypeObject record_Type = {
467 PyVarObject_HEAD_INIT(NULL, 0)
468 "_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*/
510 static PyObject*
511 record_new(MSIHANDLE h)
513 msiobj *result = PyObject_NEW(struct msiobj, &record_Type);
515 if (!result) {
516 MsiCloseHandle(h);
517 return NULL;
520 result->h = h;
521 return (PyObject*)result;
524 /*************************** SummaryInformation objects **************/
526 static PyObject*
527 summary_getproperty(msiobj* si, PyObject *args)
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);
539 if (!PyArg_ParseTuple(args, "i:GetProperty", &field))
540 return NULL;
542 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
543 &fval, sval, &ssize);
544 if (status == ERROR_MORE_DATA) {
545 sval = malloc(ssize);
546 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
547 &fval, sval, &ssize);
550 switch(type) {
551 case VT_I2: case VT_I4:
552 return PyInt_FromLong(ival);
553 case VT_FILETIME:
554 PyErr_SetString(PyExc_NotImplementedError, "FILETIME result");
555 return NULL;
556 case VT_LPSTR:
557 result = PyString_FromStringAndSize(sval, ssize);
558 if (sval != sbuf)
559 free(sval);
560 return result;
562 PyErr_Format(PyExc_NotImplementedError, "result of type %d", type);
563 return NULL;
566 static PyObject*
567 summary_getpropertycount(msiobj* si, PyObject *args)
569 int status;
570 UINT result;
572 status = MsiSummaryInfoGetPropertyCount(si->h, &result);
573 if (status != ERROR_SUCCESS)
574 return msierror(status);
576 return PyInt_FromLong(result);
579 static PyObject*
580 summary_setproperty(msiobj* si, PyObject *args)
582 int status;
583 int field;
584 PyObject* data;
586 if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data))
587 return NULL;
589 if (PyString_Check(data)) {
590 status = MsiSummaryInfoSetProperty(si->h, field, VT_LPSTR,
591 0, NULL, PyString_AsString(data));
592 } else if (PyInt_Check(data)) {
593 status = MsiSummaryInfoSetProperty(si->h, field, VT_I4,
594 PyInt_AsLong(data), NULL, NULL);
595 } else {
596 PyErr_SetString(PyExc_TypeError, "unsupported type");
597 return NULL;
600 if (status != ERROR_SUCCESS)
601 return msierror(status);
603 Py_INCREF(Py_None);
604 return Py_None;
608 static PyObject*
609 summary_persist(msiobj* si, PyObject *args)
611 int status;
613 status = MsiSummaryInfoPersist(si->h);
614 if (status != ERROR_SUCCESS)
615 return msierror(status);
616 Py_INCREF(Py_None);
617 return Py_None;
620 static PyMethodDef summary_methods[] = {
621 { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS,
622 PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")},
623 { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS,
624 PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")},
625 { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS,
626 PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")},
627 { "Persist", (PyCFunction)summary_persist, METH_NOARGS,
628 PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")},
629 { NULL, NULL }
632 static PyTypeObject summary_Type = {
633 PyVarObject_HEAD_INIT(NULL, 0)
634 "_msi.SummaryInformation", /*tp_name*/
635 sizeof(msiobj), /*tp_basicsize*/
636 0, /*tp_itemsize*/
637 /* methods */
638 (destructor)msiobj_dealloc, /*tp_dealloc*/
639 0, /*tp_print*/
640 0, /*tp_getattr*/
641 0, /*tp_setattr*/
642 0, /*tp_compare*/
643 0, /*tp_repr*/
644 0, /*tp_as_number*/
645 0, /*tp_as_sequence*/
646 0, /*tp_as_mapping*/
647 0, /*tp_hash*/
648 0, /*tp_call*/
649 0, /*tp_str*/
650 PyObject_GenericGetAttr,/*tp_getattro*/
651 PyObject_GenericSetAttr,/*tp_setattro*/
652 0, /*tp_as_buffer*/
653 Py_TPFLAGS_DEFAULT, /*tp_flags*/
654 0, /*tp_doc*/
655 0, /*tp_traverse*/
656 0, /*tp_clear*/
657 0, /*tp_richcompare*/
658 0, /*tp_weaklistoffset*/
659 0, /*tp_iter*/
660 0, /*tp_iternext*/
661 summary_methods, /*tp_methods*/
662 0, /*tp_members*/
663 0, /*tp_getset*/
664 0, /*tp_base*/
665 0, /*tp_dict*/
666 0, /*tp_descr_get*/
667 0, /*tp_descr_set*/
668 0, /*tp_dictoffset*/
669 0, /*tp_init*/
670 0, /*tp_alloc*/
671 0, /*tp_new*/
672 0, /*tp_free*/
673 0, /*tp_is_gc*/
676 /*************************** View objects **************/
678 static PyObject*
679 view_execute(msiobj *view, PyObject*args)
681 int status;
682 MSIHANDLE params = 0;
683 PyObject *oparams = Py_None;
685 if (!PyArg_ParseTuple(args, "O:Execute", &oparams))
686 return NULL;
688 if (oparams != Py_None) {
689 if (oparams->ob_type != &record_Type) {
690 PyErr_SetString(PyExc_TypeError, "Execute argument must be a record");
691 return NULL;
693 params = ((msiobj*)oparams)->h;
696 status = MsiViewExecute(view->h, params);
697 if (status != ERROR_SUCCESS)
698 return msierror(status);
700 Py_INCREF(Py_None);
701 return Py_None;
704 static PyObject*
705 view_fetch(msiobj *view, PyObject*args)
707 int status;
708 MSIHANDLE result;
710 if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS)
711 return msierror(status);
713 return record_new(result);
716 static PyObject*
717 view_getcolumninfo(msiobj *view, PyObject *args)
719 int status;
720 int kind;
721 MSIHANDLE result;
723 if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind))
724 return NULL;
726 if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS)
727 return msierror(status);
729 return record_new(result);
732 static PyObject*
733 view_modify(msiobj *view, PyObject *args)
735 int kind;
736 PyObject *data;
737 int status;
739 if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data))
740 return NULL;
742 if (data->ob_type != &record_Type) {
743 PyErr_SetString(PyExc_TypeError, "Modify expects a record object");
744 return NULL;
747 if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS)
748 return msierror(status);
750 Py_INCREF(Py_None);
751 return Py_None;
754 static PyObject*
755 view_close(msiobj *view, PyObject*args)
757 int status;
759 if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS)
760 return msierror(status);
762 Py_INCREF(Py_None);
763 return Py_None;
766 static PyMethodDef view_methods[] = {
767 { "Execute", (PyCFunction)view_execute, METH_VARARGS,
768 PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")},
769 { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS,
770 PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")},
771 { "Fetch", (PyCFunction)view_fetch, METH_NOARGS,
772 PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")},
773 { "Modify", (PyCFunction)view_modify, METH_VARARGS,
774 PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")},
775 { "Close", (PyCFunction)view_close, METH_NOARGS,
776 PyDoc_STR("Close() -> result\nWraps MsiViewClose")},
777 { NULL, NULL }
780 static PyTypeObject msiview_Type = {
781 PyVarObject_HEAD_INIT(NULL, 0)
782 "_msi.View", /*tp_name*/
783 sizeof(msiobj), /*tp_basicsize*/
784 0, /*tp_itemsize*/
785 /* methods */
786 (destructor)msiobj_dealloc, /*tp_dealloc*/
787 0, /*tp_print*/
788 0, /*tp_getattr*/
789 0, /*tp_setattr*/
790 0, /*tp_compare*/
791 0, /*tp_repr*/
792 0, /*tp_as_number*/
793 0, /*tp_as_sequence*/
794 0, /*tp_as_mapping*/
795 0, /*tp_hash*/
796 0, /*tp_call*/
797 0, /*tp_str*/
798 PyObject_GenericGetAttr,/*tp_getattro*/
799 PyObject_GenericSetAttr,/*tp_setattro*/
800 0, /*tp_as_buffer*/
801 Py_TPFLAGS_DEFAULT, /*tp_flags*/
802 0, /*tp_doc*/
803 0, /*tp_traverse*/
804 0, /*tp_clear*/
805 0, /*tp_richcompare*/
806 0, /*tp_weaklistoffset*/
807 0, /*tp_iter*/
808 0, /*tp_iternext*/
809 view_methods, /*tp_methods*/
810 0, /*tp_members*/
811 0, /*tp_getset*/
812 0, /*tp_base*/
813 0, /*tp_dict*/
814 0, /*tp_descr_get*/
815 0, /*tp_descr_set*/
816 0, /*tp_dictoffset*/
817 0, /*tp_init*/
818 0, /*tp_alloc*/
819 0, /*tp_new*/
820 0, /*tp_free*/
821 0, /*tp_is_gc*/
824 /*************************** Database objects **************/
826 static PyObject*
827 msidb_openview(msiobj *msidb, PyObject *args)
829 int status;
830 char *sql;
831 MSIHANDLE hView;
832 msiobj *result;
834 if (!PyArg_ParseTuple(args, "s:OpenView", &sql))
835 return NULL;
837 if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS)
838 return msierror(status);
840 result = PyObject_NEW(struct msiobj, &msiview_Type);
841 if (!result) {
842 MsiCloseHandle(hView);
843 return NULL;
846 result->h = hView;
847 return (PyObject*)result;
850 static PyObject*
851 msidb_commit(msiobj *msidb, PyObject *args)
853 int status;
855 if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS)
856 return msierror(status);
858 Py_INCREF(Py_None);
859 return Py_None;
862 static PyObject*
863 msidb_getsummaryinformation(msiobj *db, PyObject *args)
865 int status;
866 int count;
867 MSIHANDLE result;
868 msiobj *oresult;
870 if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count))
871 return NULL;
873 status = MsiGetSummaryInformation(db->h, NULL, count, &result);
874 if (status != ERROR_SUCCESS)
875 return msierror(status);
877 oresult = PyObject_NEW(struct msiobj, &summary_Type);
878 if (!result) {
879 MsiCloseHandle(result);
880 return NULL;
883 oresult->h = result;
884 return (PyObject*)oresult;
887 static PyMethodDef db_methods[] = {
888 { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS,
889 PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")},
890 { "Commit", (PyCFunction)msidb_commit, METH_NOARGS,
891 PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")},
892 { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS,
893 PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")},
894 { NULL, NULL }
897 static PyTypeObject msidb_Type = {
898 PyVarObject_HEAD_INIT(NULL, 0)
899 "_msi.Database", /*tp_name*/
900 sizeof(msiobj), /*tp_basicsize*/
901 0, /*tp_itemsize*/
902 /* methods */
903 (destructor)msiobj_dealloc, /*tp_dealloc*/
904 0, /*tp_print*/
905 0, /*tp_getattr*/
906 0, /*tp_setattr*/
907 0, /*tp_compare*/
908 0, /*tp_repr*/
909 0, /*tp_as_number*/
910 0, /*tp_as_sequence*/
911 0, /*tp_as_mapping*/
912 0, /*tp_hash*/
913 0, /*tp_call*/
914 0, /*tp_str*/
915 PyObject_GenericGetAttr,/*tp_getattro*/
916 PyObject_GenericSetAttr,/*tp_setattro*/
917 0, /*tp_as_buffer*/
918 Py_TPFLAGS_DEFAULT, /*tp_flags*/
919 0, /*tp_doc*/
920 0, /*tp_traverse*/
921 0, /*tp_clear*/
922 0, /*tp_richcompare*/
923 0, /*tp_weaklistoffset*/
924 0, /*tp_iter*/
925 0, /*tp_iternext*/
926 db_methods, /*tp_methods*/
927 0, /*tp_members*/
928 0, /*tp_getset*/
929 0, /*tp_base*/
930 0, /*tp_dict*/
931 0, /*tp_descr_get*/
932 0, /*tp_descr_set*/
933 0, /*tp_dictoffset*/
934 0, /*tp_init*/
935 0, /*tp_alloc*/
936 0, /*tp_new*/
937 0, /*tp_free*/
938 0, /*tp_is_gc*/
941 static PyObject* msiopendb(PyObject *obj, PyObject *args)
943 int status;
944 char *path;
945 int persist;
946 MSIHANDLE h;
947 msiobj *result;
949 if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist))
950 return NULL;
952 status = MsiOpenDatabase(path, (LPCSTR)persist, &h);
953 if (status != ERROR_SUCCESS)
954 return msierror(status);
956 result = PyObject_NEW(struct msiobj, &msidb_Type);
957 if (!result) {
958 MsiCloseHandle(h);
959 return NULL;
961 result->h = h;
962 return (PyObject*)result;
965 static PyObject*
966 createrecord(PyObject *o, PyObject *args)
968 int count;
969 MSIHANDLE h;
971 if (!PyArg_ParseTuple(args, "i:CreateRecord", &count))
972 return NULL;
974 h = MsiCreateRecord(count);
975 if (h == 0)
976 return msierror(0);
978 return record_new(h);
982 static PyMethodDef msi_methods[] = {
983 {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS,
984 PyDoc_STR("UuidCreate() -> string")},
985 {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS,
986 PyDoc_STR("fcicreate(cabname,files) -> None")},
987 {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS,
988 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")},
989 {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS,
990 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")},
991 {NULL, NULL} /* sentinel */
994 static char msi_doc[] = "Documentation";
996 PyMODINIT_FUNC
997 init_msi(void)
999 PyObject *m;
1001 m = Py_InitModule3("_msi", msi_methods, msi_doc);
1002 if (m == NULL)
1003 return;
1005 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (int)MSIDBOPEN_CREATEDIRECT);
1006 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (int)MSIDBOPEN_CREATE);
1007 PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (int)MSIDBOPEN_DIRECT);
1008 PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (int)MSIDBOPEN_READONLY);
1009 PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT);
1010 PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE);
1012 PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES);
1013 PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES);
1015 PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK);
1016 PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH);
1017 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT);
1018 PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE);
1019 PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN);
1020 PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE);
1021 PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE);
1022 PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE);
1023 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY);
1024 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE);
1025 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW);
1026 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD);
1027 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE);
1029 PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE);
1030 PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE);
1031 PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT);
1032 PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR);
1033 PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS);
1034 PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS);
1035 PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE);
1036 PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR);
1037 PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER);
1038 PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED);
1039 PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM);
1040 PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM);
1041 PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT);
1042 PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT);
1043 PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT);
1044 PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME);
1045 PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY);
1047 MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL);
1048 if (!MSIError)
1049 return;
1050 PyModule_AddObject(m, "MSIError", MSIError);