blob: fadc7bc9996f56ae728c8023096aae2100d4e4a6 [file] [log] [blame]
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef MsiDb_h
#define MsiDb_h
#include <windows.h>
#include <msiquery.h>
#include "MsiUtils.h"
class Guid;
namespace msi {
void closeDatabaseView(MSIHANDLE h);
class CA;
class DatabaseView;
class DatabaseRecord;
/**
* Opens product's database to query properties.
* The database is opened in R/O mode, i.e. it is safe to call this method
* even if there is active install/uninstall session. Unlike MsiOpenProduct(),
* it never fails with 1618 ('Another installation is
* already in progress') error code.
*
* Database can be opened from product code GUID, path to msi package or from
* custom action.
*
* If opened from CA the database is opened in R/W mode, however only adding
* new temporary records is supported. It is forbidden to change data in
* existing records.
*/
class Database {
public:
/**
* Opens msi database from the given product code GUID.
* Throws exception if fails.
*/
explicit Database(const Guid& productCode);
/**
* Opens msi database from the given path to .msi file.
* Throws exception if fails.
*/
explicit Database(const tstring& msiPath);
/**
* Opens msi database from the given custom action.
* Throws exception if fails.
*/
explicit Database(const CA& ca);
~Database() {
if (dbHandle != 0) {
closeMSIHANDLE(dbHandle);
}
}
/**
* Returns value of property with the given name.
* Throws NoMoreItemsError if property with the given name doesn't exist
* or Error if some error occurred.
*/
tstring getProperty(const tstring& name) const;
/**
* Returns value of property with the given name.
* Returns empty string if property with the given name doesn't exist or
* if some error occurred.
*/
tstring getProperty(const std::nothrow_t&, const tstring& name) const;
friend class DatabaseView;
private:
Database(const Database&);
Database& operator=(const Database&);
private:
const tstring msiPath;
MSIHANDLE dbHandle;
};
typedef std::unique_ptr<Database> DatabasePtr;
class DatabaseRecord {
public:
DatabaseRecord(): handle(MSIHANDLE(0)) {
}
DatabaseRecord(const DatabaseRecord& other): handle(MSIHANDLE(0)) {
handle = other.handle;
other.handle = 0;
}
DatabaseRecord& operator=(const DatabaseRecord& other);
friend class DatabaseView;
explicit DatabaseRecord(unsigned fieldCount);
explicit DatabaseRecord(DatabaseView& view) : handle(MSIHANDLE(0)) {
fetch(view);
}
~DatabaseRecord() {
if (handle != 0) {
closeMSIHANDLE(handle);
}
}
DatabaseRecord& fetch(DatabaseView& view);
DatabaseRecord& tryFetch(DatabaseView& view);
DatabaseRecord& setString(unsigned idx, const tstring& v);
DatabaseRecord& setInteger(unsigned idx, int v);
DatabaseRecord& setStreamFromFile(unsigned idx, const tstring& v);
unsigned getFieldCount() const;
tstring getString(unsigned idx) const;
int getInteger(unsigned idx) const;
void saveStreamToFile(unsigned idx, const tstring& path) const;
bool empty() const {
return 0 == handle;
}
MSIHANDLE getHandle() const {
return handle;
}
private:
mutable MSIHANDLE handle;
};
class DatabaseView {
public:
DatabaseView(const Database& db, const tstring& sqlQuery,
const DatabaseRecord& queryParam=DatabaseRecord());
~DatabaseView() {
if (handle != 0) {
closeMSIHANDLE(handle);
}
}
DatabaseRecord fetch();
DatabaseRecord tryFetch();
DatabaseView& modify(const DatabaseRecord& record, MSIMODIFY mode);
private:
tstring sqlQuery;
const Database& db;
MSIHANDLE handle;
};
} // namespace msi
#endif // #ifndef MsiDb_h