PageRenderTime 66ms CodeModel.GetById 2ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 0ms

/PC/_msi.c

http://unladen-swallow.googlecode.com/
C | 1051 lines | 1003 code | 38 blank | 10 comment | 41 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
   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
  15static PyObject *MSIError;
  16
  17static PyObject*
  18uuidcreate(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
  46static FNFCIALLOC(cb_alloc)
  47{
  48    return malloc(cb);
  49}
  50
  51static FNFCIFREE(cb_free)
  52{
  53    free(memory);
  54}
  55
  56static FNFCIOPEN(cb_open)
  57{
  58    int result = _open(pszFile, oflag, pmode);
  59    if (result == -1)
  60	*err = errno;
  61    return result;
  62}
  63
  64static FNFCIREAD(cb_read)
  65{
  66    UINT result = (UINT)_read(hf, memory, cb);
  67    if (result != cb)
  68	*err = errno;
  69    return result;
  70}
  71
  72static FNFCIWRITE(cb_write)
  73{
  74    UINT result = (UINT)_write(hf, memory, cb);
  75    if (result != cb)
  76	*err = errno;
  77    return result;
  78}
  79
  80static FNFCICLOSE(cb_close)
  81{
  82    int result = _close(hf);
  83    if (result != 0)
  84	*err = errno;
  85    return result;
  86}
  87
  88static FNFCISEEK(cb_seek)
  89{
  90    long result = (long)_lseek(hf, dist, seektype);
  91    if (result == -1)
  92	*err = errno;
  93    return result;
  94}
  95
  96static FNFCIDELETE(cb_delete)
  97{
  98    int result = remove(pszFile);
  99    if (result != 0)
 100	*err = errno;
 101    return result;
 102}
 103
 104static FNFCIFILEPLACED(cb_fileplaced)
 105{
 106    return 0;
 107}
 108
 109static 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
 122static 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
 133static 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
 152static 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
 181static 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;
 258err:
 259    PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
 260    FCIDestroy(hfci);
 261    return NULL;
 262}
 263
 264typedef struct msiobj{
 265    PyObject_HEAD
 266    MSIHANDLE h;
 267}msiobj;
 268
 269static void 
 270msiobj_dealloc(msiobj* msidb)
 271{
 272    MsiCloseHandle(msidb->h);
 273    msidb->h = 0;
 274}
 275
 276static PyObject*
 277msiobj_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
 285static PyObject*
 286msierror(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
 335static PyObject*
 336record_getfieldcount(msiobj* record, PyObject* args)
 337{
 338    return PyInt_FromLong(MsiRecordGetFieldCount(record->h));
 339}
 340
 341static PyObject*
 342record_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
 357static PyObject*
 358record_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
 384static PyObject*
 385record_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
 395static PyObject*
 396record_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
 412static PyObject*
 413record_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
 429static PyObject*
 430record_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
 448static 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
 466static 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
 510static PyObject*
 511record_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
 526static PyObject*
 527summary_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
 566static PyObject*
 567summary_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
 579static PyObject*
 580summary_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
 608static PyObject*
 609summary_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
 620static 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
 632static 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
 678static PyObject*
 679view_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
 704static PyObject*
 705view_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
 716static PyObject*
 717view_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
 732static PyObject*
 733view_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
 754static PyObject*
 755view_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
 766static 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
 780static 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
 826static PyObject*
 827msidb_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
 850static PyObject*
 851msidb_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
 862static PyObject*
 863msidb_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
 887static 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
 897static 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
 941static PyObject* msiopendb(PyObject *obj, PyObject *args)
 942{
 943    int status;
 944    char *path;
 945    int persist;
 946    MSIHANDLE h;
 947    msiobj *result;
 948    
 949    if (!PyArg_ParseTuple(args, "si:MSIOpenDatabase", &path, &persist))
 950	return NULL;
 951
 952	status = MsiOpenDatabase(path, (LPCSTR)persist, &h);
 953    if (status != ERROR_SUCCESS)
 954	return msierror(status);
 955
 956    result = PyObject_NEW(struct msiobj, &msidb_Type);
 957    if (!result) {
 958	MsiCloseHandle(h);
 959	return NULL;
 960    }
 961    result->h = h;
 962    return (PyObject*)result;
 963}
 964
 965static PyObject*
 966createrecord(PyObject *o, PyObject *args)
 967{
 968    int count;
 969    MSIHANDLE h;
 970
 971    if (!PyArg_ParseTuple(args, "i:CreateRecord", &count))
 972	return NULL;
 973    
 974    h = MsiCreateRecord(count);
 975    if (h == 0)
 976	return msierror(0);
 977
 978    return record_new(h);
 979}
 980
 981
 982static PyMethodDef msi_methods[] = {
 983        {"UuidCreate", (PyCFunction)uuidcreate, METH_NOARGS,
 984		PyDoc_STR("UuidCreate() -> string")},
 985	{"FCICreate",	(PyCFunction)fcicreate,	METH_VARARGS,
 986		PyDoc_STR("fcicreate(cabname,files) -> None")},
 987	{"OpenDatabase", (PyCFunction)msiopendb, METH_VARARGS,
 988	PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiOpenDatabase")},
 989	{"CreateRecord", (PyCFunction)createrecord, METH_VARARGS,
 990	PyDoc_STR("OpenDatabase(name, flags) -> dbobj\nWraps MsiCreateRecord")},
 991	{NULL,		NULL}		/* sentinel */
 992};
 993
 994static char msi_doc[] = "Documentation";
 995
 996PyMODINIT_FUNC
 997init_msi(void)
 998{
 999    PyObject *m;
1000
1001    m = Py_InitModule3("_msi", msi_methods, msi_doc);
1002    if (m == NULL)
1003	return;
1004
1005    PyModule_AddIntConstant(m, "MSIDBOPEN_CREATEDIRECT", (int)MSIDBOPEN_CREATEDIRECT);
1006    PyModule_AddIntConstant(m, "MSIDBOPEN_CREATE", (int)MSIDBOPEN_CREATE);
1007    PyModule_AddIntConstant(m, "MSIDBOPEN_DIRECT", (int)MSIDBOPEN_DIRECT);
1008    PyModule_AddIntConstant(m, "MSIDBOPEN_READONLY", (int)MSIDBOPEN_READONLY);
1009    PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT);
1010    PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE);
1011
1012    PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES);
1013    PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES);
1014
1015    PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK);
1016    PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH);
1017    PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT);
1018    PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE);
1019    PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN);
1020    PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE);
1021    PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE);
1022    PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE);
1023    PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY);
1024    PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE);
1025    PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW);
1026    PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD);
1027    PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE);
1028
1029    PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE);
1030    PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE);
1031    PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT);
1032    PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR);
1033    PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS);
1034    PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS);
1035    PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE);
1036    PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR);
1037    PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER);
1038    PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED);
1039    PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM);
1040    PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM);
1041    PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT);
1042    PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT);
1043    PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT);
1044    PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME);
1045    PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY);
1046
1047    MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL);
1048    if (!MSIError)
1049	return;
1050    PyModule_AddObject(m, "MSIError", MSIError);
1051}