1 /* Helper library for MSI creation with Python.
2 * Copyright (C) 2005 Martin v. Löwis
3 * Licensed to PSF under a contributor agreement.
15 static PyObject
*MSIError
;
18 uuidcreate(PyObject
* obj
, PyObject
*args
)
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
28 if (UuidCreate(&result
) == RPC_S_UUID_NO_ADDRESS
) {
29 PyErr_SetString(PyExc_NotImplementedError
, "processing 'no address' result");
33 if (UuidToString(&result
, &cresult
) == RPC_S_OUT_OF_MEMORY
) {
34 PyErr_SetString(PyExc_MemoryError
, "out of memory in uuidgen");
38 oresult
= PyString_FromString(cresult
);
39 RpcStringFree(&cresult
);
44 /* FCI callback functions */
46 static FNFCIALLOC(cb_alloc
)
51 static FNFCIFREE(cb_free
)
56 static FNFCIOPEN(cb_open
)
58 int result
= _open(pszFile
, oflag
, pmode
);
64 static FNFCIREAD(cb_read
)
66 UINT result
= (UINT
)_read(hf
, memory
, cb
);
72 static FNFCIWRITE(cb_write
)
74 UINT result
= (UINT
)_write(hf
, memory
, cb
);
80 static FNFCICLOSE(cb_close
)
82 int result
= _close(hf
);
88 static FNFCISEEK(cb_seek
)
90 long result
= (long)_lseek(hf
, dist
, seektype
);
96 static FNFCIDELETE(cb_delete
)
98 int result
= remove(pszFile
);
104 static FNFCIFILEPLACED(cb_fileplaced
)
109 static FNFCIGETTEMPFILE(cb_gettempfile
)
111 char *name
= _tempnam("", "tmp");
112 if ((name
!= NULL
) && ((int)strlen(name
) < cbTempName
)) {
113 strcpy(pszTempName
, name
);
118 if (name
) free(name
);
122 static FNFCISTATUS(cb_status
)
125 PyObject
*result
= PyObject_CallMethod(pv
, "status", "iii", typeStatus
, cb1
, cb2
);
133 static FNFCIGETNEXTCABINET(cb_getnextcabinet
)
136 PyObject
*result
= PyObject_CallMethod(pv
, "getnextcabinet", "i", pccab
->iCab
);
139 if (!PyString_Check(result
)) {
140 PyErr_Format(PyExc_TypeError
,
141 "Incorrect return type %s from getnextcabinet",
142 result
->ob_type
->tp_name
);
146 strncpy(pccab
->szCab
, PyString_AsString(result
), sizeof(pccab
->szCab
));
152 static FNFCIGETOPENINFO(cb_getopeninfo
)
154 BY_HANDLE_FILE_INFORMATION bhfi
;
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
)
164 if (GetFileInformationByHandle(handle
, &bhfi
) == FALSE
)
170 FileTimeToLocalFileTime(&bhfi
.ftLastWriteTime
, &filetime
);
171 FileTimeToDosDateTime(&filetime
, pdate
, ptime
);
173 *pattribs
= (int)(bhfi
.dwFileAttributes
&
174 (_A_RDONLY
| _A_SYSTEM
| _A_HIDDEN
| _A_ARCH
));
178 return _open(pszName
, _O_RDONLY
| _O_BINARY
);
181 static PyObject
* fcicreate(PyObject
* obj
, PyObject
* args
)
191 if (!PyArg_ParseTuple(args
, "sO:FCICreate", &cabname
, &files
))
194 if (!PyList_Check(files
)) {
195 PyErr_SetString(PyExc_TypeError
, "FCICreate expects a list");
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;
209 ccab
.szDisk
[0] = '\0';
211 for (i
=0; cabname
[i
]; i
++)
212 if (cabname
[i
] == '\\' || cabname
[i
] == '/')
215 if (i
> sizeof(ccab
.szCabPath
) ||
216 strlen(cabname
+i
) > sizeof(ccab
.szCab
)) {
217 PyErr_SetString(PyExc_ValueError
, "path name too long");
222 memcpy(ccab
.szCabPath
, cabname
, i
);
223 ccab
.szCabPath
[i
] = '\0';
224 strcpy(ccab
.szCab
, cabname
+i
);
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
);
235 PyErr_Format(PyExc_ValueError
, "FCI error %d", erf
.erfOper
);
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
))
244 if (!FCIAddFile(hfci
, filename
, cabname
, FALSE
,
245 cb_getnextcabinet
, cb_status
, cb_getopeninfo
,
250 if (!FCIFlushCabinet(hfci
, FALSE
, cb_getnextcabinet
, cb_status
))
253 if (!FCIDestroy(hfci
))
259 PyErr_Format(PyExc_ValueError
, "FCI error %d", erf
.erfOper
); /* XXX better error type */
264 typedef struct msiobj
{
270 msiobj_dealloc(msiobj
* msidb
)
272 MsiCloseHandle(msidb
->h
);
277 msiobj_close(msiobj
* msidb
, PyObject
*args
)
279 MsiCloseHandle(msidb
->h
);
291 DWORD size
= sizeof(buf
);
292 MSIHANDLE err
= MsiGetLastErrorRecord();
296 case ERROR_ACCESS_DENIED
:
297 PyErr_SetString(MSIError
, "access denied");
299 case ERROR_FUNCTION_FAILED
:
300 PyErr_SetString(MSIError
, "function failed");
302 case ERROR_INVALID_DATA
:
303 PyErr_SetString(MSIError
, "invalid data");
305 case ERROR_INVALID_HANDLE
:
306 PyErr_SetString(MSIError
, "invalid handle");
308 case ERROR_INVALID_STATE
:
309 PyErr_SetString(MSIError
, "invalid state");
311 case ERROR_INVALID_PARAMETER
:
312 PyErr_SetString(MSIError
, "invalid parameter");
315 PyErr_Format(MSIError
, "unknown error %x", status
);
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
);
327 PyErr_SetString(MSIError
, res
);
333 /*************************** Record objects **********************/
336 record_getfieldcount(msiobj
* record
, PyObject
* args
)
338 return PyInt_FromLong(MsiRecordGetFieldCount(record
->h
));
342 record_cleardata(msiobj
* record
, PyObject
*args
)
344 int status
= MsiRecordClearData(record
->h
);
345 if (status
!= ERROR_SUCCESS
)
346 return msierror(status
);
353 record_setstring(msiobj
* record
, PyObject
*args
)
359 if (!PyArg_ParseTuple(args
, "is:SetString", &field
, &data
))
362 if ((status
= MsiRecordSetString(record
->h
, field
, data
)) != ERROR_SUCCESS
)
363 return msierror(status
);
370 record_setstream(msiobj
* record
, PyObject
*args
)
376 if (!PyArg_ParseTuple(args
, "is:SetStream", &field
, &data
))
379 if ((status
= MsiRecordSetStream(record
->h
, field
, data
)) != ERROR_SUCCESS
)
380 return msierror(status
);
387 record_setinteger(msiobj
* record
, PyObject
*args
)
393 if (!PyArg_ParseTuple(args
, "ii:SetInteger", &field
, &data
))
396 if ((status
= MsiRecordSetInteger(record
->h
, field
, data
)) != ERROR_SUCCESS
)
397 return msierror(status
);
405 static 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")},
419 static PyTypeObject record_Type
= {
420 PyObject_HEAD_INIT(NULL
)
422 "_msi.Record", /*tp_name*/
423 sizeof(msiobj
), /*tp_basicsize*/
426 (destructor
)msiobj_dealloc
, /*tp_dealloc*/
433 0, /*tp_as_sequence*/
438 PyObject_GenericGetAttr
,/*tp_getattro*/
439 PyObject_GenericSetAttr
,/*tp_setattro*/
441 Py_TPFLAGS_DEFAULT
, /*tp_flags*/
445 0, /*tp_richcompare*/
446 0, /*tp_weaklistoffset*/
449 record_methods
, /*tp_methods*/
465 record_new(MSIHANDLE h
)
467 msiobj
*result
= PyObject_NEW(struct msiobj
, &record_Type
);
475 return (PyObject
*)result
;
478 /*************************** SummaryInformation objects **************/
481 summary_getproperty(msiobj
* si
, PyObject
*args
)
491 DWORD ssize
= sizeof(sval
);
493 if (!PyArg_ParseTuple(args
, "i:GetProperty", &field
))
496 status
= MsiSummaryInfoGetProperty(si
->h
, field
, &type
, &ival
,
497 &fval
, sval
, &ssize
);
498 if (status
== ERROR_MORE_DATA
) {
499 sval
= malloc(ssize
);
500 status
= MsiSummaryInfoGetProperty(si
->h
, field
, &type
, &ival
,
501 &fval
, sval
, &ssize
);
505 case VT_I2
: case VT_I4
:
506 return PyInt_FromLong(ival
);
508 PyErr_SetString(PyExc_NotImplementedError
, "FILETIME result");
511 result
= PyString_FromStringAndSize(sval
, ssize
);
516 PyErr_Format(PyExc_NotImplementedError
, "result of type %d", type
);
521 summary_getpropertycount(msiobj
* si
, PyObject
*args
)
526 status
= MsiSummaryInfoGetPropertyCount(si
->h
, &result
);
527 if (status
!= ERROR_SUCCESS
)
528 return msierror(status
);
530 return PyInt_FromLong(result
);
534 summary_setproperty(msiobj
* si
, PyObject
*args
)
540 if (!PyArg_ParseTuple(args
, "iO:SetProperty", &field
, &data
))
543 if (PyString_Check(data
)) {
544 status
= MsiSummaryInfoSetProperty(si
->h
, field
, VT_LPSTR
,
545 0, NULL
, PyString_AsString(data
));
546 } else if (PyInt_Check(data
)) {
547 status
= MsiSummaryInfoSetProperty(si
->h
, field
, VT_I4
,
548 PyInt_AsLong(data
), NULL
, NULL
);
550 PyErr_SetString(PyExc_TypeError
, "unsupported type");
554 if (status
!= ERROR_SUCCESS
)
555 return msierror(status
);
563 summary_persist(msiobj
* si
, PyObject
*args
)
567 status
= MsiSummaryInfoPersist(si
->h
);
568 if (status
!= ERROR_SUCCESS
)
569 return msierror(status
);
574 static PyMethodDef summary_methods
[] = {
575 { "GetProperty", (PyCFunction
)summary_getproperty
, METH_VARARGS
,
576 PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")},
577 { "GetPropertyCount", (PyCFunction
)summary_getpropertycount
, METH_NOARGS
,
578 PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")},
579 { "SetProperty", (PyCFunction
)summary_setproperty
, METH_VARARGS
,
580 PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")},
581 { "Persist", (PyCFunction
)summary_persist
, METH_NOARGS
,
582 PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")},
586 static PyTypeObject summary_Type
= {
587 PyObject_HEAD_INIT(NULL
)
589 "_msi.SummaryInformation", /*tp_name*/
590 sizeof(msiobj
), /*tp_basicsize*/
593 (destructor
)msiobj_dealloc
, /*tp_dealloc*/
600 0, /*tp_as_sequence*/
605 PyObject_GenericGetAttr
,/*tp_getattro*/
606 PyObject_GenericSetAttr
,/*tp_setattro*/
608 Py_TPFLAGS_DEFAULT
, /*tp_flags*/
612 0, /*tp_richcompare*/
613 0, /*tp_weaklistoffset*/
616 summary_methods
, /*tp_methods*/
631 /*************************** View objects **************/
634 view_execute(msiobj
*view
, PyObject
*args
)
637 MSIHANDLE params
= 0;
638 PyObject
*oparams
= Py_None
;
640 if (!PyArg_ParseTuple(args
, "O:Execute", &oparams
))
643 if (oparams
!= Py_None
) {
644 if (oparams
->ob_type
!= &record_Type
) {
645 PyErr_SetString(PyExc_TypeError
, "Execute argument must be a record");
648 params
= ((msiobj
*)oparams
)->h
;
651 status
= MsiViewExecute(view
->h
, params
);
652 if (status
!= ERROR_SUCCESS
)
653 return msierror(status
);
660 view_fetch(msiobj
*view
, PyObject
*args
)
665 if ((status
= MsiViewFetch(view
->h
, &result
)) != ERROR_SUCCESS
)
666 return msierror(status
);
668 return record_new(result
);
672 view_getcolumninfo(msiobj
*view
, PyObject
*args
)
678 if (!PyArg_ParseTuple(args
, "i:GetColumnInfo", &kind
))
681 if ((status
= MsiViewGetColumnInfo(view
->h
, kind
, &result
)) != ERROR_SUCCESS
)
682 return msierror(status
);
684 return record_new(result
);
688 view_modify(msiobj
*view
, PyObject
*args
)
694 if (!PyArg_ParseTuple(args
, "iO:Modify", &kind
, &data
))
697 if (data
->ob_type
!= &record_Type
) {
698 PyErr_SetString(PyExc_TypeError
, "Modify expects a record object");
702 if ((status
= MsiViewModify(view
->h
, kind
, ((msiobj
*)data
)->h
)) != ERROR_SUCCESS
)
703 return msierror(status
);
710 view_close(msiobj
*view
, PyObject
*args
)
714 if ((status
= MsiViewClose(view
->h
)) != ERROR_SUCCESS
)
715 return msierror(status
);
721 static PyMethodDef view_methods
[] = {
722 { "Execute", (PyCFunction
)view_execute
, METH_VARARGS
,
723 PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")},
724 { "GetColumnInfo", (PyCFunction
)view_getcolumninfo
, METH_VARARGS
,
725 PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")},
726 { "Fetch", (PyCFunction
)view_fetch
, METH_NOARGS
,
727 PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")},
728 { "Modify", (PyCFunction
)view_modify
, METH_VARARGS
,
729 PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")},
730 { "Close", (PyCFunction
)view_close
, METH_NOARGS
,
731 PyDoc_STR("Close() -> result\nWraps MsiViewClose")},
735 static PyTypeObject msiview_Type
= {
736 PyObject_HEAD_INIT(NULL
)
738 "_msi.View", /*tp_name*/
739 sizeof(msiobj
), /*tp_basicsize*/
742 (destructor
)msiobj_dealloc
, /*tp_dealloc*/
749 0, /*tp_as_sequence*/
754 PyObject_GenericGetAttr
,/*tp_getattro*/
755 PyObject_GenericSetAttr
,/*tp_setattro*/
757 Py_TPFLAGS_DEFAULT
, /*tp_flags*/
761 0, /*tp_richcompare*/
762 0, /*tp_weaklistoffset*/
765 view_methods
, /*tp_methods*/
780 /*************************** Database objects **************/
783 msidb_openview(msiobj
*msidb
, PyObject
*args
)
790 if (!PyArg_ParseTuple(args
, "s:OpenView", &sql
))
793 if ((status
= MsiDatabaseOpenView(msidb
->h
, sql
, &hView
)) != ERROR_SUCCESS
)
794 return msierror(status
);
796 result
= PyObject_NEW(struct msiobj
, &msiview_Type
);
798 MsiCloseHandle(hView
);
803 return (PyObject
*)result
;
807 msidb_commit(msiobj
*msidb
, PyObject
*args
)
811 if ((status
= MsiDatabaseCommit(msidb
->h
)) != ERROR_SUCCESS
)
812 return msierror(status
);
819 msidb_getsummaryinformation(msiobj
*db
, PyObject
*args
)
826 if (!PyArg_ParseTuple(args
, "i:GetSummaryInformation", &count
))
829 status
= MsiGetSummaryInformation(db
->h
, NULL
, count
, &result
);
830 if (status
!= ERROR_SUCCESS
)
831 return msierror(status
);
833 oresult
= PyObject_NEW(struct msiobj
, &summary_Type
);
835 MsiCloseHandle(result
);
840 return (PyObject
*)oresult
;
843 static PyMethodDef db_methods
[] = {
844 { "OpenView", (PyCFunction
)msidb_openview
, METH_VARARGS
,
845 PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")},
846 { "Commit", (PyCFunction
)msidb_commit
, METH_NOARGS
,
847 PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")},
848 { "GetSummaryInformation", (PyCFunction
)msidb_getsummaryinformation
, METH_VARARGS
,
849 PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")},
853 static PyTypeObject msidb_Type
= {
854 PyObject_HEAD_INIT(NULL
)
856 "_msi.Database", /*tp_name*/
857 sizeof(msiobj
), /*tp_basicsize*/
860 (destructor
)msiobj_dealloc
, /*tp_dealloc*/
867 0, /*tp_as_sequence*/
872 PyObject_GenericGetAttr
,/*tp_getattro*/
873 PyObject_GenericSetAttr
,/*tp_setattro*/
875 Py_TPFLAGS_DEFAULT
, /*tp_flags*/
879 0, /*tp_richcompare*/
880 0, /*tp_weaklistoffset*/
883 db_methods
, /*tp_methods*/
898 static PyObject
* msiopendb(PyObject
*obj
, PyObject
*args
)
906 if (!PyArg_ParseTuple(args
, "si:MSIOpenDatabase", &path
, &persist
))
909 status
= MsiOpenDatabase(path
, (LPCSTR
)persist
, &h
);
910 if (status
!= ERROR_SUCCESS
)
911 return msierror(status
);
913 result
= PyObject_NEW(struct msiobj
, &msidb_Type
);
919 return (PyObject
*)result
;
923 createrecord(PyObject
*o
, PyObject
*args
)
928 if (!PyArg_ParseTuple(args
, "i:CreateRecord", &count
))
931 h
= MsiCreateRecord(count
);
935 return record_new(h
);
939 static 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 */
951 static char msi_doc
[] = "Documentation";
958 m
= Py_InitModule3("_msi", msi_methods
, msi_doc
);
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
);
969 PyModule_AddIntConstant(m
, "MSICOLINFO_NAMES", MSICOLINFO_NAMES
);
970 PyModule_AddIntConstant(m
, "MSICOLINFO_TYPES", MSICOLINFO_TYPES
);
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
);
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
);
1004 MSIError
= PyErr_NewException ("_msi.MSIError", NULL
, NULL
);
1007 PyModule_AddObject(m
, "MSIError", MSIError
);