// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. #include "precomp.h" /******************************************************************** * CreateDatabase - CUSTOM ACTION ENTRY POINT for creating databases * * Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword * ****************************************************************/ extern "C" UINT __stdcall CreateDatabase(MSIHANDLE hInstall) { //AssertSz(FALSE, "debug CreateDatabase here"); UINT er = ERROR_SUCCESS; HRESULT hr = S_OK; LPWSTR pwzData = NULL; IDBCreateSession* pidbSession = NULL; BSTR bstrErrorDescription = NULL; LPWSTR pwz = NULL; LPWSTR pwzDatabaseKey = NULL; LPWSTR pwzServer = NULL; LPWSTR pwzInstance = NULL; LPWSTR pwzDatabase = NULL; LPWSTR pwzTemp = NULL; int iAttributes; BOOL fIntegratedAuth; LPWSTR pwzUser = NULL; LPWSTR pwzPassword = NULL; BOOL fHaveDbFileSpec = FALSE; SQL_FILESPEC sfDb; BOOL fHaveLogFileSpec = FALSE; SQL_FILESPEC sfLog; BOOL fInitializedCom = FALSE; memset(&sfDb, 0, sizeof(sfDb)); memset(&sfLog, 0, sizeof(sfLog)); hr = WcaInitialize(hInstall, "CreateDatabase"); ExitOnFailure(hr, "failed to initialize"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to intialize COM"); fInitializedCom = TRUE; hr = WcaGetProperty( L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); pwz = pwzData; hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); // SQL Server ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz); hr = WcaReadStringFromCaData(&pwz, &pwzServer); // SQL Server ExitOnFailure(hr, "failed to read server from custom action data: %ls", pwz); hr = WcaReadStringFromCaData(&pwz, &pwzInstance); // SQL Server Instance ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz); hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); // SQL Database ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz); hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); ExitOnFailure(hr, "failed to read attributes from custom action data: %ls", pwz); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); // Integrated Windows Authentication? ExitOnFailure(hr, "failed to read integrated auth flag from custom action data: %ls", pwz); hr = WcaReadStringFromCaData(&pwz, &pwzUser); // SQL User ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz); hr = WcaReadStringFromCaData(&pwz, &pwzPassword); // SQL User Password ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz); // db file spec hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fHaveDbFileSpec)); ExitOnFailure(hr, "failed to read db file spec from custom action data: %ls", pwz); if (fHaveDbFileSpec) { hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read db file spec name from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfDb.wzName, countof(sfDb.wzName), pwzTemp); ExitOnFailure(hr, "failed to copy db file spec name: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read db file spec filename from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfDb.wzFilename, countof(sfDb.wzFilename), pwzTemp); ExitOnFailure(hr, "failed to copy db file spec filename: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read db file spec size from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfDb.wzSize, countof(sfDb.wzSize), pwzTemp); ExitOnFailure(hr, "failed to copy db file spec size value: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read db file spec max size from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfDb.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp); ExitOnFailure(hr, "failed to copy db file spec max size: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read db file spec grow from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfDb.wzGrow, countof(sfDb.wzGrow), pwzTemp); ExitOnFailure(hr, "failed to copy db file spec grow value: %ls", pwzTemp); } // log file spec hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fHaveLogFileSpec)); ExitOnFailure(hr, "failed to read log file spec from custom action data: %ls", pwz); if (fHaveLogFileSpec) { hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read log file spec name from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfLog.wzName, countof(sfDb.wzName), pwzTemp); ExitOnFailure(hr, "failed to copy log file spec name: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read log file spec filename from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfLog.wzFilename, countof(sfDb.wzFilename), pwzTemp); ExitOnFailure(hr, "failed to copy log file spec filename: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read log file spec size from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfLog.wzSize, countof(sfDb.wzSize), pwzTemp); ExitOnFailure(hr, "failed to copy log file spec size value: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read log file spec max size from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfLog.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp); ExitOnFailure(hr, "failed to copy log file spec max size: %ls", pwzTemp); hr = WcaReadStringFromCaData(&pwz, &pwzTemp); ExitOnFailure(hr, "failed to read log file spec grow from custom action data: %ls", pwz); hr = ::StringCchCopyW(sfLog.wzGrow, countof(sfDb.wzGrow), pwzTemp); ExitOnFailure(hr, "failed to copy log file spec grow value: %ls", pwzTemp); } if (iAttributes & SCADB_CONFIRM_OVERWRITE) { // Check if the database already exists hr = SqlDatabaseExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription); MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to check if database exists: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); if (S_OK == hr) // found an existing database, confirm that they don't want to stop before it gets trampled, in no UI case just continue anyways { hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); if (IDNO == WcaErrorMessage(msierrSQLDatabaseAlreadyExists, hr, MB_YESNO, 1, pwzDatabase)) ExitOnFailure(hr, "failed to initialize"); } } hr = SqlDatabaseEnsureExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, fHaveDbFileSpec ? &sfDb : NULL, fHaveLogFileSpec ? &sfLog : NULL, &bstrErrorDescription); if ((iAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to create SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase); hr = S_OK; } MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to create to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE); LExit: ReleaseStr(pwzDatabaseKey); ReleaseStr(pwzServer); ReleaseStr(pwzInstance); ReleaseStr(pwzDatabase); ReleaseStr(pwzUser); ReleaseStr(pwzPassword); ReleaseObject(pidbSession); ReleaseBSTR(bstrErrorDescription); if (fInitializedCom) { ::CoUninitialize(); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); } /******************************************************************** DropDatabase - CUSTOM ACTION ENTRY POINT for removing databases Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword * ****************************************************************/ extern "C" UINT __stdcall DropDatabase(MSIHANDLE hInstall) { //Assert(FALSE); UINT er = ERROR_SUCCESS; HRESULT hr = S_OK; LPWSTR pwzData = NULL; IDBCreateSession* pidbSession = NULL; BSTR bstrErrorDescription = NULL; LPWSTR pwz = NULL; LPWSTR pwzDatabaseKey = NULL; LPWSTR pwzServer = NULL; LPWSTR pwzInstance = NULL; LPWSTR pwzDatabase = NULL; long lAttributes; BOOL fIntegratedAuth; LPWSTR pwzUser = NULL; LPWSTR pwzPassword = NULL; BOOL fInitializedCom = TRUE; hr = WcaInitialize(hInstall, "DropDatabase"); ExitOnFailure(hr, "failed to initialize"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to intialize COM"); fInitializedCom = TRUE; hr = WcaGetProperty( L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); pwz = pwzData; hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); ExitOnFailure(hr, "failed to read database key"); hr = WcaReadStringFromCaData(&pwz, &pwzServer); ExitOnFailure(hr, "failed to read server"); hr = WcaReadStringFromCaData(&pwz, &pwzInstance); ExitOnFailure(hr, "failed to read instance"); hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); ExitOnFailure(hr, "failed to read database"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&lAttributes)); ExitOnFailure(hr, "failed to read attributes"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); // Integrated Windows Authentication? ExitOnFailure(hr, "failed to read integrated auth flag"); hr = WcaReadStringFromCaData(&pwz, &pwzUser); ExitOnFailure(hr, "failed to read user"); hr = WcaReadStringFromCaData(&pwz, &pwzPassword); ExitOnFailure(hr, "failed to read password"); hr = SqlDropDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription); if ((lAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to drop SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase); hr = S_OK; } MessageExitOnFailure(hr, msierrSQLFailedDropDatabase, "failed to drop to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE); LExit: ReleaseStr(pwzDatabaseKey); ReleaseStr(pwzServer); ReleaseStr(pwzInstance); ReleaseStr(pwzDatabase); ReleaseStr(pwzUser); ReleaseStr(pwzPassword); ReleaseStr(pwzData); ReleaseObject(pidbSession); ReleaseBSTR(bstrErrorDescription); if (fInitializedCom) { ::CoUninitialize(); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); } /******************************************************************** ExecuteSqlStrings - CUSTOM ACTION ENTRY POINT for running SQL strings Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword\tSQLKey1\tSQLString1\tSQLKey2\tSQLString2\tSQLKey3\tSQLString3\t... rollback CustomActionData - same as above * ****************************************************************/ extern "C" UINT __stdcall ExecuteSqlStrings(MSIHANDLE hInstall) { //Assert(FALSE); UINT er = ERROR_SUCCESS; HRESULT hr = S_OK; HRESULT hrDB = S_OK; LPWSTR pwzData = NULL; IDBCreateSession* pidbSession = NULL; BSTR bstrErrorDescription = NULL; LPWSTR pwz = NULL; LPWSTR pwzDatabaseKey = NULL; LPWSTR pwzServer = NULL; LPWSTR pwzInstance = NULL; LPWSTR pwzDatabase = NULL; int iAttributesDB; int iAttributesSQL; BOOL fIntegratedAuth; LPWSTR pwzUser = NULL; LPWSTR pwzPassword = NULL; LPWSTR pwzSqlKey = NULL; LPWSTR pwzSql = NULL; BOOL fInitializedCom = FALSE; hr = WcaInitialize(hInstall, "ExecuteSqlStrings"); ExitOnFailure(hr, "failed to initialize"); hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to intialize COM"); fInitializedCom = TRUE; hr = WcaGetProperty( L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); pwz = pwzData; hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); ExitOnFailure(hr, "failed to read database key"); hr = WcaReadStringFromCaData(&pwz, &pwzServer); ExitOnFailure(hr, "failed to read server"); hr = WcaReadStringFromCaData(&pwz, &pwzInstance); ExitOnFailure(hr, "failed to read instance"); hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); ExitOnFailure(hr, "failed to read database"); hr = WcaReadIntegerFromCaData(&pwz, &iAttributesDB); ExitOnFailure(hr, "failed to read attributes"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast(&fIntegratedAuth)); // Integrated Windows Authentication? ExitOnFailure(hr, "failed to read integrated auth flag"); hr = WcaReadStringFromCaData(&pwz, &pwzUser); ExitOnFailure(hr, "failed to read user"); hr = WcaReadStringFromCaData(&pwz, &pwzPassword); ExitOnFailure(hr, "failed to read password"); // Store off the result of the connect, only exit if we don't care if the database connection succeeds // Wait to fail until later to see if we actually have work to do that is not set to continue on error hrDB = SqlConnectDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &pidbSession); if ((iAttributesDB & SCADB_CONTINUE_ON_ERROR) && FAILED(hrDB)) { WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase); ExitFunction1(hr = S_OK); } while (S_OK == hr && S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzSqlKey))) { hr = WcaReadIntegerFromCaData(&pwz, &iAttributesSQL); ExitOnFailure(hr, "failed to read attributes for SQL string: %ls", pwzSqlKey); hr = WcaReadStringFromCaData(&pwz, &pwzSql); ExitOnFailure(hr, "failed to read SQL string for key: %ls", pwzSqlKey); // If the Wix4SqlString row is set to continue on error and the DB connection failed, skip attempting to execute if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hrDB)) { WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase); continue; } // Now check if the DB connection succeeded MessageExitOnFailure(hr = hrDB, msierrSQLFailedConnectDatabase, "failed to connect to database: '%ls'", pwzDatabase); WcaLog(LOGMSG_VERBOSE, "Executing SQL string: %ls", pwzSql); hr = SqlSessionExecuteQuery(pidbSession, pwzSql, NULL, NULL, &bstrErrorDescription); if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to execute SQL string but continuing, error: %ls, SQL key: %ls SQL string: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql); hr = S_OK; } MessageExitOnFailure(hr, msierrSQLFailedExecString, "failed to execute SQL string, error: %ls, SQL key: %ls SQL string: %ls", NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql); WcaProgressMessage(COST_SQL_STRING, FALSE); } if (E_NOMOREITEMS == hr) { hr = S_OK; } LExit: ReleaseStr(pwzDatabaseKey); ReleaseStr(pwzServer); ReleaseStr(pwzInstance); ReleaseStr(pwzDatabase); ReleaseStr(pwzUser); ReleaseStr(pwzPassword); ReleaseStr(pwzData); ReleaseBSTR(bstrErrorDescription); ReleaseObject(pidbSession); if (fInitializedCom) { ::CoUninitialize(); } if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }