1 /* Helper library for MSI creation with Python. 2 * Copyright (C) 2005 Martin v. Lwis 3 * Licensed to PSF under a contributor agreement. 4 */ 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 15 static PyObject *MSIError; 16 17 static PyObject* 18 uuidcreate(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 38 oresult = PyString_FromString(cresult); 39 RpcStringFree(&cresult); 40 return oresult; 41 42 } 43 44 /* FCI callback functions */ 45 46 static FNFCIALLOC(cb_alloc) 47 { 48 return malloc(cb); 49 } 50 51 static FNFCIFREE(cb_free) 52 { 53 free(memory); 54 } 55 56 static FNFCIOPEN(cb_open) 57 { 58 int result = _open(pszFile, oflag, pmode); 59 if (result == -1) 60 *err = errno; 61 return result; 62 } 63 64 static FNFCIREAD(cb_read) 65 { 66 UINT result = (UINT)_read(hf, memory, cb); 67 if (result != cb) 68 *err = errno; 69 return result; 70 } 71 72 static FNFCIWRITE(cb_write) 73 { 74 UINT result = (UINT)_write(hf, memory, cb); 75 if (result != cb) 76 *err = errno; 77 return result; 78 } 79 80 static FNFCICLOSE(cb_close) 81 { 82 int result = _close(hf); 83 if (result != 0) 84 *err = errno; 85 return result; 86 } 87 88 static FNFCISEEK(cb_seek) 89 { 90 long result = (long)_lseek(hf, dist, seektype); 91 if (result == -1) 92 *err = errno; 93 return result; 94 } 95 96 static FNFCIDELETE(cb_delete) 97 { 98 int result = remove(pszFile); 99 if (result != 0) 100 *err = errno; 101 return result; 102 } 103 104 static FNFCIFILEPLACED(cb_fileplaced) 105 { 106 return 0; 107 } 108 109 static 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 122 static 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 133 static FNFCIGETNEXTCABINET(cb_getnextcabinet) 134 { 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; 145 } 146 strncpy(pccab->szCab, PyString_AsString(result), sizeof(pccab->szCab)); 147 return TRUE; 148 } 149 return FALSE; 150 } 151 152 static 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 181 static PyObject* fcicreate(PyObject* obj, PyObject* args) 182 { 183 char *cabname, *p; 184 PyObject *files; 185 CCAB ccab; 186 HFCI hfci; 187 ERF erf; 188 Py_ssize_t i; 189 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 211 for (i = 0, p = cabname; *p; p = CharNext(p)) 212 if (*p == '\\' || *p == '/') 213 i = p - cabname + 1; 214 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; 219 } 220 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); 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; 258 err: 259 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */ 260 FCIDestroy(hfci); 261 return NULL; 262 } 263 264 typedef struct msiobj{ 265 PyObject_HEAD 266 MSIHANDLE h; 267 }msiobj; 268 269 static void 270 msiobj_dealloc(msiobj* msidb) 271 { 272 MsiCloseHandle(msidb->h); 273 msidb->h = 0; 274 } 275 276 static PyObject* 277 msiobj_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 285 static PyObject* 286 msierror(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 335 static PyObject* 336 record_getfieldcount(msiobj* record, PyObject* args) 337 { 338 return PyInt_FromLong(MsiRecordGetFieldCount(record->h)); 339 } 340 341 static PyObject* 342 record_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 } 354 return PyInt_FromLong((long) status); 355 } 356 357 static PyObject* 358 record_getstring(msiobj* record, PyObject* args) 359 { 360 unsigned int field; 361 unsigned int status; 362 char buf[2000]; 363 char *res = buf; 364 DWORD size = sizeof(buf); 365 PyObject* string; 366 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); 375 } 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; 382 } 383 384 static PyObject* 385 record_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 395 static PyObject* 396 record_setstring(msiobj* record, PyObject *args) 397 { 398 int status; 399 int field; 400 char *data; 401 402 if (!PyArg_ParseTuple(args, "is:SetString", &field, &data)) 403 return NULL; 404 405 if ((status = MsiRecordSetString(record->h, field, data)) != ERROR_SUCCESS) 406 return msierror(status); 407 408 Py_INCREF(Py_None); 409 return Py_None; 410 } 411 412 static PyObject* 413 record_setstream(msiobj* record, PyObject *args) 414 { 415 int status; 416 int field; 417 char *data; 418 419 if (!PyArg_ParseTuple(args, "is:SetStream", &field, &data)) 420 return NULL; 421 422 if ((status = MsiRecordSetStream(record->h, field, data)) != ERROR_SUCCESS) 423 return msierror(status); 424 425 Py_INCREF(Py_None); 426 return Py_None; 427 } 428 429 static PyObject* 430 record_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 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 } 464 }; 465 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*/ 508 }; 509 510 static PyObject* 511 record_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 526 static PyObject* 527 summary_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); 544 if (status == ERROR_MORE_DATA) { 545 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: 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; 561 } 562 PyErr_Format(PyExc_NotImplementedError, "result of type %d", type); 563 return NULL; 564 } 565 566 static PyObject* 567 summary_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 576 return PyInt_FromLong(result); 577 } 578 579 static PyObject* 580 summary_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 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; 598 } 599 600 if (status != ERROR_SUCCESS) 601 return msierror(status); 602 603 Py_INCREF(Py_None); 604 return Py_None; 605 } 606 607 608 static PyObject* 609 summary_persist(msiobj* si, PyObject *args) 610 { 611 int status; 612 613 status = MsiSummaryInfoPersist(si->h); 614 if (status != ERROR_SUCCESS) 615 return msierror(status); 616 Py_INCREF(Py_None); 617 return Py_None; 618 } 619 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 } 630 }; 631 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*/ 674 }; 675 676 /*************************** View objects **************/ 677 678 static PyObject* 679 view_execute(msiobj *view, PyObject*args) 680 { 681 int status; 682 MSIHANDLE params = 0; 683 PyObject *oparams = Py_None; 684 685 if (!PyArg_ParseTuple(args, "O:Execute", &oparams)) 686 return NULL; 687 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; 692 } 693 params = ((msiobj*)oparams)->h; 694 } 695 696 status = MsiViewExecute(view->h, params); 697 if (status != ERROR_SUCCESS) 698 return msierror(status); 699 700 Py_INCREF(Py_None); 701 return Py_None; 702 } 703 704 static PyObject* 705 view_fetch(msiobj *view, PyObject*args) 706 { 707 int status; 708 MSIHANDLE result; 709 710 if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS) 711 return msierror(status); 712 713 return record_new(result); 714 } 715 716 static PyObject* 717 view_getcolumninfo(msiobj *view, PyObject *args) 718 { 719 int status; 720 int kind; 721 MSIHANDLE result; 722 723 if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind)) 724 return NULL; 725 726 if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS) 727 return msierror(status); 728 729 return record_new(result); 730 } 731 732 static PyObject* 733 view_modify(msiobj *view, PyObject *args) 734 { 735 int kind; 736 PyObject *data; 737 int status; 738 739 if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data)) 740 return NULL; 741 742 if (data->ob_type != &record_Type) { 743 PyErr_SetString(PyExc_TypeError, "Modify expects a record object"); 744 return NULL; 745 } 746 747 if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS) 748 return msierror(status); 749 750 Py_INCREF(Py_None); 751 return Py_None; 752 } 753 754 static PyObject* 755 view_close(msiobj *view, PyObject*args) 756 { 757 int status; 758 759 if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS) 760 return msierror(status); 761 762 Py_INCREF(Py_None); 763 return Py_None; 764 } 765 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 } 778 }; 779 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*/ 822 }; 823 824 /*************************** Database objects **************/ 825 826 static PyObject* 827 msidb_openview(msiobj *msidb, PyObject *args) 828 { 829 int status; 830 char *sql; 831 MSIHANDLE hView; 832 msiobj *result; 833 834 if (!PyArg_ParseTuple(args, "s:OpenView", &sql)) 835 return NULL; 836 837 if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS) 838 return msierror(status); 839 840 result = PyObject_NEW(struct msiobj, &msiview_Type); 841 if (!result) { 842 MsiCloseHandle(hView); 843 return NULL; 844 } 845 846 result->h = hView; 847 return (PyObject*)result; 848 } 849 850 static PyObject* 851 msidb_commit(msiobj *msidb, PyObject *args) 852 { 853 int status; 854 855 if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS) 856 return msierror(status); 857 858 Py_INCREF(Py_None); 859 return Py_None; 860 } 861 862 static PyObject* 863 msidb_getsummaryinformation(msiobj *db, PyObject *args) 864 { 865 int status; 866 int count; 867 MSIHANDLE result; 868 msiobj *oresult; 869 870 if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count)) 871 return NULL; 872 873 status = MsiGetSummaryInformation(db->h, NULL, count, &result); 874 if (status != ERROR_SUCCESS) 875 return msierror(status); 876 877 oresult = PyObject_NEW(struct msiobj, &summary_Type); 878 if (!result) { 879 MsiCloseHandle(result); 880 return NULL; 881 } 882 883 oresult->h = result; 884 return (PyObject*)oresult; 885 } 886 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 } 895 }; 896 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*/ 939 }; 940 941 #define Py_NOT_PERSIST(x, flag) \ 942 (x != (int)(flag) && \ 943 x != ((int)(flag) | MSIDBOPEN_PATCHFILE)) 944 945 #define Py_INVALID_PERSIST(x) \ 946 (Py_NOT_PERSIST(x, MSIDBOPEN_READONLY) && \ 947 Py_NOT_PERSIST(x, MSIDBOPEN_TRANSACT) && \ 948 Py_NOT_PERSIST(x, MSIDBOPEN_DIRECT) && \ 949 Py_NOT_PERSIST(x, MSIDBOPEN_CREATE) && \ 950 Py_NOT_PERSIST(x, MSIDBOPEN_CREATEDIRECT)) 951 952 static PyObject* msiopendb(PyObject *obj, PyObject *args) 953 { 954 int status; 955 char *path; 956 int persist; 957 MSIHANDLE h; 958 msiobj *result; 959 if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist)) 960 return NULL; 961 /* We need to validate that persist is a valid MSIDBOPEN_* value. Otherwise, 962 MsiOpenDatabase may treat the value as a pointer, leading to unexpected 963 behavior. */ 964 if (Py_INVALID_PERSIST(persist)) 965 return msierror(ERROR_INVALID_PARAMETER); 966 status = MsiOpenDatabase(path, (LPCSTR)persist, &h); 967 if (status != ERROR_SUCCESS) 968 return msierror(status); 969 970 result = PyObject_NEW(struct msiobj, &msidb_Type); 971 if (!result) { 972 MsiCloseHandle(h); 973 return NULL; 974 } 975 result->h = h; 976 return (PyObject*)result; 977 } 978 979 static PyObject* 980 createrecord(PyObject *o, PyObject *args) 981 { 982 int count; 983 MSIHANDLE h; 984 985 if (!PyArg_ParseTuple(args, "i:CreateRecord", &count)) 986 return NULL; 987 988 h = MsiCreateRecord(count); 989 if (h == 0) 990 return msierror(0); 991 992 return record_new(h); 993 } 994 995 996 static PyMethodDef msi_methods[] = { 997 {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS, 998 PyDoc_STR("UuidCreate() -> string")}, 999 {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS, 1000 PyDoc_STR("fcicreate(cabname,files) -> None")}, 1001 {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS, 1002 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")}, 1003 {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS, 1004 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")}, 1005 {NULL, NULL} /* sentinel */ 1006 }; 1007 1008 static char msi_doc[] = "Documentation"; 1009 1010 PyMODINIT_FUNC 1011 init_msi(void) 1012 { 1013 PyObject *m; 1014 1015 m = Py_InitModule3("_msi", msi_methods, msi_doc); 1016 if (m == NULL) 1017 return; 1018 1019 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (int)MSIDBOPEN_CREATEDIRECT); 1020 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (int)MSIDBOPEN_CREATE); 1021 PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (int)MSIDBOPEN_DIRECT); 1022 PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (int)MSIDBOPEN_READONLY); 1023 PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT); 1024 PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE); 1025 1026 PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES); 1027 PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES); 1028 1029 PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK); 1030 PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH); 1031 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT); 1032 PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE); 1033 PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN); 1034 PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE); 1035 PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE); 1036 PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE); 1037 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY); 1038 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE); 1039 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW); 1040 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD); 1041 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE); 1042 1043 PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE); 1044 PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE); 1045 PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT); 1046 PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR); 1047 PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS); 1048 PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS); 1049 PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE); 1050 PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR); 1051 PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER); 1052 PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED); 1053 PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM); 1054 PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM); 1055 PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT); 1056 PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT); 1057 PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT); 1058 PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME); 1059 PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY); 1060 1061 MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL); 1062 if (!MSIError) 1063 return; 1064 PyModule_AddObject(m, "MSIError", MSIError); 1065 } 1066