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 wchar_t *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 (UuidToStringW(&result, &cresult) == RPC_S_OUT_OF_MEMORY) { 34 PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen"); 35 return NULL; 36 } 37 38 oresult = PyUnicode_FromWideChar(cresult, wcslen(cresult)); 39 RpcStringFreeW(&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 | O_NOINHERIT, pmode); 59 if (result == -1) 60 *err = errno; 61 return result; 62 } 63 64 static FNFCIREAD(cb_read) 65 { 66 UINT result = (UINT)_read((int)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((int)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((int)hf); 83 if (result != 0) 84 *err = errno; 85 return result; 86 } 87 88 static FNFCISEEK(cb_seek) 89 { 90 long result = (long)_lseek((int)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 _Py_IDENTIFIER(status); 126 127 PyObject *result = _PyObject_CallMethodId(pv, &PyId_status, "iii", typeStatus, cb1, cb2); 128 if (result == NULL) 129 return -1; 130 Py_DECREF(result); 131 } 132 return 0; 133 } 134 135 static FNFCIGETNEXTCABINET(cb_getnextcabinet) 136 { 137 if (pv) { 138 _Py_IDENTIFIER(getnextcabinet); 139 140 PyObject *result = _PyObject_CallMethodId(pv, &PyId_getnextcabinet, "i", pccab->iCab); 141 if (result == NULL) 142 return -1; 143 if (!PyBytes_Check(result)) { 144 PyErr_Format(PyExc_TypeError, 145 "Incorrect return type %s from getnextcabinet", 146 result->ob_type->tp_name); 147 Py_DECREF(result); 148 return FALSE; 149 } 150 strncpy(pccab->szCab, PyBytes_AsString(result), sizeof(pccab->szCab)); 151 return TRUE; 152 } 153 return FALSE; 154 } 155 156 static FNFCIGETOPENINFO(cb_getopeninfo) 157 { 158 BY_HANDLE_FILE_INFORMATION bhfi; 159 FILETIME filetime; 160 HANDLE handle; 161 162 /* Need Win32 handle to get time stamps */ 163 handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL, 164 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 165 if (handle == INVALID_HANDLE_VALUE) 166 return -1; 167 168 if (GetFileInformationByHandle(handle, &bhfi) == FALSE) 169 { 170 CloseHandle(handle); 171 return -1; 172 } 173 174 FileTimeToLocalFileTime(&bhfi.ftLastWriteTime, &filetime); 175 FileTimeToDosDateTime(&filetime, pdate, ptime); 176 177 *pattribs = (int)(bhfi.dwFileAttributes & 178 (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH)); 179 180 CloseHandle(handle); 181 182 return _open(pszName, _O_RDONLY | _O_BINARY | O_NOINHERIT); 183 } 184 185 static PyObject* fcicreate(PyObject* obj, PyObject* args) 186 { 187 char *cabname, *p; 188 PyObject *files; 189 CCAB ccab; 190 HFCI hfci; 191 ERF erf; 192 Py_ssize_t i; 193 194 195 if (!PyArg_ParseTuple(args, "sO:FCICreate", &cabname, &files)) 196 return NULL; 197 198 if (!PyList_Check(files)) { 199 PyErr_SetString(PyExc_TypeError, "FCICreate expects a list"); 200 return NULL; 201 } 202 203 ccab.cb = INT_MAX; /* no need to split CAB into multiple media */ 204 ccab.cbFolderThresh = 1000000; /* flush directory after this many bytes */ 205 ccab.cbReserveCFData = 0; 206 ccab.cbReserveCFFolder = 0; 207 ccab.cbReserveCFHeader = 0; 208 209 ccab.iCab = 1; 210 ccab.iDisk = 1; 211 212 ccab.setID = 0; 213 ccab.szDisk[0] = '\0'; 214 215 for (i = 0, p = cabname; *p; p = CharNext(p)) 216 if (*p == '\\' || *p == '/') 217 i = p - cabname + 1; 218 219 if (i >= sizeof(ccab.szCabPath) || 220 strlen(cabname+i) >= sizeof(ccab.szCab)) { 221 PyErr_SetString(PyExc_ValueError, "path name too long"); 222 return 0; 223 } 224 225 if (i > 0) { 226 memcpy(ccab.szCabPath, cabname, i); 227 ccab.szCabPath[i] = '\0'; 228 strcpy(ccab.szCab, cabname+i); 229 } else { 230 strcpy(ccab.szCabPath, ".\\"); 231 strcpy(ccab.szCab, cabname); 232 } 233 234 hfci = FCICreate(&erf, cb_fileplaced, cb_alloc, cb_free, 235 cb_open, cb_read, cb_write, cb_close, cb_seek, cb_delete, 236 cb_gettempfile, &ccab, NULL); 237 238 if (hfci == NULL) { 239 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); 240 return NULL; 241 } 242 243 for (i=0; i < PyList_GET_SIZE(files); i++) { 244 PyObject *item = PyList_GET_ITEM(files, i); 245 char *filename, *cabname; 246 247 if (!PyArg_ParseTuple(item, "ss", &filename, &cabname)) { 248 PyErr_SetString(PyExc_TypeError, "FCICreate expects a list of tuples containing two strings"); 249 FCIDestroy(hfci); 250 return NULL; 251 } 252 253 if (!FCIAddFile(hfci, filename, cabname, FALSE, 254 cb_getnextcabinet, cb_status, cb_getopeninfo, 255 tcompTYPE_MSZIP)) 256 goto err; 257 } 258 259 if (!FCIFlushCabinet(hfci, FALSE, cb_getnextcabinet, cb_status)) 260 goto err; 261 262 if (!FCIDestroy(hfci)) 263 goto err; 264 265 Py_RETURN_NONE; 266 err: 267 if(erf.fError) 268 PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */ 269 else 270 PyErr_SetString(PyExc_ValueError, "FCI general error"); 271 272 FCIDestroy(hfci); 273 return NULL; 274 } 275 276 typedef struct msiobj{ 277 PyObject_HEAD 278 MSIHANDLE h; 279 }msiobj; 280 281 static void 282 msiobj_dealloc(msiobj* msidb) 283 { 284 MsiCloseHandle(msidb->h); 285 msidb->h = 0; 286 PyObject_Del(msidb); 287 } 288 289 static PyObject* 290 msierror(int status) 291 { 292 int code; 293 char buf[2000]; 294 char *res = buf; 295 DWORD size = sizeof(buf); 296 MSIHANDLE err = MsiGetLastErrorRecord(); 297 298 if (err == 0) { 299 switch(status) { 300 case ERROR_ACCESS_DENIED: 301 PyErr_SetString(MSIError, "access denied"); 302 return NULL; 303 case ERROR_FUNCTION_FAILED: 304 PyErr_SetString(MSIError, "function failed"); 305 return NULL; 306 case ERROR_INVALID_DATA: 307 PyErr_SetString(MSIError, "invalid data"); 308 return NULL; 309 case ERROR_INVALID_HANDLE: 310 PyErr_SetString(MSIError, "invalid handle"); 311 return NULL; 312 case ERROR_INVALID_STATE: 313 PyErr_SetString(MSIError, "invalid state"); 314 return NULL; 315 case ERROR_INVALID_PARAMETER: 316 PyErr_SetString(MSIError, "invalid parameter"); 317 return NULL; 318 case ERROR_OPEN_FAILED: 319 PyErr_SetString(MSIError, "open failed"); 320 return NULL; 321 case ERROR_CREATE_FAILED: 322 PyErr_SetString(MSIError, "create failed"); 323 return NULL; 324 default: 325 PyErr_Format(MSIError, "unknown error %x", status); 326 return NULL; 327 } 328 } 329 330 code = MsiRecordGetInteger(err, 1); /* XXX code */ 331 if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) { 332 res = malloc(size+1); 333 if (res == NULL) { 334 MsiCloseHandle(err); 335 return PyErr_NoMemory(); 336 } 337 MsiFormatRecord(0, err, res, &size); 338 res[size]='\0'; 339 } 340 MsiCloseHandle(err); 341 PyErr_SetString(MSIError, res); 342 if (res != buf) 343 free(res); 344 return NULL; 345 } 346 347 static PyObject* 348 msidb_close(msiobj* msidb, PyObject *args) 349 { 350 int status; 351 if ((status = MsiCloseHandle(msidb->h)) != ERROR_SUCCESS) { 352 return msierror(status); 353 } 354 msidb->h = 0; 355 Py_RETURN_NONE; 356 } 357 358 /*************************** Record objects **********************/ 359 360 static PyObject* 361 record_getfieldcount(msiobj* record, PyObject* args) 362 { 363 return PyLong_FromLong(MsiRecordGetFieldCount(record->h)); 364 } 365 366 static PyObject* 367 record_getinteger(msiobj* record, PyObject* args) 368 { 369 unsigned int field; 370 int status; 371 372 if (!PyArg_ParseTuple(args, "I:GetInteger", &field)) 373 return NULL; 374 status = MsiRecordGetInteger(record->h, field); 375 if (status == MSI_NULL_INTEGER){ 376 PyErr_SetString(MSIError, "could not convert record field to integer"); 377 return NULL; 378 } 379 return PyLong_FromLong((long) status); 380 } 381 382 static PyObject* 383 record_getstring(msiobj* record, PyObject* args) 384 { 385 unsigned int field; 386 unsigned int status; 387 WCHAR buf[2000]; 388 WCHAR *res = buf; 389 DWORD size = sizeof(buf); 390 PyObject* string; 391 392 if (!PyArg_ParseTuple(args, "I:GetString", &field)) 393 return NULL; 394 status = MsiRecordGetStringW(record->h, field, res, &size); 395 if (status == ERROR_MORE_DATA) { 396 res = (WCHAR*) malloc((size + 1)*sizeof(WCHAR)); 397 if (res == NULL) 398 return PyErr_NoMemory(); 399 status = MsiRecordGetStringW(record->h, field, res, &size); 400 } 401 if (status != ERROR_SUCCESS) 402 return msierror((int) status); 403 string = PyUnicode_FromWideChar(res, size); 404 if (buf != res) 405 free(res); 406 return string; 407 } 408 409 static PyObject* 410 record_cleardata(msiobj* record, PyObject *args) 411 { 412 int status = MsiRecordClearData(record->h); 413 if (status != ERROR_SUCCESS) 414 return msierror(status); 415 416 Py_RETURN_NONE; 417 } 418 419 static PyObject* 420 record_setstring(msiobj* record, PyObject *args) 421 { 422 int status; 423 int field; 424 wchar_t *data; 425 426 if (!PyArg_ParseTuple(args, "iu:SetString", &field, &data)) 427 return NULL; 428 429 if ((status = MsiRecordSetStringW(record->h, field, data)) != ERROR_SUCCESS) 430 return msierror(status); 431 432 Py_RETURN_NONE; 433 } 434 435 static PyObject* 436 record_setstream(msiobj* record, PyObject *args) 437 { 438 int status; 439 int field; 440 wchar_t *data; 441 442 if (!PyArg_ParseTuple(args, "iu:SetStream", &field, &data)) 443 return NULL; 444 445 if ((status = MsiRecordSetStreamW(record->h, field, data)) != ERROR_SUCCESS) 446 return msierror(status); 447 448 Py_RETURN_NONE; 449 } 450 451 static PyObject* 452 record_setinteger(msiobj* record, PyObject *args) 453 { 454 int status; 455 int field; 456 int data; 457 458 if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data)) 459 return NULL; 460 461 if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS) 462 return msierror(status); 463 464 Py_RETURN_NONE; 465 } 466 467 468 469 static PyMethodDef record_methods[] = { 470 { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS, 471 PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")}, 472 { "GetInteger", (PyCFunction)record_getinteger, METH_VARARGS, 473 PyDoc_STR("GetInteger(field) -> int\nWraps MsiRecordGetInteger")}, 474 { "GetString", (PyCFunction)record_getstring, METH_VARARGS, 475 PyDoc_STR("GetString(field) -> string\nWraps MsiRecordGetString")}, 476 { "SetString", (PyCFunction)record_setstring, METH_VARARGS, 477 PyDoc_STR("SetString(field,str) -> None\nWraps MsiRecordSetString")}, 478 { "SetStream", (PyCFunction)record_setstream, METH_VARARGS, 479 PyDoc_STR("SetStream(field,filename) -> None\nWraps MsiRecordSetInteger")}, 480 { "SetInteger", (PyCFunction)record_setinteger, METH_VARARGS, 481 PyDoc_STR("SetInteger(field,int) -> None\nWraps MsiRecordSetInteger")}, 482 { "ClearData", (PyCFunction)record_cleardata, METH_NOARGS, 483 PyDoc_STR("ClearData() -> int\nWraps MsiRecordGClearData")}, 484 { NULL, NULL } 485 }; 486 487 static PyTypeObject record_Type = { 488 PyVarObject_HEAD_INIT(NULL, 0) 489 "_msi.Record", /*tp_name*/ 490 sizeof(msiobj), /*tp_basicsize*/ 491 0, /*tp_itemsize*/ 492 /* methods */ 493 (destructor)msiobj_dealloc, /*tp_dealloc*/ 494 0, /*tp_print*/ 495 0, /*tp_getattr*/ 496 0, /*tp_setattr*/ 497 0, /*tp_reserved*/ 498 0, /*tp_repr*/ 499 0, /*tp_as_number*/ 500 0, /*tp_as_sequence*/ 501 0, /*tp_as_mapping*/ 502 0, /*tp_hash*/ 503 0, /*tp_call*/ 504 0, /*tp_str*/ 505 PyObject_GenericGetAttr,/*tp_getattro*/ 506 PyObject_GenericSetAttr,/*tp_setattro*/ 507 0, /*tp_as_buffer*/ 508 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 509 0, /*tp_doc*/ 510 0, /*tp_traverse*/ 511 0, /*tp_clear*/ 512 0, /*tp_richcompare*/ 513 0, /*tp_weaklistoffset*/ 514 0, /*tp_iter*/ 515 0, /*tp_iternext*/ 516 record_methods, /*tp_methods*/ 517 0, /*tp_members*/ 518 0, /*tp_getset*/ 519 0, /*tp_base*/ 520 0, /*tp_dict*/ 521 0, /*tp_descr_get*/ 522 0, /*tp_descr_set*/ 523 0, /*tp_dictoffset*/ 524 0, /*tp_init*/ 525 0, /*tp_alloc*/ 526 0, /*tp_new*/ 527 0, /*tp_free*/ 528 0, /*tp_is_gc*/ 529 }; 530 531 static PyObject* 532 record_new(MSIHANDLE h) 533 { 534 msiobj *result = PyObject_NEW(struct msiobj, &record_Type); 535 536 if (!result) { 537 MsiCloseHandle(h); 538 return NULL; 539 } 540 541 result->h = h; 542 return (PyObject*)result; 543 } 544 545 /*************************** SummaryInformation objects **************/ 546 547 static PyObject* 548 summary_getproperty(msiobj* si, PyObject *args) 549 { 550 int status; 551 int field; 552 PyObject *result; 553 UINT type; 554 INT ival; 555 FILETIME fval; 556 char sbuf[1000]; 557 char *sval = sbuf; 558 DWORD ssize = sizeof(sbuf); 559 560 if (!PyArg_ParseTuple(args, "i:GetProperty", &field)) 561 return NULL; 562 563 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival, 564 &fval, sval, &ssize); 565 if (status == ERROR_MORE_DATA) { 566 ssize++; 567 sval = malloc(ssize); 568 if (sval == NULL) { 569 return PyErr_NoMemory(); 570 } 571 status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival, 572 &fval, sval, &ssize); 573 } 574 575 switch(type) { 576 case VT_I2: 577 case VT_I4: 578 result = PyLong_FromLong(ival); 579 break; 580 case VT_FILETIME: 581 PyErr_SetString(PyExc_NotImplementedError, "FILETIME result"); 582 result = NULL; 583 break; 584 case VT_LPSTR: 585 result = PyBytes_FromStringAndSize(sval, ssize); 586 break; 587 case VT_EMPTY: 588 Py_INCREF(Py_None); 589 result = Py_None; 590 break; 591 default: 592 PyErr_Format(PyExc_NotImplementedError, "result of type %d", type); 593 result = NULL; 594 break; 595 } 596 if (sval != sbuf) 597 free(sval); 598 return result; 599 } 600 601 static PyObject* 602 summary_getpropertycount(msiobj* si, PyObject *args) 603 { 604 int status; 605 UINT result; 606 607 status = MsiSummaryInfoGetPropertyCount(si->h, &result); 608 if (status != ERROR_SUCCESS) 609 return msierror(status); 610 611 return PyLong_FromLong(result); 612 } 613 614 static PyObject* 615 summary_setproperty(msiobj* si, PyObject *args) 616 { 617 int status; 618 int field; 619 PyObject* data; 620 621 if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data)) 622 return NULL; 623 624 if (PyUnicode_Check(data)) { 625 const WCHAR *value = _PyUnicode_AsUnicode(data); 626 if (value == NULL) { 627 return NULL; 628 } 629 status = MsiSummaryInfoSetPropertyW(si->h, field, VT_LPSTR, 630 0, NULL, value); 631 } else if (PyLong_CheckExact(data)) { 632 long value = PyLong_AsLong(data); 633 if (value == -1 && PyErr_Occurred()) { 634 return NULL; 635 } 636 status = MsiSummaryInfoSetProperty(si->h, field, VT_I4, 637 value, NULL, NULL); 638 } else { 639 PyErr_SetString(PyExc_TypeError, "unsupported type"); 640 return NULL; 641 } 642 643 if (status != ERROR_SUCCESS) 644 return msierror(status); 645 646 Py_RETURN_NONE; 647 } 648 649 650 static PyObject* 651 summary_persist(msiobj* si, PyObject *args) 652 { 653 int status; 654 655 status = MsiSummaryInfoPersist(si->h); 656 if (status != ERROR_SUCCESS) 657 return msierror(status); 658 Py_RETURN_NONE; 659 } 660 661 static PyMethodDef summary_methods[] = { 662 { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS, 663 PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")}, 664 { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS, 665 PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")}, 666 { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS, 667 PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")}, 668 { "Persist", (PyCFunction)summary_persist, METH_NOARGS, 669 PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")}, 670 { NULL, NULL } 671 }; 672 673 static PyTypeObject summary_Type = { 674 PyVarObject_HEAD_INIT(NULL, 0) 675 "_msi.SummaryInformation", /*tp_name*/ 676 sizeof(msiobj), /*tp_basicsize*/ 677 0, /*tp_itemsize*/ 678 /* methods */ 679 (destructor)msiobj_dealloc, /*tp_dealloc*/ 680 0, /*tp_print*/ 681 0, /*tp_getattr*/ 682 0, /*tp_setattr*/ 683 0, /*tp_reserved*/ 684 0, /*tp_repr*/ 685 0, /*tp_as_number*/ 686 0, /*tp_as_sequence*/ 687 0, /*tp_as_mapping*/ 688 0, /*tp_hash*/ 689 0, /*tp_call*/ 690 0, /*tp_str*/ 691 PyObject_GenericGetAttr,/*tp_getattro*/ 692 PyObject_GenericSetAttr,/*tp_setattro*/ 693 0, /*tp_as_buffer*/ 694 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 695 0, /*tp_doc*/ 696 0, /*tp_traverse*/ 697 0, /*tp_clear*/ 698 0, /*tp_richcompare*/ 699 0, /*tp_weaklistoffset*/ 700 0, /*tp_iter*/ 701 0, /*tp_iternext*/ 702 summary_methods, /*tp_methods*/ 703 0, /*tp_members*/ 704 0, /*tp_getset*/ 705 0, /*tp_base*/ 706 0, /*tp_dict*/ 707 0, /*tp_descr_get*/ 708 0, /*tp_descr_set*/ 709 0, /*tp_dictoffset*/ 710 0, /*tp_init*/ 711 0, /*tp_alloc*/ 712 0, /*tp_new*/ 713 0, /*tp_free*/ 714 0, /*tp_is_gc*/ 715 }; 716 717 /*************************** View objects **************/ 718 719 static PyObject* 720 view_execute(msiobj *view, PyObject*args) 721 { 722 int status; 723 MSIHANDLE params = 0; 724 PyObject *oparams = Py_None; 725 726 if (!PyArg_ParseTuple(args, "O:Execute", &oparams)) 727 return NULL; 728 729 if (oparams != Py_None) { 730 if (oparams->ob_type != &record_Type) { 731 PyErr_SetString(PyExc_TypeError, "Execute argument must be a record"); 732 return NULL; 733 } 734 params = ((msiobj*)oparams)->h; 735 } 736 737 status = MsiViewExecute(view->h, params); 738 if (status != ERROR_SUCCESS) 739 return msierror(status); 740 741 Py_RETURN_NONE; 742 } 743 744 static PyObject* 745 view_fetch(msiobj *view, PyObject*args) 746 { 747 int status; 748 MSIHANDLE result; 749 750 status = MsiViewFetch(view->h, &result); 751 if (status == ERROR_NO_MORE_ITEMS) { 752 Py_RETURN_NONE; 753 } else if (status != ERROR_SUCCESS) { 754 return msierror(status); 755 } 756 757 return record_new(result); 758 } 759 760 static PyObject* 761 view_getcolumninfo(msiobj *view, PyObject *args) 762 { 763 int status; 764 int kind; 765 MSIHANDLE result; 766 767 if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind)) 768 return NULL; 769 770 if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS) 771 return msierror(status); 772 773 return record_new(result); 774 } 775 776 static PyObject* 777 view_modify(msiobj *view, PyObject *args) 778 { 779 int kind; 780 PyObject *data; 781 int status; 782 783 if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data)) 784 return NULL; 785 786 if (data->ob_type != &record_Type) { 787 PyErr_SetString(PyExc_TypeError, "Modify expects a record object"); 788 return NULL; 789 } 790 791 if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS) 792 return msierror(status); 793 794 Py_RETURN_NONE; 795 } 796 797 static PyObject* 798 view_close(msiobj *view, PyObject*args) 799 { 800 int status; 801 802 if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS) 803 return msierror(status); 804 805 Py_RETURN_NONE; 806 } 807 808 static PyMethodDef view_methods[] = { 809 { "Execute", (PyCFunction)view_execute, METH_VARARGS, 810 PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")}, 811 { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS, 812 PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")}, 813 { "Fetch", (PyCFunction)view_fetch, METH_NOARGS, 814 PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")}, 815 { "Modify", (PyCFunction)view_modify, METH_VARARGS, 816 PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")}, 817 { "Close", (PyCFunction)view_close, METH_NOARGS, 818 PyDoc_STR("Close() -> result\nWraps MsiViewClose")}, 819 { NULL, NULL } 820 }; 821 822 static PyTypeObject msiview_Type = { 823 PyVarObject_HEAD_INIT(NULL, 0) 824 "_msi.View", /*tp_name*/ 825 sizeof(msiobj), /*tp_basicsize*/ 826 0, /*tp_itemsize*/ 827 /* methods */ 828 (destructor)msiobj_dealloc, /*tp_dealloc*/ 829 0, /*tp_print*/ 830 0, /*tp_getattr*/ 831 0, /*tp_setattr*/ 832 0, /*tp_reserved*/ 833 0, /*tp_repr*/ 834 0, /*tp_as_number*/ 835 0, /*tp_as_sequence*/ 836 0, /*tp_as_mapping*/ 837 0, /*tp_hash*/ 838 0, /*tp_call*/ 839 0, /*tp_str*/ 840 PyObject_GenericGetAttr,/*tp_getattro*/ 841 PyObject_GenericSetAttr,/*tp_setattro*/ 842 0, /*tp_as_buffer*/ 843 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 844 0, /*tp_doc*/ 845 0, /*tp_traverse*/ 846 0, /*tp_clear*/ 847 0, /*tp_richcompare*/ 848 0, /*tp_weaklistoffset*/ 849 0, /*tp_iter*/ 850 0, /*tp_iternext*/ 851 view_methods, /*tp_methods*/ 852 0, /*tp_members*/ 853 0, /*tp_getset*/ 854 0, /*tp_base*/ 855 0, /*tp_dict*/ 856 0, /*tp_descr_get*/ 857 0, /*tp_descr_set*/ 858 0, /*tp_dictoffset*/ 859 0, /*tp_init*/ 860 0, /*tp_alloc*/ 861 0, /*tp_new*/ 862 0, /*tp_free*/ 863 0, /*tp_is_gc*/ 864 }; 865 866 /*************************** Database objects **************/ 867 868 static PyObject* 869 msidb_openview(msiobj *msidb, PyObject *args) 870 { 871 int status; 872 char *sql; 873 MSIHANDLE hView; 874 msiobj *result; 875 876 if (!PyArg_ParseTuple(args, "s:OpenView", &sql)) 877 return NULL; 878 879 if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS) 880 return msierror(status); 881 882 result = PyObject_NEW(struct msiobj, &msiview_Type); 883 if (!result) { 884 MsiCloseHandle(hView); 885 return NULL; 886 } 887 888 result->h = hView; 889 return (PyObject*)result; 890 } 891 892 static PyObject* 893 msidb_commit(msiobj *msidb, PyObject *args) 894 { 895 int status; 896 897 if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS) 898 return msierror(status); 899 900 Py_RETURN_NONE; 901 } 902 903 static PyObject* 904 msidb_getsummaryinformation(msiobj *db, PyObject *args) 905 { 906 int status; 907 int count; 908 MSIHANDLE result; 909 msiobj *oresult; 910 911 if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count)) 912 return NULL; 913 914 status = MsiGetSummaryInformation(db->h, NULL, count, &result); 915 if (status != ERROR_SUCCESS) 916 return msierror(status); 917 918 oresult = PyObject_NEW(struct msiobj, &summary_Type); 919 if (!oresult) { 920 MsiCloseHandle(result); 921 return NULL; 922 } 923 924 oresult->h = result; 925 return (PyObject*)oresult; 926 } 927 928 static PyMethodDef db_methods[] = { 929 { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS, 930 PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")}, 931 { "Commit", (PyCFunction)msidb_commit, METH_NOARGS, 932 PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")}, 933 { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS, 934 PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")}, 935 { "Close", (PyCFunction)msidb_close, METH_NOARGS, 936 PyDoc_STR("Close() -> None\nWraps MsiCloseHandle")}, 937 { NULL, NULL } 938 }; 939 940 static PyTypeObject msidb_Type = { 941 PyVarObject_HEAD_INIT(NULL, 0) 942 "_msi.Database", /*tp_name*/ 943 sizeof(msiobj), /*tp_basicsize*/ 944 0, /*tp_itemsize*/ 945 /* methods */ 946 (destructor)msiobj_dealloc, /*tp_dealloc*/ 947 0, /*tp_print*/ 948 0, /*tp_getattr*/ 949 0, /*tp_setattr*/ 950 0, /*tp_reserved*/ 951 0, /*tp_repr*/ 952 0, /*tp_as_number*/ 953 0, /*tp_as_sequence*/ 954 0, /*tp_as_mapping*/ 955 0, /*tp_hash*/ 956 0, /*tp_call*/ 957 0, /*tp_str*/ 958 PyObject_GenericGetAttr,/*tp_getattro*/ 959 PyObject_GenericSetAttr,/*tp_setattro*/ 960 0, /*tp_as_buffer*/ 961 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 962 0, /*tp_doc*/ 963 0, /*tp_traverse*/ 964 0, /*tp_clear*/ 965 0, /*tp_richcompare*/ 966 0, /*tp_weaklistoffset*/ 967 0, /*tp_iter*/ 968 0, /*tp_iternext*/ 969 db_methods, /*tp_methods*/ 970 0, /*tp_members*/ 971 0, /*tp_getset*/ 972 0, /*tp_base*/ 973 0, /*tp_dict*/ 974 0, /*tp_descr_get*/ 975 0, /*tp_descr_set*/ 976 0, /*tp_dictoffset*/ 977 0, /*tp_init*/ 978 0, /*tp_alloc*/ 979 0, /*tp_new*/ 980 0, /*tp_free*/ 981 0, /*tp_is_gc*/ 982 }; 983 984 #define Py_NOT_PERSIST(x, flag) \ 985 (x != (SIZE_T)(flag) && \ 986 x != ((SIZE_T)(flag) | MSIDBOPEN_PATCHFILE)) 987 988 #define Py_INVALID_PERSIST(x) \ 989 (Py_NOT_PERSIST(x, MSIDBOPEN_READONLY) && \ 990 Py_NOT_PERSIST(x, MSIDBOPEN_TRANSACT) && \ 991 Py_NOT_PERSIST(x, MSIDBOPEN_DIRECT) && \ 992 Py_NOT_PERSIST(x, MSIDBOPEN_CREATE) && \ 993 Py_NOT_PERSIST(x, MSIDBOPEN_CREATEDIRECT)) 994 995 static PyObject* msiopendb(PyObject *obj, PyObject *args) 996 { 997 int status; 998 char *path; 999 int persist; 1000 MSIHANDLE h; 1001 msiobj *result; 1002 if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist)) 1003 return NULL; 1004 /* We need to validate that persist is a valid MSIDBOPEN_* value. Otherwise, 1005 MsiOpenDatabase may treat the value as a pointer, leading to unexpected 1006 behavior. */ 1007 if (Py_INVALID_PERSIST(persist)) 1008 return msierror(ERROR_INVALID_PARAMETER); 1009 status = MsiOpenDatabase(path, (LPCSTR)(SIZE_T)persist, &h); 1010 if (status != ERROR_SUCCESS) 1011 return msierror(status); 1012 1013 result = PyObject_NEW(struct msiobj, &msidb_Type); 1014 if (!result) { 1015 MsiCloseHandle(h); 1016 return NULL; 1017 } 1018 result->h = h; 1019 return (PyObject*)result; 1020 } 1021 1022 static PyObject* 1023 createrecord(PyObject *o, PyObject *args) 1024 { 1025 int count; 1026 MSIHANDLE h; 1027 1028 if (!PyArg_ParseTuple(args, "i:CreateRecord", &count)) 1029 return NULL; 1030 1031 h = MsiCreateRecord(count); 1032 if (h == 0) 1033 return msierror(0); 1034 1035 return record_new(h); 1036 } 1037 1038 1039 static PyMethodDef msi_methods[] = { 1040 {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS, 1041 PyDoc_STR("UuidCreate() -> string")}, 1042 {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS, 1043 PyDoc_STR("fcicreate(cabname,files) -> None")}, 1044 {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS, 1045 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")}, 1046 {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS, 1047 PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")}, 1048 {NULL, NULL} /* sentinel */ 1049 }; 1050 1051 static char msi_doc[] = "Documentation"; 1052 1053 1054 static struct PyModuleDef _msimodule = { 1055 PyModuleDef_HEAD_INIT, 1056 "_msi", 1057 msi_doc, 1058 -1, 1059 msi_methods, 1060 NULL, 1061 NULL, 1062 NULL, 1063 NULL 1064 }; 1065 1066 PyMODINIT_FUNC 1067 PyInit__msi(void) 1068 { 1069 PyObject *m; 1070 1071 m = PyModule_Create(&_msimodule); 1072 if (m == NULL) 1073 return NULL; 1074 1075 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (long)(SIZE_T)MSIDBOPEN_CREATEDIRECT); 1076 PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (long)(SIZE_T)MSIDBOPEN_CREATE); 1077 PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (long)(SIZE_T)MSIDBOPEN_DIRECT); 1078 PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (long)(SIZE_T)MSIDBOPEN_READONLY); 1079 PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (long)(SIZE_T)MSIDBOPEN_TRANSACT); 1080 PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (long)(SIZE_T)MSIDBOPEN_PATCHFILE); 1081 1082 PyModule_AddIntMacro(m, MSICOLINFO_NAMES); 1083 PyModule_AddIntMacro(m, MSICOLINFO_TYPES); 1084 1085 PyModule_AddIntMacro(m, MSIMODIFY_SEEK); 1086 PyModule_AddIntMacro(m, MSIMODIFY_REFRESH); 1087 PyModule_AddIntMacro(m, MSIMODIFY_INSERT); 1088 PyModule_AddIntMacro(m, MSIMODIFY_UPDATE); 1089 PyModule_AddIntMacro(m, MSIMODIFY_ASSIGN); 1090 PyModule_AddIntMacro(m, MSIMODIFY_REPLACE); 1091 PyModule_AddIntMacro(m, MSIMODIFY_MERGE); 1092 PyModule_AddIntMacro(m, MSIMODIFY_DELETE); 1093 PyModule_AddIntMacro(m, MSIMODIFY_INSERT_TEMPORARY); 1094 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE); 1095 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_NEW); 1096 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_FIELD); 1097 PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_DELETE); 1098 1099 PyModule_AddIntMacro(m, PID_CODEPAGE); 1100 PyModule_AddIntMacro(m, PID_TITLE); 1101 PyModule_AddIntMacro(m, PID_SUBJECT); 1102 PyModule_AddIntMacro(m, PID_AUTHOR); 1103 PyModule_AddIntMacro(m, PID_KEYWORDS); 1104 PyModule_AddIntMacro(m, PID_COMMENTS); 1105 PyModule_AddIntMacro(m, PID_TEMPLATE); 1106 PyModule_AddIntMacro(m, PID_LASTAUTHOR); 1107 PyModule_AddIntMacro(m, PID_REVNUMBER); 1108 PyModule_AddIntMacro(m, PID_LASTPRINTED); 1109 PyModule_AddIntMacro(m, PID_CREATE_DTM); 1110 PyModule_AddIntMacro(m, PID_LASTSAVE_DTM); 1111 PyModule_AddIntMacro(m, PID_PAGECOUNT); 1112 PyModule_AddIntMacro(m, PID_WORDCOUNT); 1113 PyModule_AddIntMacro(m, PID_CHARCOUNT); 1114 PyModule_AddIntMacro(m, PID_APPNAME); 1115 PyModule_AddIntMacro(m, PID_SECURITY); 1116 1117 MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL); 1118 if (!MSIError) 1119 return NULL; 1120 PyModule_AddObject(m, "MSIError", MSIError); 1121 return m; 1122 } 1123