Search code examples
installationwindows-installerrecorddtf

Update MSI table using MSI programming API


I need to update an Attributes column in an MSI file. Unfortunately, I am unable to find any documentation (esp. for C++).

Here is a code snippet of what I am trying to do:

DatabasePtr db = /* opening db succeeds*/
ViewPtr view = db->OpenView(_bstr_t("SELECT Attributes FROM Component"));
view->Execute(NULL);
RecordPtr record=view->Fetch();

record->PutIntegerData(2, record->GetIntegerData(1)|2048);

// I do not exactly understand the next 2 lines
// Should I really call Execute before Modify?
record->Execute(record);
record->Modify(msiViewModifyUpdate, record); //throws a _com_error

As stated upon record->Modify(...) throw a _com_error stating: IDispatch error #1000? What does that mean. Where Can I look up these error codes? These are not HRESULTs...

But more important questions are how do I update the record properly? How can I iterate through all selected records? Doing a new fetch and comparing the record with NULL results in an infinite loop.

Thanks for help,
Ovanes


Solution

  • Ok, found the problem :(

    I opened the database in the read-only mode.

    Here is the snipped which works:

    InstallerPtr installer(TEXT("WindowsInstaller.Installer"));
    VARIANT open_flag;
    VariantInit(&open_flag);
    open_flag.vt = VT_I4;
    open_flag.lVal = msiOpenDatabaseModeTransact;
    
    DatabasePtr db = installer->OpenDatabase(msi_path, open_flag);
    {
      ViewPtr view = db->OpenView(_bstr_t("SELECT Attributes FROM Component"));
      view->Execute(NULL);
      RecordPtr record=view->Fetch();
    
      if(!record) ... //error handling
    
      while(record)
      {
        record->PutIntegerData(1, record->GetIntegerData(1)|2048);
    
        record->Modify(msiViewModifyUpdate, record);
        record=view->Fetch();
      }
    } //view->Close() is called implicitly
    db->Commit();
    

    Hope that helps to someone.

    Ovanes