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 PyObject_Del(msidb); 275 } 276 277 static PyObject* 278 msiobj_close(msiobj* msidb, PyObject *args) 279 { 280 MsiCloseHandle(msidb->h); 281 msidb->h = 0; 282 Py_INCREF(Py_None); 283 return Py_None; 284 } 285 286 static PyObject* 287 msierror(int status) 288 { 289 int code; 290 char buf[2000]; 291 char *res = buf; 292 DWORD size = sizeof(buf); 293 MSIHANDLE err = MsiGetLastErrorRecord(); 294 295 if (err == 0) { 296 switch(status) { 297 case ERROR_ACCESS_DENIED: 298 PyErr_SetString(MSIError, "access denied"); 299 return NULL; 300 case ERROR_FUNCTION_FAILED: 301 PyErr_SetString(MSIError, "function failed"); 302 return NULL; 303 case ERROR_INVALID_DATA: 304 PyErr_SetString(MSIError, "invalid data"); 305 return NULL; 306 case ERROR_INVALID_HANDLE: 307 PyErr_SetString(MSIError, "invalid handle"); 308 return NULL; 309 case ERROR_INVALID_STATE: 310 PyErr_SetString(MSIError, "invalid state"); 311 return NULL; 312 case ERROR_INVALID_PARAMETER: 313 PyErr_SetString(MSIError, "invalid parameter"); 314 return NULL; 315 default: 316 PyErr_Format(MSIError, "unknown error %x", status); 317 return NULL; 318 } 319 } 320 321 code = MsiRecordGetInteger(err, 1); /* XXX code */ 322 if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) { 323 res = malloc(size+1); 324 if (res == NULL) { 325 MsiCloseHandle(err); 326 return PyErr_NoMemory(); 327 } 328 MsiFormatRecord(0, err, res, &size); 329 res[size]='\0'; 330 } 331 MsiCloseHandle(err); 332 PyErr_SetString(MSIError, res); 333 if (res != buf) 334 free(res); 335 return NULL; 336 } 337 338 /*************************** Record objects **********************/ 339 340 static PyObject* 341 record_getfieldcount(msiobj* record, PyObject* args) 342 { 343 return PyInt_FromLong(MsiRecordGetFieldCount(record->h)); 344 } 345 346 static PyObject* 347 record_getinteger(msiobj* record, PyObject* args) 348 { 349 unsigned int field; 350 int status; 351 352 if (!PyArg_ParseTuple(args, "I:GetInteger", &field)) 353 return NULL; 354 status = MsiRecordGetInteger(record->h, field); 355 if (status == MSI_NULL_INTEGER){ 356 PyErr_SetString(MSIError, "could not convert record field to integer"); 357 return NULL; 358 } 359 return PyInt_FromLong((long) status); 360 } 361 362 static PyObject* 363 record_getstring(msiobj* record, PyObject* args) 364 { 365 unsigned int field; 366 unsigned int status; 367 char buf[2000]; 368 char *res = buf; 369 DWORD size = sizeof(buf); 370 PyObject* string; 371 372 if (!PyArg_ParseTuple(args, "I:GetString", &field)) 373 return NULL; 374 status = MsiRecordGetString(record->h, field, res, &size); 375 if (status == ERROR_MORE_DATA) { 376 res = (char*) malloc(size + 1); 377 if (res == NULL) 378 return PyErr_NoMemory(); 379 status = MsiRecordGetString(record->h, field, res, &size); 380 } 381 if (status != ERROR_SUCCESS) 382 return msierror((int) status); 383 string = PyString_FromString(res); 384 if (buf != res) 385 free(res); 386 return string; 387 } 388 389 static PyObject* 390 record_cleardata(msiobj* record, PyObject *args) 391 { 392 int status = MsiRecordClearData(record->h); 393 if (status != ERROR_SUCCESS) 394 return msierror(status); 395 396 Py_INCREF(Py_None); 397 return Py_None; 398 } 399 400 static PyObject* 401 record_setstring(msiobj* record, PyObject *args) 402 { 403 int status; 404 int field; 405 char *data; 406 407 if (!PyArg_ParseTuple(args, "is:SetString", &field, &data)) 408 return NULL; 409 410 if ((status = MsiRecordSetString(record->h, field, data)) != ERROR_SUCCESS) 411 return msierror(status); 412 413 Py_INCREF(Py_None); 414 return Py_None; 415 } 416 417 static PyObject* 418 record_setstream(msiobj* record, PyObject *args) 419 { 420 int status; 421 int field; 422 char *data; 423 424 if (!PyArg_ParseTuple(args, "is:SetStream", &field, &data)) 425 return NULL; 426 427 if ((status = MsiRecordSetStream(record->h, field, data)) != ERROR_SUCCESS) 428 return msierror(status); 429 430 Py_INCREF(Py_None); 431 return Py_None; 432 } 433 434 static PyObject* 435 record_setinteger(msiobj* record, PyObject *args) 436 { 437 int status; 438 int field; 439 int data; 440 441 if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data)) 442 return NULL; 443 444 if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS) 445 return msierror(status); 446 447 Py_INCREF(Py_None); 448 return Py_None; 449 } 450 451 452 453 static PyMethodDef record_methods[] = { 454 { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS, 455 PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")}, 456 { "GetInteger", (PyCFunction)record_getinteger, METH_VARARGS, 457 PyDoc_STR("GetInteger(field) -> int\nWraps MsiRecordGetInteger")}, 458 { "GetString", (PyCFunction)record_getstring, METH_VARARGS, 459 PyDoc_STR("GetString(field) -> string\nWraps MsiRecordGetString")}, 460 { "SetString", (PyCFunction)record_setstring, METH_VARARGS, 461 PyDoc_STR("SetString(field,str) -> None\nWraps MsiRecordSetString")}, 462 { "SetStream", (PyCFunction)record_setstream, METH_VARARGS, 463 PyDoc_STR("SetStream(field,filename) -> None\nWraps MsiRecordSetInteger")}, 464 { "SetInteger", (PyCFunction)record_setinteger, METH_VARARGS, 465 PyDoc_STR("SetInteger(field,int) -> None\nWraps MsiRecordSetInteger")}, 466 { "ClearData", (PyCFunction)record_cleardata, METH_NOARGS, 467 PyDoc_STR("ClearData() -> int\nWraps MsiRecordGClearData")}, 468 { NULL, NULL } 469 }; 470 471 static PyTypeObject record_Type = { 472 PyVarObject_HEAD_INIT(NULL, 0) 473 "_msi.Record", /*tp_name*/ 474 sizeof(msiobj), /*tp_basicsize*/ 475 0, /*tp_itemsize*/ 476 /* methods */ 477 (destructor)msiobj_dealloc, /*tp_dealloc*/ 478 0, /*tp_print*/ 479 0, /*tp_getattr*/ 480 0, /*tp_setattr*/ 481 0, /*tp_compare*/ 482 0, /*tp_repr*/ 483 0, /*tp_as_number*/ 484 0, /*tp_as_sequence*/ 485 0, /*tp_as_mapping*/ 486 0, /*tp_hash*/ 487 0, /*tp_call*/ 488 0, /*tp_str*/ 489 PyObject_GenericGetAttr,/*tp_getattro*/ 490 PyObject_GenericSetAttr,/*tp_setattro*/ 491 0, /*tp_as_buffer*/ 492 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 493 0, /*tp_doc*/ 494 0, /*tp_traverse*/ 495 0, /*tp_clear*/ 496 0, /*tp_richcompare*/ 497 0, /*tp_weaklistoffset*/ 498 0, /*tp_iter*/ 499 0, /*tp_iternext*/ 500 record_methods, /*tp_methods*/ 501 0, /*tp_members*/ 502 0, /*tp_getset*/ 503 0, /*tp_base*/ 504 0, /*tp_dict*/ 505 0, /*tp_descr_get*/ 506 0, /*tp_descr_set*/ 507 0, /*tp_dictoffset*/ 508 0, /*tp_init*/ 509 0, /*tp_alloc*/ 510 0, /*tp_new*/ 511 0, /*tp_free*/ 512 0, /*tp_is_gc*/ 513 }; 514 515 static PyObject* 516 record_new(MSIHANDLE h) 517 { 518 msiobj *result = PyObject_NEW(struct msiobj, &record_Type); 519 520 if (!result) { 521 MsiCloseHandle(h); 522 return NULL; 523 } 524 525 result->h = h; 526 return (PyObject*)result; 527 } 528 529 /*************************** SummaryInformation objects **************/ 530 531 static PyObject* 532 summary_getproperty(msiobj* si, PyObject *args) 533 { 534 int status; 535 int field; 536 PyObject *result; 537 UINT type; 538 INT ival; 539 FILETIME fval; 540 char sbuf[1000]; 541 char *sval = sbuf; 542 DWORD ssize = sizeof(sval); 543 544 if (!PyArg_ParseTuple(args, "i:GetProperty", &field)) 545 return NULL; 546 547 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival, 548 &fval, sval, &ssize); 549 if (status == ERROR_MORE_DATA) { 550 sval = malloc(ssize); 551 if (sval == NULL) { 552 return PyErr_NoMemory(); 553 } 554 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival, 555 &fval, sval, &ssize); 556 } 557 558 switch(type) { 559 case VT_I2: case VT_I4: 560 return PyInt_FromLong(ival); 561 case VT_FILETIME: 562 PyErr_SetString(PyExc_NotImplementedError, "FILETIME result"); 563 return NULL; 564 case VT_LPSTR: 565 result = PyString_FromStringAndSize(sval, ssize); 566 if (sval != sbuf) 567 free(sval); 568 return result; 569 } 570 PyErr_Format(PyExc_NotImplementedError, "result of type %d", type); 571 return NULL; 572 } 573 574 static PyObject* 575 summary_getpropertycount(msiobj* si, PyObject *args) 576 { 577 int status; 578 UINT result; 579 580 status = MsiSummaryInfoGetPropertyCount(si->h, &result); 581 if (status != ERROR_SUCCESS) 582 return msierror(status); 583 584 return PyInt_FromLong(result); 585 } 586 587 static PyObject* 588 summary_setproperty(msiobj* si, PyObject *args) 589 { 590 int status; 591 int field; 592 PyObject* data; 593 594 if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data)) 595 return NULL; 596 597 if (PyString_Check(data)) { 598 status = MsiSummaryInfoSetProperty(si->h, field, VT_LPSTR, 599 0, NULL, PyString_AsString(data)); 600 } else if (PyInt_Check(data)) { 601 status = MsiSummaryInfoSetProperty(si->h, field, VT_I4, 602 PyInt_AsLong(data), NULL, NULL); 603 } else { 604 PyErr_SetString(PyExc_TypeError, "unsupported type"); 605 return NULL; 606 } 607 608 if (status != ERROR_SUCCESS) 609 return msierror(status); 610 611 Py_INCREF(Py_None); 612 return Py_None; 613 } 614 615 616 static PyObject* 617 summary_persist(msiobj* si, PyObject *args) 618 { 619 int status; 620 621 status = MsiSummaryInfoPersist(si->h); 622 if (status != ERROR_SUCCESS) 623 return msierror(status); 624 Py_INCREF(Py_None); 625 return Py_None; 626 } 627 628 static PyMethodDef summary_methods[] = { 629 { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS, 630 PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")}, 631 { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS, 632 PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")}, 633 { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS, 634 PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")}, 635 { "Persist", (PyCFunction)summary_persist, METH_NOARGS, 636 PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")}, 637 { NULL, NULL } 638 }; 639 640 static PyTypeObject summary_Type = { 641 PyVarObject_HEAD_INIT(NULL, 0) 642 "_msi.SummaryInformation", /*tp_name*/ 643 sizeof(msiobj), /*tp_basicsize*/ 644 0, /*tp_itemsize*/ 645 /* methods */ 646 (destructor)msiobj_dealloc, /*tp_dealloc*/ 647 0, /*tp_print*/ 648 0, /*tp_getattr*/ 649 0, /*tp_setattr*/ 650 0, /*tp_compare*/ 651 0, /*tp_repr*/ 652 0, /*tp_as_number*/ 653 0, /*tp_as_sequence*/ 654 0, /*tp_as_mapping*/ 655 0, /*tp_hash*/ 656 0, /*tp_call*/ 657 0, /*tp_str*/ 658 PyObject_GenericGetAttr,/*tp_getattro*/ 659 PyObject_GenericSetAttr,/*tp_setattro*/ 660 0, /*tp_as_buffer*/ 661 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 662 0, /*tp_doc*/ 663 0, /*tp_traverse*/ 664 0, /*tp_clear*/ 665 0, /*tp_richcompare*/ 666 0, /*tp_weaklistoffset*/ 667 0, /*tp_iter*/ 668 0, /*tp_iternext*/ 669 summary_methods, /*tp_methods*/ 670 0, /*tp_members*/ 671 0, /*tp_getset*/ 672 0, /*tp_base*/ 673 0, /*tp_dict*/ 674 0, /*tp_descr_get*/ 675 0, /*tp_descr_set*/ 676 0, /*tp_dictoffset*/ 677 0, /*tp_init*/ 678 0, /*tp_alloc*/ 679 0, /*tp_new*/ 680 0, /*tp_free*/ 681 0, /*tp_is_gc*/ 682 }; 683 684 /*************************** View objects **************/ 685 686 static PyObject* 687 view_execute(msiobj *view, PyObject*args) 688 { 689 int status; 690 MSIHANDLE params = 0; 691 PyObject *oparams = Py_None; 692 693 if (!PyArg_ParseTuple(args, "O:Execute", &oparams)) 694 return NULL; 695 696 if (oparams != Py_None) { 697 if (oparams->ob_type != &record_Type) { 698 PyErr_SetString(PyExc_TypeError, "Execute argument must be a record"); 699 return NULL; 700 } 701 params = ((msiobj*)oparams)->h; 702 } 703 704 status = MsiViewExecute(view->h, params); 705 if (status != ERROR_SUCCESS) 706 return msierror(status); 707 708 Py_INCREF(Py_None); 709 return Py_None; 710 } 711 712 static PyObject* 713 view_fetch(msiobj *view, PyObject*args) 714 { 715 int status; 716 MSIHANDLE result; 717 718 if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS) 719 return msierror(status); 720 721 return record_new(result); 722 } 723 724 static PyObject* 725 view_getcolumninfo(msiobj *view, PyObject *args) 726 { 727 int status; 728 int kind; 729 MSIHANDLE result; 730 731 if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind)) 732 return NULL; 733 734 if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS) 735 return msierror(status); 736 737 return record_new(result); 738 } 739 740 static PyObject* 741 view_modify(msiobj *view, PyObject *args) 742 { 743 int kind; 744 PyObject *data; 745 int status; 746 747 if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data)) 748 return NULL; 749 750 if (data->ob_type != &record_Type) { 751 PyErr_SetString(PyExc_TypeError, "Modify expects a record object"); 752 return NULL; 753 } 754 755 if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS) 756 return msierror(status); 757 758 Py_INCREF(Py_None); 759 return Py_None; 760 } 761 762 static PyObject* 763 view_close(msiobj *view, PyObject*args) 764 { 765 int status; 766 767 if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS) 768 return msierror(status); 769 770 Py_INCREF(Py_None); 771 return Py_None; 772 } 773 774 static PyMethodDef view_methods[] = { 775 { "Execute", (PyCFunction)view_execute, METH_VARARGS, 776 PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")}, 777 { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS, 778 PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")}, 779 { "Fetch", (PyCFunction)view_fetch, METH_NOARGS, 780 PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")}, 781 { "Modify", (PyCFunction)view_modify, METH_VARARGS, 782 PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")}, 783 { "Close", (PyCFunction)view_close, METH_NOARGS, 784 PyDoc_STR("Close() -> result\nWraps MsiViewClose")}, 785 { NULL, NULL } 786 }; 787 788 static PyTypeObject msiview_Type = { 789 PyVarObject_HEAD_INIT(NULL, 0) 790 "_msi.View", /*tp_name*/ 791 sizeof(msiobj), /*tp_basicsize*/ 792 0, /*tp_itemsize*/ 793 /* methods */ 794 (destructor)msiobj_dealloc, /*tp_dealloc*/ 795 0, /*tp_print*/ 796 0, /*tp_getattr*/ 797 0, /*tp_setattr*/ 798 0, /*tp_compare*/ 799 0, /*tp_repr*/ 800 0, /*tp_as_number*/ 801 0, /*tp_as_sequence*/ 802 0, /*tp_as_mapping*/ 803 0, /*tp_hash*/ 804 0, /*tp_call*/ 805 0, /*tp_str*/ 806 PyObject_GenericGetAttr,/*tp_getattro*/ 807 PyObject_GenericSetAttr,/*tp_setattro*/ 808 0, /*tp_as_buffer*/ 809 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 810 0, /*tp_doc*/ 811 0, /*tp_traverse*/ 812 0, /*tp_clear*/ 813 0, /*tp_richcompare*/ 814 0, /*tp_weaklistoffset*/ 815 0, /*tp_iter*/ 816 0, /*tp_iternext*/ 817 view_methods, /*tp_methods*/ 818 0, /*tp_members*/ 819 0, /*tp_getset*/ 820 0, /*tp_base*/ 821 0, /*tp_dict*/ 822 0, /*tp_descr_get*/ 823 0, /*tp_descr_set*/ 824 0, /*tp_dictoffset*/ 825 0, /*tp_init*/ 826 0, /*tp_alloc*/ 827 0, /*tp_new*/ 828 0, /*tp_free*/ 829 0, /*tp_is_gc*/ 830 }; 831 832 /*************************** Database objects **************/ 833 834 static PyObject* 835 msidb_openview(msiobj *msidb, PyObject *args) 836 { 837 int status; 838 char *sql; 839 MSIHANDLE hView; 840 msiobj *result; 841 842 if (!PyArg_ParseTuple(args, "s:OpenView", &sql)) 843 return NULL; 844 845 if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS) 846 return msierror(status); 847 848 result = PyObject_NEW(struct msiobj, &msiview_Type); 849 if (!result) { 850 MsiCloseHandle(hView); 851 return NULL; 852 } 853 854 result->h = hView; 855 return (PyObject*)result; 856 } 857 858 static PyObject* 859 msidb_commit(msiobj *msidb, PyObject *args) 860 { 861 int status; 862 863 if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS) 864 return msierror(status); 865 866 Py_INCREF(Py_None); 867 return Py_None; 868 } 869 870 static PyObject* 871 msidb_getsummaryinformation(msiobj *db, PyObject *args) 872 { 873 int status; 874 int count; 875 MSIHANDLE result; 876 msiobj *oresult; 877 878 if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count)) 879 return NULL; 880 881 status = MsiGetSummaryInformation(db->h, NULL, count, &result); 882 if (status != ERROR_SUCCESS) 883 return msierror(status); 884 885 oresult = PyObject_NEW(struct msiobj, &summary_Type); 886 if (!result) { 887 MsiCloseHandle(result); 888 return NULL; 889 } 890 891 oresult->h = result; 892 return (PyObject*)oresult; 893 } 894 895 static PyMethodDef db_methods[] = { 896 { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS, 897 PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")}, 898 { "Commit", (PyCFunction)msidb_commit, METH_NOARGS, 899 PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")}, 900 { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS, 901 PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")}, 902 { NULL, NULL } 903 }; 904 905 static PyTypeObject msidb_Type = { 906 PyVarObject_HEAD_INIT(NULL, 0) 907 "_msi.Database", /*tp_name*/ 908 sizeof(msiobj), /*tp_basicsize*/ 909 0, /*tp_itemsize*/ 910 /* methods */ 911 (destructor)msiobj_dealloc, /*tp_dealloc*/ 912 0, /*tp_print*/ 913 0, /*tp_getattr*/ 914 0, /*tp_setattr*/ 915 0, /*tp_compare*/ 916 0, /*tp_repr*/ 917 0, /*tp_as_number*/ 918 0, /*tp_as_sequence*/ 919 0, /*tp_as_mapping*/ 920 0, /*tp_hash*/ 921 0, /*tp_call*/ 922 0, /*tp_str*/ 923 PyObject_GenericGetAttr,/*tp_getattro*/ 924 PyObject_GenericSetAttr,/*tp_setattro*/ 925 0, /*tp_as_buffer*/ 926 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 927 0, /*tp_doc*/ 928 0, /*tp_traverse*/ 929 0, /*tp_clear*/ 930 0, /*tp_richcompare*/ 931 0, /*tp_weaklistoffset*/ 932 0, /*tp_iter*/ 933 0, /*tp_iternext*/ 934 db_methods, /*tp_methods*/ 935 0, /*tp_members*/ 936 0, /*tp_getset*/ 937 0, /*tp_base*/ 938 0, /*tp_dict*/ 939 0, /*tp_descr_get*/ 940 0, /*tp_descr_set*/ 941 0, /*tp_dictoffset*/ 942 0, /*tp_init*/ 943 0, /*tp_alloc*/ 944 0, /*tp_new*/ 945 0, /*tp_free*/ 946 0, /*tp_is_gc*/ 947 }; 948 949 #define Py_NOT_PERSIST(x, flag) \ 950 (x != (int)(flag) && \ 951 x != ((int)(flag) | MSIDBOPEN_PATCHFILE)) 952 953 #define Py_INVALID_PERSIST(x) \ 954 (Py_NOT_PERSIST(x, MSIDBOPEN_READONLY) && \ 955 Py_NOT_PERSIST(x, MSIDBOPEN_TRANSACT) && \ 956 Py_NOT_PERSIST(x, MSIDBOPEN_DIRECT) && \ 957 Py_NOT_PERSIST(x, MSIDBOPEN_CREATE) && \ 958 Py_NOT_PERSIST(x, MSIDBOPEN_CREATEDIRECT)) 959 960 static PyObject* msiopendb(PyObject *obj, PyObject *args) 961 { 962 int status; 963 char *path; 964 int persist; 965 MSIHANDLE h; 966 msiobj *result; 967 if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist)) 968 return NULL; 969 /* We need to validate that persist is a valid MSIDBOPEN_* value. Otherwise, 970 MsiOpenDatabase may treat the value as a pointer, leading to unexpected 971 behavior. */ 972 if (Py_INVALID_PERSIST(persist)) 973 return msierror(ERROR_INVALID_PARAMETER); 974 status = MsiOpenDatabase(path, (LPCSTR)persist, &h); 975 if (status != ERROR_SUCCESS) 976 return msierror(status); 977 978 result = PyObject_NEW(struct msiobj, &msidb_Type); 979 if (!result) { 980 MsiCloseHandle(h); 981 return NULL; 982 } 983 result->h = h; 984 return (PyObject*)result; 985 } 986 987 static PyObject* 988 createrecord(PyObject *o, PyObject *args) 989 { 990 int count; 991 MSIHANDLE h; 992 993 if (!PyArg_ParseTuple(args, "i:CreateRecord", &count)) 994 return NULL; 995 996 h = MsiCreateRecord(count); 997 if (h == 0) 998 return msierror(0); 999 1000 return record_new(h); 1001 } 1002 1003 1004 static PyMethodDef msi_methods[] = { 1005 {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS, 1006 PyDoc_STR("UuidCreate() -> string")}, 1007 {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS, 1008 PyDoc_STR("fcicreate(cabname,files) -> None")}, 1009 {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS, 1010 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")}, 1011 {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS, 1012 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")}, 1013 {NULL, NULL} /* sentinel */ 1014 }; 1015 1016 static char msi_doc[] = "Documentation"; 1017 1018 PyMODINIT_FUNC 1019 init_msi(void) 1020 { 1021 PyObject *m; 1022 1023 m = Py_InitModule3("_msi", msi_methods, msi_doc); 1024 if (m == NULL) 1025 return; 1026 1027 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (int)MSIDBOPEN_CREATEDIRECT); 1028 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (int)MSIDBOPEN_CREATE); 1029 PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (int)MSIDBOPEN_DIRECT); 1030 PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (int)MSIDBOPEN_READONLY); 1031 PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT); 1032 PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE); 1033 1034 PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES); 1035 PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES); 1036 1037 PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK); 1038 PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH); 1039 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT); 1040 PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE); 1041 PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN); 1042 PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE); 1043 PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE); 1044 PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE); 1045 PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY); 1046 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE); 1047 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW); 1048 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD); 1049 PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE); 1050 1051 PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE); 1052 PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE); 1053 PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT); 1054 PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR); 1055 PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS); 1056 PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS); 1057 PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE); 1058 PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR); 1059 PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER); 1060 PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED); 1061 PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM); 1062 PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM); 1063 PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT); 1064 PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT); 1065 PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT); 1066 PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME); 1067 PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY); 1068 1069 MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL); 1070 if (!MSIError) 1071 return; 1072 PyModule_AddObject(m, "MSIError", MSIError); 1073 } 1074