/PC/_msi.c

http://unladen-swallow.googlecode.com/ · C · 1051 lines · 881 code · 152 blank · 18 comment · 135 complexity · afd2bc681554a61e25b58b3f02e4be5d MD5 · raw file

  1. /* Helper library for MSI creation with Python.
  2. * Copyright (C) 2005 Martin v. Löwis
  3. * Licensed to PSF under a contributor agreement.
  4. */
  5. #include <Python.h>
  6. #include <fci.h>
  7. #include <fcntl.h>
  8. #include <windows.h>
  9. #include <msi.h>
  10. #include <msiquery.h>
  11. #include <msidefs.h>
  12. #include <rpc.h>
  13. static PyObject *MSIError;
  14. static PyObject*
  15. uuidcreate(PyObject* obj, PyObject*args)
  16. {
  17. UUID result;
  18. char *cresult;
  19. PyObject *oresult;
  20. /* May return ok, local only, and no address.
  21. For local only, the documentation says we still get a uuid.
  22. For RPC_S_UUID_NO_ADDRESS, it's not clear whether we can
  23. use the result. */
  24. if (UuidCreate(&result) == RPC_S_UUID_NO_ADDRESS) {
  25. PyErr_SetString(PyExc_NotImplementedError, "processing 'no address' result");
  26. return NULL;
  27. }
  28. if (UuidToString(&result, &cresult) == RPC_S_OUT_OF_MEMORY) {
  29. PyErr_SetString(PyExc_MemoryError, "out of memory in uuidgen");
  30. return NULL;
  31. }
  32. oresult = PyString_FromString(cresult);
  33. RpcStringFree(&cresult);
  34. return oresult;
  35. }
  36. /* FCI callback functions */
  37. static FNFCIALLOC(cb_alloc)
  38. {
  39. return malloc(cb);
  40. }
  41. static FNFCIFREE(cb_free)
  42. {
  43. free(memory);
  44. }
  45. static FNFCIOPEN(cb_open)
  46. {
  47. int result = _open(pszFile, oflag, pmode);
  48. if (result == -1)
  49. *err = errno;
  50. return result;
  51. }
  52. static FNFCIREAD(cb_read)
  53. {
  54. UINT result = (UINT)_read(hf, memory, cb);
  55. if (result != cb)
  56. *err = errno;
  57. return result;
  58. }
  59. static FNFCIWRITE(cb_write)
  60. {
  61. UINT result = (UINT)_write(hf, memory, cb);
  62. if (result != cb)
  63. *err = errno;
  64. return result;
  65. }
  66. static FNFCICLOSE(cb_close)
  67. {
  68. int result = _close(hf);
  69. if (result != 0)
  70. *err = errno;
  71. return result;
  72. }
  73. static FNFCISEEK(cb_seek)
  74. {
  75. long result = (long)_lseek(hf, dist, seektype);
  76. if (result == -1)
  77. *err = errno;
  78. return result;
  79. }
  80. static FNFCIDELETE(cb_delete)
  81. {
  82. int result = remove(pszFile);
  83. if (result != 0)
  84. *err = errno;
  85. return result;
  86. }
  87. static FNFCIFILEPLACED(cb_fileplaced)
  88. {
  89. return 0;
  90. }
  91. static FNFCIGETTEMPFILE(cb_gettempfile)
  92. {
  93. char *name = _tempnam("", "tmp");
  94. if ((name != NULL) && ((int)strlen(name) < cbTempName)) {
  95. strcpy(pszTempName, name);
  96. free(name);
  97. return TRUE;
  98. }
  99. if (name) free(name);
  100. return FALSE;
  101. }
  102. static FNFCISTATUS(cb_status)
  103. {
  104. if (pv) {
  105. PyObject *result = PyObject_CallMethod(pv, "status", "iii", typeStatus, cb1, cb2);
  106. if (result == NULL)
  107. return -1;
  108. Py_DECREF(result);
  109. }
  110. return 0;
  111. }
  112. static FNFCIGETNEXTCABINET(cb_getnextcabinet)
  113. {
  114. if (pv) {
  115. PyObject *result = PyObject_CallMethod(pv, "getnextcabinet", "i", pccab->iCab);
  116. if (result == NULL)
  117. return -1;
  118. if (!PyString_Check(result)) {
  119. PyErr_Format(PyExc_TypeError,
  120. "Incorrect return type %s from getnextcabinet",
  121. result->ob_type->tp_name);
  122. Py_DECREF(result);
  123. return FALSE;
  124. }
  125. strncpy(pccab->szCab, PyString_AsString(result), sizeof(pccab->szCab));
  126. return TRUE;
  127. }
  128. return FALSE;
  129. }
  130. static FNFCIGETOPENINFO(cb_getopeninfo)
  131. {
  132. BY_HANDLE_FILE_INFORMATION bhfi;
  133. FILETIME filetime;
  134. HANDLE handle;
  135. /* Need Win32 handle to get time stamps */
  136. handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
  137. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  138. if (handle == INVALID_HANDLE_VALUE)
  139. return -1;
  140. if (GetFileInformationByHandle(handle, &bhfi) == FALSE)
  141. {
  142. CloseHandle(handle);
  143. return -1;
  144. }
  145. FileTimeToLocalFileTime(&bhfi.ftLastWriteTime, &filetime);
  146. FileTimeToDosDateTime(&filetime, pdate, ptime);
  147. *pattribs = (int)(bhfi.dwFileAttributes &
  148. (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH));
  149. CloseHandle(handle);
  150. return _open(pszName, _O_RDONLY | _O_BINARY);
  151. }
  152. static PyObject* fcicreate(PyObject* obj, PyObject* args)
  153. {
  154. char *cabname, *p;
  155. PyObject *files;
  156. CCAB ccab;
  157. HFCI hfci;
  158. ERF erf;
  159. Py_ssize_t i;
  160. if (!PyArg_ParseTuple(args, "sO:FCICreate", &cabname, &files))
  161. return NULL;
  162. if (!PyList_Check(files)) {
  163. PyErr_SetString(PyExc_TypeError, "FCICreate expects a list");
  164. return NULL;
  165. }
  166. ccab.cb = INT_MAX; /* no need to split CAB into multiple media */
  167. ccab.cbFolderThresh = 1000000; /* flush directory after this many bytes */
  168. ccab.cbReserveCFData = 0;
  169. ccab.cbReserveCFFolder = 0;
  170. ccab.cbReserveCFHeader = 0;
  171. ccab.iCab = 1;
  172. ccab.iDisk = 1;
  173. ccab.setID = 0;
  174. ccab.szDisk[0] = '\0';
  175. for (i = 0, p = cabname; *p; p = CharNext(p))
  176. if (*p == '\\' || *p == '/')
  177. i = p - cabname + 1;
  178. if (i >= sizeof(ccab.szCabPath) ||
  179. strlen(cabname+i) >= sizeof(ccab.szCab)) {
  180. PyErr_SetString(PyExc_ValueError, "path name too long");
  181. return 0;
  182. }
  183. if (i > 0) {
  184. memcpy(ccab.szCabPath, cabname, i);
  185. ccab.szCabPath[i] = '\0';
  186. strcpy(ccab.szCab, cabname+i);
  187. } else {
  188. strcpy(ccab.szCabPath, ".\\");
  189. strcpy(ccab.szCab, cabname);
  190. }
  191. hfci = FCICreate(&erf, cb_fileplaced, cb_alloc, cb_free,
  192. cb_open, cb_read, cb_write, cb_close, cb_seek, cb_delete,
  193. cb_gettempfile, &ccab, NULL);
  194. if (hfci == NULL) {
  195. PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper);
  196. return NULL;
  197. }
  198. for (i=0; i < PyList_GET_SIZE(files); i++) {
  199. PyObject *item = PyList_GET_ITEM(files, i);
  200. char *filename, *cabname;
  201. if (!PyArg_ParseTuple(item, "ss", &filename, &cabname))
  202. goto err;
  203. if (!FCIAddFile(hfci, filename, cabname, FALSE,
  204. cb_getnextcabinet, cb_status, cb_getopeninfo,
  205. tcompTYPE_MSZIP))
  206. goto err;
  207. }
  208. if (!FCIFlushCabinet(hfci, FALSE, cb_getnextcabinet, cb_status))
  209. goto err;
  210. if (!FCIDestroy(hfci))
  211. goto err;
  212. Py_INCREF(Py_None);
  213. return Py_None;
  214. err:
  215. PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
  216. FCIDestroy(hfci);
  217. return NULL;
  218. }
  219. typedef struct msiobj{
  220. PyObject_HEAD
  221. MSIHANDLE h;
  222. }msiobj;
  223. static void
  224. msiobj_dealloc(msiobj* msidb)
  225. {
  226. MsiCloseHandle(msidb->h);
  227. msidb->h = 0;
  228. }
  229. static PyObject*
  230. msiobj_close(msiobj* msidb, PyObject *args)
  231. {
  232. MsiCloseHandle(msidb->h);
  233. msidb->h = 0;
  234. Py_INCREF(Py_None);
  235. return Py_None;
  236. }
  237. static PyObject*
  238. msierror(int status)
  239. {
  240. int code;
  241. char buf[2000];
  242. char *res = buf;
  243. DWORD size = sizeof(buf);
  244. MSIHANDLE err = MsiGetLastErrorRecord();
  245. if (err == 0) {
  246. switch(status) {
  247. case ERROR_ACCESS_DENIED:
  248. PyErr_SetString(MSIError, "access denied");
  249. return NULL;
  250. case ERROR_FUNCTION_FAILED:
  251. PyErr_SetString(MSIError, "function failed");
  252. return NULL;
  253. case ERROR_INVALID_DATA:
  254. PyErr_SetString(MSIError, "invalid data");
  255. return NULL;
  256. case ERROR_INVALID_HANDLE:
  257. PyErr_SetString(MSIError, "invalid handle");
  258. return NULL;
  259. case ERROR_INVALID_STATE:
  260. PyErr_SetString(MSIError, "invalid state");
  261. return NULL;
  262. case ERROR_INVALID_PARAMETER:
  263. PyErr_SetString(MSIError, "invalid parameter");
  264. return NULL;
  265. default:
  266. PyErr_Format(MSIError, "unknown error %x", status);
  267. return NULL;
  268. }
  269. }
  270. code = MsiRecordGetInteger(err, 1); /* XXX code */
  271. if (MsiFormatRecord(0, err, res, &size) == ERROR_MORE_DATA) {
  272. res = malloc(size+1);
  273. MsiFormatRecord(0, err, res, &size);
  274. res[size]='\0';
  275. }
  276. MsiCloseHandle(err);
  277. PyErr_SetString(MSIError, res);
  278. if (res != buf)
  279. free(res);
  280. return NULL;
  281. }
  282. /*************************** Record objects **********************/
  283. static PyObject*
  284. record_getfieldcount(msiobj* record, PyObject* args)
  285. {
  286. return PyInt_FromLong(MsiRecordGetFieldCount(record->h));
  287. }
  288. static PyObject*
  289. record_getinteger(msiobj* record, PyObject* args)
  290. {
  291. unsigned int field;
  292. int status;
  293. if (!PyArg_ParseTuple(args, "I:GetInteger", &field))
  294. return NULL;
  295. status = MsiRecordGetInteger(record->h, field);
  296. if (status == MSI_NULL_INTEGER){
  297. PyErr_SetString(MSIError, "could not convert record field to integer");
  298. return NULL;
  299. }
  300. return PyInt_FromLong((long) status);
  301. }
  302. static PyObject*
  303. record_getstring(msiobj* record, PyObject* args)
  304. {
  305. unsigned int field;
  306. unsigned int status;
  307. char buf[2000];
  308. char *res = buf;
  309. DWORD size = sizeof(buf);
  310. PyObject* string;
  311. if (!PyArg_ParseTuple(args, "I:GetString", &field))
  312. return NULL;
  313. status = MsiRecordGetString(record->h, field, res, &size);
  314. if (status == ERROR_MORE_DATA) {
  315. res = (char*) malloc(size + 1);
  316. if (res == NULL)
  317. return PyErr_NoMemory();
  318. status = MsiRecordGetString(record->h, field, res, &size);
  319. }
  320. if (status != ERROR_SUCCESS)
  321. return msierror((int) status);
  322. string = PyString_FromString(res);
  323. if (buf != res)
  324. free(res);
  325. return string;
  326. }
  327. static PyObject*
  328. record_cleardata(msiobj* record, PyObject *args)
  329. {
  330. int status = MsiRecordClearData(record->h);
  331. if (status != ERROR_SUCCESS)
  332. return msierror(status);
  333. Py_INCREF(Py_None);
  334. return Py_None;
  335. }
  336. static PyObject*
  337. record_setstring(msiobj* record, PyObject *args)
  338. {
  339. int status;
  340. int field;
  341. char *data;
  342. if (!PyArg_ParseTuple(args, "is:SetString", &field, &data))
  343. return NULL;
  344. if ((status = MsiRecordSetString(record->h, field, data)) != ERROR_SUCCESS)
  345. return msierror(status);
  346. Py_INCREF(Py_None);
  347. return Py_None;
  348. }
  349. static PyObject*
  350. record_setstream(msiobj* record, PyObject *args)
  351. {
  352. int status;
  353. int field;
  354. char *data;
  355. if (!PyArg_ParseTuple(args, "is:SetStream", &field, &data))
  356. return NULL;
  357. if ((status = MsiRecordSetStream(record->h, field, data)) != ERROR_SUCCESS)
  358. return msierror(status);
  359. Py_INCREF(Py_None);
  360. return Py_None;
  361. }
  362. static PyObject*
  363. record_setinteger(msiobj* record, PyObject *args)
  364. {
  365. int status;
  366. int field;
  367. int data;
  368. if (!PyArg_ParseTuple(args, "ii:SetInteger", &field, &data))
  369. return NULL;
  370. if ((status = MsiRecordSetInteger(record->h, field, data)) != ERROR_SUCCESS)
  371. return msierror(status);
  372. Py_INCREF(Py_None);
  373. return Py_None;
  374. }
  375. static PyMethodDef record_methods[] = {
  376. { "GetFieldCount", (PyCFunction)record_getfieldcount, METH_NOARGS,
  377. PyDoc_STR("GetFieldCount() -> int\nWraps MsiRecordGetFieldCount")},
  378. { "GetInteger", (PyCFunction)record_getinteger, METH_VARARGS,
  379. PyDoc_STR("GetInteger(field) -> int\nWraps MsiRecordGetInteger")},
  380. { "GetString", (PyCFunction)record_getstring, METH_VARARGS,
  381. PyDoc_STR("GetString(field) -> string\nWraps MsiRecordGetString")},
  382. { "SetString", (PyCFunction)record_setstring, METH_VARARGS,
  383. PyDoc_STR("SetString(field,str) -> None\nWraps MsiRecordSetString")},
  384. { "SetStream", (PyCFunction)record_setstream, METH_VARARGS,
  385. PyDoc_STR("SetStream(field,filename) -> None\nWraps MsiRecordSetInteger")},
  386. { "SetInteger", (PyCFunction)record_setinteger, METH_VARARGS,
  387. PyDoc_STR("SetInteger(field,int) -> None\nWraps MsiRecordSetInteger")},
  388. { "ClearData", (PyCFunction)record_cleardata, METH_NOARGS,
  389. PyDoc_STR("ClearData() -> int\nWraps MsiRecordGClearData")},
  390. { NULL, NULL }
  391. };
  392. static PyTypeObject record_Type = {
  393. PyVarObject_HEAD_INIT(NULL, 0)
  394. "_msi.Record", /*tp_name*/
  395. sizeof(msiobj), /*tp_basicsize*/
  396. 0, /*tp_itemsize*/
  397. /* methods */
  398. (destructor)msiobj_dealloc, /*tp_dealloc*/
  399. 0, /*tp_print*/
  400. 0, /*tp_getattr*/
  401. 0, /*tp_setattr*/
  402. 0, /*tp_compare*/
  403. 0, /*tp_repr*/
  404. 0, /*tp_as_number*/
  405. 0, /*tp_as_sequence*/
  406. 0, /*tp_as_mapping*/
  407. 0, /*tp_hash*/
  408. 0, /*tp_call*/
  409. 0, /*tp_str*/
  410. PyObject_GenericGetAttr,/*tp_getattro*/
  411. PyObject_GenericSetAttr,/*tp_setattro*/
  412. 0, /*tp_as_buffer*/
  413. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  414. 0, /*tp_doc*/
  415. 0, /*tp_traverse*/
  416. 0, /*tp_clear*/
  417. 0, /*tp_richcompare*/
  418. 0, /*tp_weaklistoffset*/
  419. 0, /*tp_iter*/
  420. 0, /*tp_iternext*/
  421. record_methods, /*tp_methods*/
  422. 0, /*tp_members*/
  423. 0, /*tp_getset*/
  424. 0, /*tp_base*/
  425. 0, /*tp_dict*/
  426. 0, /*tp_descr_get*/
  427. 0, /*tp_descr_set*/
  428. 0, /*tp_dictoffset*/
  429. 0, /*tp_init*/
  430. 0, /*tp_alloc*/
  431. 0, /*tp_new*/
  432. 0, /*tp_free*/
  433. 0, /*tp_is_gc*/
  434. };
  435. static PyObject*
  436. record_new(MSIHANDLE h)
  437. {
  438. msiobj *result = PyObject_NEW(struct msiobj, &record_Type);
  439. if (!result) {
  440. MsiCloseHandle(h);
  441. return NULL;
  442. }
  443. result->h = h;
  444. return (PyObject*)result;
  445. }
  446. /*************************** SummaryInformation objects **************/
  447. static PyObject*
  448. summary_getproperty(msiobj* si, PyObject *args)
  449. {
  450. int status;
  451. int field;
  452. PyObject *result;
  453. UINT type;
  454. INT ival;
  455. FILETIME fval;
  456. char sbuf[1000];
  457. char *sval = sbuf;
  458. DWORD ssize = sizeof(sval);
  459. if (!PyArg_ParseTuple(args, "i:GetProperty", &field))
  460. return NULL;
  461. status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
  462. &fval, sval, &ssize);
  463. if (status == ERROR_MORE_DATA) {
  464. sval = malloc(ssize);
  465. status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival,
  466. &fval, sval, &ssize);
  467. }
  468. switch(type) {
  469. case VT_I2: case VT_I4:
  470. return PyInt_FromLong(ival);
  471. case VT_FILETIME:
  472. PyErr_SetString(PyExc_NotImplementedError, "FILETIME result");
  473. return NULL;
  474. case VT_LPSTR:
  475. result = PyString_FromStringAndSize(sval, ssize);
  476. if (sval != sbuf)
  477. free(sval);
  478. return result;
  479. }
  480. PyErr_Format(PyExc_NotImplementedError, "result of type %d", type);
  481. return NULL;
  482. }
  483. static PyObject*
  484. summary_getpropertycount(msiobj* si, PyObject *args)
  485. {
  486. int status;
  487. UINT result;
  488. status = MsiSummaryInfoGetPropertyCount(si->h, &result);
  489. if (status != ERROR_SUCCESS)
  490. return msierror(status);
  491. return PyInt_FromLong(result);
  492. }
  493. static PyObject*
  494. summary_setproperty(msiobj* si, PyObject *args)
  495. {
  496. int status;
  497. int field;
  498. PyObject* data;
  499. if (!PyArg_ParseTuple(args, "iO:SetProperty", &field, &data))
  500. return NULL;
  501. if (PyString_Check(data)) {
  502. status = MsiSummaryInfoSetProperty(si->h, field, VT_LPSTR,
  503. 0, NULL, PyString_AsString(data));
  504. } else if (PyInt_Check(data)) {
  505. status = MsiSummaryInfoSetProperty(si->h, field, VT_I4,
  506. PyInt_AsLong(data), NULL, NULL);
  507. } else {
  508. PyErr_SetString(PyExc_TypeError, "unsupported type");
  509. return NULL;
  510. }
  511. if (status != ERROR_SUCCESS)
  512. return msierror(status);
  513. Py_INCREF(Py_None);
  514. return Py_None;
  515. }
  516. static PyObject*
  517. summary_persist(msiobj* si, PyObject *args)
  518. {
  519. int status;
  520. status = MsiSummaryInfoPersist(si->h);
  521. if (status != ERROR_SUCCESS)
  522. return msierror(status);
  523. Py_INCREF(Py_None);
  524. return Py_None;
  525. }
  526. static PyMethodDef summary_methods[] = {
  527. { "GetProperty", (PyCFunction)summary_getproperty, METH_VARARGS,
  528. PyDoc_STR("GetProperty(propid) -> value\nWraps MsiSummaryInfoGetProperty")},
  529. { "GetPropertyCount", (PyCFunction)summary_getpropertycount, METH_NOARGS,
  530. PyDoc_STR("GetProperty() -> int\nWraps MsiSummaryInfoGetPropertyCount")},
  531. { "SetProperty", (PyCFunction)summary_setproperty, METH_VARARGS,
  532. PyDoc_STR("SetProperty(value) -> None\nWraps MsiSummaryInfoProperty")},
  533. { "Persist", (PyCFunction)summary_persist, METH_NOARGS,
  534. PyDoc_STR("Persist() -> None\nWraps MsiSummaryInfoPersist")},
  535. { NULL, NULL }
  536. };
  537. static PyTypeObject summary_Type = {
  538. PyVarObject_HEAD_INIT(NULL, 0)
  539. "_msi.SummaryInformation", /*tp_name*/
  540. sizeof(msiobj), /*tp_basicsize*/
  541. 0, /*tp_itemsize*/
  542. /* methods */
  543. (destructor)msiobj_dealloc, /*tp_dealloc*/
  544. 0, /*tp_print*/
  545. 0, /*tp_getattr*/
  546. 0, /*tp_setattr*/
  547. 0, /*tp_compare*/
  548. 0, /*tp_repr*/
  549. 0, /*tp_as_number*/
  550. 0, /*tp_as_sequence*/
  551. 0, /*tp_as_mapping*/
  552. 0, /*tp_hash*/
  553. 0, /*tp_call*/
  554. 0, /*tp_str*/
  555. PyObject_GenericGetAttr,/*tp_getattro*/
  556. PyObject_GenericSetAttr,/*tp_setattro*/
  557. 0, /*tp_as_buffer*/
  558. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  559. 0, /*tp_doc*/
  560. 0, /*tp_traverse*/
  561. 0, /*tp_clear*/
  562. 0, /*tp_richcompare*/
  563. 0, /*tp_weaklistoffset*/
  564. 0, /*tp_iter*/
  565. 0, /*tp_iternext*/
  566. summary_methods, /*tp_methods*/
  567. 0, /*tp_members*/
  568. 0, /*tp_getset*/
  569. 0, /*tp_base*/
  570. 0, /*tp_dict*/
  571. 0, /*tp_descr_get*/
  572. 0, /*tp_descr_set*/
  573. 0, /*tp_dictoffset*/
  574. 0, /*tp_init*/
  575. 0, /*tp_alloc*/
  576. 0, /*tp_new*/
  577. 0, /*tp_free*/
  578. 0, /*tp_is_gc*/
  579. };
  580. /*************************** View objects **************/
  581. static PyObject*
  582. view_execute(msiobj *view, PyObject*args)
  583. {
  584. int status;
  585. MSIHANDLE params = 0;
  586. PyObject *oparams = Py_None;
  587. if (!PyArg_ParseTuple(args, "O:Execute", &oparams))
  588. return NULL;
  589. if (oparams != Py_None) {
  590. if (oparams->ob_type != &record_Type) {
  591. PyErr_SetString(PyExc_TypeError, "Execute argument must be a record");
  592. return NULL;
  593. }
  594. params = ((msiobj*)oparams)->h;
  595. }
  596. status = MsiViewExecute(view->h, params);
  597. if (status != ERROR_SUCCESS)
  598. return msierror(status);
  599. Py_INCREF(Py_None);
  600. return Py_None;
  601. }
  602. static PyObject*
  603. view_fetch(msiobj *view, PyObject*args)
  604. {
  605. int status;
  606. MSIHANDLE result;
  607. if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS)
  608. return msierror(status);
  609. return record_new(result);
  610. }
  611. static PyObject*
  612. view_getcolumninfo(msiobj *view, PyObject *args)
  613. {
  614. int status;
  615. int kind;
  616. MSIHANDLE result;
  617. if (!PyArg_ParseTuple(args, "i:GetColumnInfo", &kind))
  618. return NULL;
  619. if ((status = MsiViewGetColumnInfo(view->h, kind, &result)) != ERROR_SUCCESS)
  620. return msierror(status);
  621. return record_new(result);
  622. }
  623. static PyObject*
  624. view_modify(msiobj *view, PyObject *args)
  625. {
  626. int kind;
  627. PyObject *data;
  628. int status;
  629. if (!PyArg_ParseTuple(args, "iO:Modify", &kind, &data))
  630. return NULL;
  631. if (data->ob_type != &record_Type) {
  632. PyErr_SetString(PyExc_TypeError, "Modify expects a record object");
  633. return NULL;
  634. }
  635. if ((status = MsiViewModify(view->h, kind, ((msiobj*)data)->h)) != ERROR_SUCCESS)
  636. return msierror(status);
  637. Py_INCREF(Py_None);
  638. return Py_None;
  639. }
  640. static PyObject*
  641. view_close(msiobj *view, PyObject*args)
  642. {
  643. int status;
  644. if ((status = MsiViewClose(view->h)) != ERROR_SUCCESS)
  645. return msierror(status);
  646. Py_INCREF(Py_None);
  647. return Py_None;
  648. }
  649. static PyMethodDef view_methods[] = {
  650. { "Execute", (PyCFunction)view_execute, METH_VARARGS,
  651. PyDoc_STR("Execute(params=None) -> None\nWraps MsiViewExecute")},
  652. { "GetColumnInfo", (PyCFunction)view_getcolumninfo, METH_VARARGS,
  653. PyDoc_STR("GetColumnInfo() -> result\nWraps MsiGetColumnInfo")},
  654. { "Fetch", (PyCFunction)view_fetch, METH_NOARGS,
  655. PyDoc_STR("Fetch() -> result\nWraps MsiViewFetch")},
  656. { "Modify", (PyCFunction)view_modify, METH_VARARGS,
  657. PyDoc_STR("Modify(mode,record) -> None\nWraps MsiViewModify")},
  658. { "Close", (PyCFunction)view_close, METH_NOARGS,
  659. PyDoc_STR("Close() -> result\nWraps MsiViewClose")},
  660. { NULL, NULL }
  661. };
  662. static PyTypeObject msiview_Type = {
  663. PyVarObject_HEAD_INIT(NULL, 0)
  664. "_msi.View", /*tp_name*/
  665. sizeof(msiobj), /*tp_basicsize*/
  666. 0, /*tp_itemsize*/
  667. /* methods */
  668. (destructor)msiobj_dealloc, /*tp_dealloc*/
  669. 0, /*tp_print*/
  670. 0, /*tp_getattr*/
  671. 0, /*tp_setattr*/
  672. 0, /*tp_compare*/
  673. 0, /*tp_repr*/
  674. 0, /*tp_as_number*/
  675. 0, /*tp_as_sequence*/
  676. 0, /*tp_as_mapping*/
  677. 0, /*tp_hash*/
  678. 0, /*tp_call*/
  679. 0, /*tp_str*/
  680. PyObject_GenericGetAttr,/*tp_getattro*/
  681. PyObject_GenericSetAttr,/*tp_setattro*/
  682. 0, /*tp_as_buffer*/
  683. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  684. 0, /*tp_doc*/
  685. 0, /*tp_traverse*/
  686. 0, /*tp_clear*/
  687. 0, /*tp_richcompare*/
  688. 0, /*tp_weaklistoffset*/
  689. 0, /*tp_iter*/
  690. 0, /*tp_iternext*/
  691. view_methods, /*tp_methods*/
  692. 0, /*tp_members*/
  693. 0, /*tp_getset*/
  694. 0, /*tp_base*/
  695. 0, /*tp_dict*/
  696. 0, /*tp_descr_get*/
  697. 0, /*tp_descr_set*/
  698. 0, /*tp_dictoffset*/
  699. 0, /*tp_init*/
  700. 0, /*tp_alloc*/
  701. 0, /*tp_new*/
  702. 0, /*tp_free*/
  703. 0, /*tp_is_gc*/
  704. };
  705. /*************************** Database objects **************/
  706. static PyObject*
  707. msidb_openview(msiobj *msidb, PyObject *args)
  708. {
  709. int status;
  710. char *sql;
  711. MSIHANDLE hView;
  712. msiobj *result;
  713. if (!PyArg_ParseTuple(args, "s:OpenView", &sql))
  714. return NULL;
  715. if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS)
  716. return msierror(status);
  717. result = PyObject_NEW(struct msiobj, &msiview_Type);
  718. if (!result) {
  719. MsiCloseHandle(hView);
  720. return NULL;
  721. }
  722. result->h = hView;
  723. return (PyObject*)result;
  724. }
  725. static PyObject*
  726. msidb_commit(msiobj *msidb, PyObject *args)
  727. {
  728. int status;
  729. if ((status = MsiDatabaseCommit(msidb->h)) != ERROR_SUCCESS)
  730. return msierror(status);
  731. Py_INCREF(Py_None);
  732. return Py_None;
  733. }
  734. static PyObject*
  735. msidb_getsummaryinformation(msiobj *db, PyObject *args)
  736. {
  737. int status;
  738. int count;
  739. MSIHANDLE result;
  740. msiobj *oresult;
  741. if (!PyArg_ParseTuple(args, "i:GetSummaryInformation", &count))
  742. return NULL;
  743. status = MsiGetSummaryInformation(db->h, NULL, count, &result);
  744. if (status != ERROR_SUCCESS)
  745. return msierror(status);
  746. oresult = PyObject_NEW(struct msiobj, &summary_Type);
  747. if (!result) {
  748. MsiCloseHandle(result);
  749. return NULL;
  750. }
  751. oresult->h = result;
  752. return (PyObject*)oresult;
  753. }
  754. static PyMethodDef db_methods[] = {
  755. { "OpenView", (PyCFunction)msidb_openview, METH_VARARGS,
  756. PyDoc_STR("OpenView(sql) -> viewobj\nWraps MsiDatabaseOpenView")},
  757. { "Commit", (PyCFunction)msidb_commit, METH_NOARGS,
  758. PyDoc_STR("Commit() -> None\nWraps MsiDatabaseCommit")},
  759. { "GetSummaryInformation", (PyCFunction)msidb_getsummaryinformation, METH_VARARGS,
  760. PyDoc_STR("GetSummaryInformation(updateCount) -> viewobj\nWraps MsiGetSummaryInformation")},
  761. { NULL, NULL }
  762. };
  763. static PyTypeObject msidb_Type = {
  764. PyVarObject_HEAD_INIT(NULL, 0)
  765. "_msi.Database", /*tp_name*/
  766. sizeof(msiobj), /*tp_basicsize*/
  767. 0, /*tp_itemsize*/
  768. /* methods */
  769. (destructor)msiobj_dealloc, /*tp_dealloc*/
  770. 0, /*tp_print*/
  771. 0, /*tp_getattr*/
  772. 0, /*tp_setattr*/
  773. 0, /*tp_compare*/
  774. 0, /*tp_repr*/
  775. 0, /*tp_as_number*/
  776. 0, /*tp_as_sequence*/
  777. 0, /*tp_as_mapping*/
  778. 0, /*tp_hash*/
  779. 0, /*tp_call*/
  780. 0, /*tp_str*/
  781. PyObject_GenericGetAttr,/*tp_getattro*/
  782. PyObject_GenericSetAttr,/*tp_setattro*/
  783. 0, /*tp_as_buffer*/
  784. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  785. 0, /*tp_doc*/
  786. 0, /*tp_traverse*/
  787. 0, /*tp_clear*/
  788. 0, /*tp_richcompare*/
  789. 0, /*tp_weaklistoffset*/
  790. 0, /*tp_iter*/
  791. 0, /*tp_iternext*/
  792. db_methods, /*tp_methods*/
  793. 0, /*tp_members*/
  794. 0, /*tp_getset*/
  795. 0, /*tp_base*/
  796. 0, /*tp_dict*/
  797. 0, /*tp_descr_get*/
  798. 0, /*tp_descr_set*/
  799. 0, /*tp_dictoffset*/
  800. 0, /*tp_init*/
  801. 0, /*tp_alloc*/
  802. 0, /*tp_new*/
  803. 0, /*tp_free*/
  804. 0, /*tp_is_gc*/
  805. };
  806. static PyObject* msiopendb(PyObject *obj, PyObject *args)
  807. {
  808. int status;
  809. char *path;
  810. int persist;
  811. MSIHANDLE h;
  812. msiobj *result;
  813. if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist))
  814. return NULL;
  815. status = MsiOpenDatabase(path, (LPCSTR)persist, &h);
  816. if (status != ERROR_SUCCESS)
  817. return msierror(status);
  818. result = PyObject_NEW(struct msiobj, &msidb_Type);
  819. if (!result) {
  820. MsiCloseHandle(h);
  821. return NULL;
  822. }
  823. result->h = h;
  824. return (PyObject*)result;
  825. }
  826. static PyObject*
  827. createrecord(PyObject *o, PyObject *args)
  828. {
  829. int count;
  830. MSIHANDLE h;
  831. if (!PyArg_ParseTuple(args, "i:CreateRecord", &count))
  832. return NULL;
  833. h = MsiCreateRecord(count);
  834. if (h == 0)
  835. return msierror(0);
  836. return record_new(h);
  837. }
  838. static PyMethodDef msi_methods[] = {
  839. {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS,
  840. PyDoc_STR("UuidCreate() -> string")},
  841. {"FCICreate", (PyCFunction)fcicreate, METH_VARARGS,
  842. PyDoc_STR("fcicreate(cabname,files) -> None")},
  843. {"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS,
  844. PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")},
  845. {"CreateRecord", (PyCFunction)createrecord, METH_VARARGS,
  846. PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")},
  847. {NULL, NULL} /* sentinel */
  848. };
  849. static char msi_doc[] = "Documentation";
  850. PyMODINIT_FUNC
  851. init_msi(void)
  852. {
  853. PyObject *m;
  854. m = Py_InitModule3("_msi", msi_methods, msi_doc);
  855. if (m == NULL)
  856. return;
  857. PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (int)MSIDBOPEN_CREATEDIRECT);
  858. PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (int)MSIDBOPEN_CREATE);
  859. PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (int)MSIDBOPEN_DIRECT);
  860. PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (int)MSIDBOPEN_READONLY);
  861. PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT);
  862. PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE);
  863. PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES);
  864. PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES);
  865. PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK);
  866. PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH);
  867. PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT);
  868. PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE);
  869. PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN);
  870. PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE);
  871. PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE);
  872. PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE);
  873. PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY);
  874. PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE);
  875. PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW);
  876. PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD);
  877. PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE);
  878. PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE);
  879. PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE);
  880. PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT);
  881. PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR);
  882. PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS);
  883. PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS);
  884. PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE);
  885. PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR);
  886. PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER);
  887. PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED);
  888. PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM);
  889. PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM);
  890. PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT);
  891. PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT);
  892. PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT);
  893. PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME);
  894. PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY);
  895. MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL);
  896. if (!MSIError)
  897. return;
  898. PyModule_AddObject(m, "MSIError", MSIError);
  899. }