From b2c4600453f926fbfdc63219126930ad39601f25 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 8 Apr 2021 14:06:21 -0700 Subject: Port missing WiX v3 changes --- src/dutil/dirutil.cpp | 31 +++++++++ src/dutil/inc/dirutil.h | 5 ++ src/dutil/inc/locutil.h | 12 ++++ src/dutil/inc/pathutil.h | 8 +++ src/dutil/locutil.cpp | 29 +++++--- src/dutil/pathutil.cpp | 33 +++++++++ src/dutil/sqlutil.cpp | 171 ++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 254 insertions(+), 35 deletions(-) (limited to 'src/dutil') diff --git a/src/dutil/dirutil.cpp b/src/dutil/dirutil.cpp index 81130a8d..b10e71f3 100644 --- a/src/dutil/dirutil.cpp +++ b/src/dutil/dirutil.cpp @@ -352,6 +352,37 @@ LExit: } +/******************************************************************* +DirDeleteEmptyDirectoriesToRoot - removes an empty directory and as many + of its parents as possible. + + Returns: count of directories deleted. +*******************************************************************/ +extern "C" DWORD DAPI DirDeleteEmptyDirectoriesToRoot( + __in_z LPCWSTR wzPath, + __in DWORD /*dwFlags*/ + ) +{ + DWORD cDeletedDirs = 0; + LPWSTR sczPath = NULL; + + while (wzPath && *wzPath && ::RemoveDirectoryW(wzPath)) + { + ++cDeletedDirs; + + HRESULT hr = PathGetParentPath(wzPath, &sczPath); + DirExitOnFailure(hr, "Failed to get parent directory for path: %ls", wzPath); + + wzPath = sczPath; + } + +LExit: + ReleaseStr(sczPath); + + return cDeletedDirs; +} + + /******************************************************************* DirGetCurrent - gets the current directory. diff --git a/src/dutil/inc/dirutil.h b/src/dutil/inc/dirutil.h index 0a19a9c0..539b3a73 100644 --- a/src/dutil/inc/dirutil.h +++ b/src/dutil/inc/dirutil.h @@ -40,6 +40,11 @@ HRESULT DAPI DirEnsureDeleteEx( __in DWORD dwFlags ); +DWORD DAPI DirDeleteEmptyDirectoriesToRoot( + __in_z LPCWSTR wzPath, + __in DWORD dwFlags + ); + HRESULT DAPI DirGetCurrent( __deref_out_z LPWSTR* psczCurrentDirectory ); diff --git a/src/dutil/inc/locutil.h b/src/dutil/inc/locutil.h index 38ddda20..626cb59e 100644 --- a/src/dutil/inc/locutil.h +++ b/src/dutil/inc/locutil.h @@ -49,6 +49,18 @@ HRESULT DAPI LocProbeForFile( __inout LPWSTR* psczPath ); +/******************************************************************** + LocProbeForFileEx - Searches for a localization file on disk. + useUILanguage should be set to TRUE. +*******************************************************************/ +HRESULT DAPI LocProbeForFileEx( + __in_z LPCWSTR wzBasePath, + __in_z LPCWSTR wzLocFileName, + __in_z_opt LPCWSTR wzLanguage, + __inout LPWSTR* psczPath, + __in BOOL fUseUILanguage + ); + /******************************************************************** LocLoadFromFile - Loads a localization file diff --git a/src/dutil/inc/pathutil.h b/src/dutil/inc/pathutil.h index f4f4e59c..719ee7d8 100644 --- a/src/dutil/inc/pathutil.h +++ b/src/dutil/inc/pathutil.h @@ -46,6 +46,14 @@ DAPI_(HRESULT) PathGetDirectory( __out_z LPWSTR *psczDirectory ); +/******************************************************************* +PathGetParentPath - extracts the parent directory from a full path. +********************************************************************/ +DAPI_(HRESULT) PathGetParentPath( + __in_z LPCWSTR wzPath, + __out_z LPWSTR *psczDirectory + ); + /******************************************************************* PathExpand - gets the full path to a file resolving environment variables along the way. diff --git a/src/dutil/locutil.cpp b/src/dutil/locutil.cpp index c4567c03..43e1bb5b 100644 --- a/src/dutil/locutil.cpp +++ b/src/dutil/locutil.cpp @@ -51,7 +51,7 @@ static HRESULT ParseWxlControl( #ifndef MUI_MERGE_SYSTEM_FALLBACK #define MUI_MERGE_SYSTEM_FALLBACK 0x10 // GetThreadPreferredUILanguages merges in parent and base languages #endif -typedef WINBASEAPI BOOL (WINAPI *GET_THREAD_PREFERRED_UI_LANGUAGES) ( +typedef WINBASEAPI BOOL (WINAPI *PFN_GET_THREAD_PREFERRED_UI_LANGUAGES) ( __in DWORD dwFlags, __out PULONG pulNumLanguages, __out_ecount_opt(*pcchLanguagesBuffer) PZZWSTR pwszLanguagesBuffer, @@ -64,15 +64,26 @@ extern "C" HRESULT DAPI LocProbeForFile( __in_z_opt LPCWSTR wzLanguage, __inout LPWSTR* psczPath ) +{ + return LocProbeForFileEx(wzBasePath, wzLocFileName, wzLanguage, psczPath, FALSE); +} + +extern "C" HRESULT DAPI LocProbeForFileEx( + __in_z LPCWSTR wzBasePath, + __in_z LPCWSTR wzLocFileName, + __in_z_opt LPCWSTR wzLanguage, + __inout LPWSTR* psczPath, + __in BOOL fUseUILanguage + ) { HRESULT hr = S_OK; LPWSTR sczProbePath = NULL; LANGID langid = 0; LPWSTR sczLangIdFile = NULL; LPWSTR sczLangsBuff = NULL; - GET_THREAD_PREFERRED_UI_LANGUAGES pvfnGetThreadPreferredUILanguages = - reinterpret_cast( - GetProcAddress(GetModuleHandle("Kernel32.dll"), "GetThreadPreferredUILanguages")); + PFN_GET_THREAD_PREFERRED_UI_LANGUAGES pfnGetThreadPreferredUILanguages = + reinterpret_cast( + ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "GetThreadPreferredUILanguages")); // If a language was specified, look for a loc file in that as a directory. if (wzLanguage && *wzLanguage) @@ -89,12 +100,12 @@ extern "C" HRESULT DAPI LocProbeForFile( } } - if (pvfnGetThreadPreferredUILanguages) + if (fUseUILanguage && pfnGetThreadPreferredUILanguages) { - ULONG nLangs; + ULONG nLangs = 0; ULONG cchLangs = 0; DWORD dwFlags = MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK | MUI_MERGE_SYSTEM_FALLBACK; - if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, NULL, &cchLangs)) + if (!(*pfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, NULL, &cchLangs)) { LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return buffer size."); } @@ -103,7 +114,7 @@ extern "C" HRESULT DAPI LocProbeForFile( LocExitOnFailure(hr, "Failed to allocate buffer for languages"); nLangs = 0; - if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, sczLangsBuff, &cchLangs)) + if (!(*pfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, sczLangsBuff, &cchLangs)) { LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return language list."); } @@ -129,7 +140,7 @@ extern "C" HRESULT DAPI LocProbeForFile( } } - langid = ::GetUserDefaultUILanguage(); + langid = fUseUILanguage ? ::GetUserDefaultUILanguage() : ::GetUserDefaultLangID(); hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); LocExitOnFailure(hr, "Failed to format user langid."); diff --git a/src/dutil/pathutil.cpp b/src/dutil/pathutil.cpp index ec338f71..183849ac 100644 --- a/src/dutil/pathutil.cpp +++ b/src/dutil/pathutil.cpp @@ -215,6 +215,39 @@ LExit: } +DAPI_(HRESULT) PathGetParentPath( + __in_z LPCWSTR wzPath, + __out_z LPWSTR *psczParent + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzParent = NULL; + + for (LPCWSTR wz = wzPath; *wz; ++wz) + { + if (wz[1] && (L'\\' == *wz || L'/' == *wz)) + { + wzParent = wz; + } + } + + if (wzParent) + { + DWORD cchPath = static_cast(wzParent - wzPath) + 1; + + hr = StrAllocString(psczParent, wzPath, cchPath); + PathExitOnFailure(hr, "Failed to copy directory."); + } + else + { + ReleaseNullStr(psczParent); + } + +LExit: + return hr; +} + + DAPI_(HRESULT) PathExpand( __out LPWSTR *psczFullPath, __in_z LPCWSTR wzRelativePath, diff --git a/src/dutil/sqlutil.cpp b/src/dutil/sqlutil.cpp index 63ee80ac..782c7088 100644 --- a/src/dutil/sqlutil.cpp +++ b/src/dutil/sqlutil.cpp @@ -10,7 +10,22 @@ #include "sqlutil.h" +//Please note that only SQL native client 11 has TLS1.2 support +#define _SQLNCLI_OLEDB_DEPRECATE_WARNING + +#if !defined(SQLNCLI_VER) +#define SQLNCLI_VER 1100 +#endif + +#if SQLNCLI_VER >= 1100 +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) +#define SQLNCLI_CLSID CLSID_SQLNCLI11 +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) +extern const GUID OLEDBDECLSPEC _SQLNCLI_OLEDB_DEPRECATE_WARNING CLSID_SQLNCLI11 = { 0x397C2819L,0x8272,0x4532,{ 0xAD,0x3A,0xFB,0x5E,0x43,0xBE,0xAA,0x39 } }; +#endif // SQLNCLI_VER >= 1100 + // Exit macros +#define SqlExitTrace(x, s, ...) ExitTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) #define SqlExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) #define SqlExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) #define SqlExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) @@ -25,11 +40,18 @@ #define SqlExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_SQLUTIL, g, x, s, __VA_ARGS__) // private prototypes +static HRESULT InitializeDatabaseConnection( + __in REFCLSID rclsid, + __in_z LPCSTR szFriendlyClsidName, + __in DBPROPSET rgdbpsetInit[], + __in_ecount(rgdbpsetInit) DWORD cdbpsetInit, + __out IDBCreateSession** ppidbSession + ); +HRESULT DumpErrorRecords(); static HRESULT FileSpecToString( __in const SQL_FILESPEC* psf, __out LPWSTR* ppwz ); - static HRESULT EscapeSqlIdentifier( __in_z LPCWSTR wzDatabase, __deref_out_z LPWSTR* ppwz @@ -55,22 +77,11 @@ extern "C" HRESULT DAPI SqlConnectDatabase( Assert(wzServer && wzDatabase && *wzDatabase && ppidbSession); HRESULT hr = S_OK; - IDBInitialize* pidbInitialize = NULL; - IDBProperties* pidbProperties = NULL; - LPWSTR pwzServerInstance = NULL; - DBPROP rgdbpInit[4]; - DBPROPSET rgdbpsetInit[1]; + DBPROP rgdbpInit[4] = { }; + DBPROPSET rgdbpsetInit[1] = { }; ULONG cProperties = 0; - memset(rgdbpInit, 0, sizeof(rgdbpInit)); - memset(rgdbpsetInit, 0, sizeof(rgdbpsetInit)); - - //obtain access to the SQLOLEDB provider - hr = ::CoCreateInstance(CLSID_SQLOLEDB, NULL, CLSCTX_INPROC_SERVER, - IID_IDBInitialize, (LPVOID*)&pidbInitialize); - SqlExitOnFailure(hr, "failed to create IID_IDBInitialize object"); - // if there is an instance if (wzInstance && *wzInstance) { @@ -137,17 +148,23 @@ extern "C" HRESULT DAPI SqlConnectDatabase( rgdbpsetInit[0].rgProperties = rgdbpInit; rgdbpsetInit[0].cProperties = cProperties; - // create and set the property set - hr = pidbInitialize->QueryInterface(IID_IDBProperties, (LPVOID*)&pidbProperties); - SqlExitOnFailure(hr, "failed to get IID_IDBProperties object"); - hr = pidbProperties->SetProperties(1, rgdbpsetInit); - SqlExitOnFailure(hr, "failed to set properties"); - - //initialize connection to datasource - hr = pidbInitialize->Initialize(); - SqlExitOnFailure(hr, "failed to initialize connection to database: %ls", wzDatabase); + // obtain access to the SQL Native Client provider + hr = InitializeDatabaseConnection(SQLNCLI_CLSID, "SQL Native Client", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); + if (FAILED(hr)) + { + SqlExitTrace(hr, "Could not initialize SQL Native Client, falling back to SQL OLE DB..."); - hr = pidbInitialize->QueryInterface(IID_IDBCreateSession, (LPVOID*)ppidbSession); + // try OLE DB but if that fails return original error failure + HRESULT hr2 = InitializeDatabaseConnection(CLSID_SQLOLEDB, "SQL OLE DB", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); + if (FAILED(hr2)) + { + SqlExitTrace(hr2, "Could not initialize SQL OLE DB either, giving up."); + } + else + { + hr = S_OK; + } + } LExit: for (; 0 < cProperties; cProperties--) @@ -155,8 +172,6 @@ LExit: ::VariantClear(&rgdbpInit[cProperties - 1].vValue); } - ReleaseObject(pidbProperties); - ReleaseObject(pidbInitialize); ReleaseStr(pwzServerInstance); return hr; @@ -787,6 +802,110 @@ LExit: // private // +static HRESULT InitializeDatabaseConnection( + __in REFCLSID rclsid, + __in_z LPCSTR szFriendlyClsidName, + __in DBPROPSET rgdbpsetInit[], + __in_ecount(rgdbpsetInit) DWORD cdbpsetInit, + __out IDBCreateSession** ppidbSession +) +{ + Unused(szFriendlyClsidName); // only used in DEBUG builds + + HRESULT hr = S_OK; + IDBInitialize* pidbInitialize = NULL; + IDBProperties* pidbProperties = NULL; + + hr = ::CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (LPVOID*)&pidbInitialize); + SqlExitOnFailure(hr, "failed to initialize %s", szFriendlyClsidName); + + // create and set the property set + hr = pidbInitialize->QueryInterface(IID_IDBProperties, (LPVOID*)&pidbProperties); + SqlExitOnFailure(hr, "failed to get IID_IDBProperties for %s", szFriendlyClsidName); + + hr = pidbProperties->SetProperties(cdbpsetInit, rgdbpsetInit); + SqlExitOnFailure(hr, "failed to set properties for %s", szFriendlyClsidName); + + // initialize connection to datasource + hr = pidbInitialize->Initialize(); + if (FAILED(hr)) + { + DumpErrorRecords(); + } + SqlExitOnFailure(hr, "failed to initialize connection for %s", szFriendlyClsidName); + + hr = pidbInitialize->QueryInterface(IID_IDBCreateSession, (LPVOID*)ppidbSession); + SqlExitOnFailure(hr, "failed to query for connection session for %s", szFriendlyClsidName); + +LExit: + ReleaseObject(pidbProperties); + ReleaseObject(pidbInitialize); + + return hr; +} + +HRESULT DumpErrorRecords() +{ + HRESULT hr = S_OK; + IErrorInfo* pIErrorInfo = NULL; + IErrorRecords* pIErrorRecords = NULL; + IErrorInfo* pIErrorInfoRecord = NULL; + BSTR bstrDescription = NULL; + ULONG i = 0; + ULONG cRecords = 0; + ERRORINFO ErrorInfo = { }; + + // Get IErrorInfo pointer from OLE. + hr = ::GetErrorInfo(0, &pIErrorInfo); + if (FAILED(hr)) + { + ExitFunction(); + } + + // QI for IID_IErrorRecords. + hr = pIErrorInfo->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords); + if (FAILED(hr)) + { + ExitFunction(); + } + + // Get error record count. + hr = pIErrorRecords->GetRecordCount(&cRecords); + if (FAILED(hr)) + { + ExitFunction(); + } + + // Loop through the error records. + for (i = 0; i < cRecords; i++) + { + // Get pIErrorInfo from pIErrorRecords. + hr = pIErrorRecords->GetErrorInfo(i, 1033, &pIErrorInfoRecord); + + if (SUCCEEDED(hr)) + { + // Get error description and source. + hr = pIErrorInfoRecord->GetDescription(&bstrDescription); + + // Retrieve the ErrorInfo structures. + hr = pIErrorRecords->GetBasicErrorInfo(i, &ErrorInfo); + + SqlExitTrace(ErrorInfo.hrError, "SQL error %lu/%lu: %ls", i + 1, cRecords, bstrDescription); + + ReleaseNullObject(pIErrorInfoRecord); + ReleaseNullBSTR(bstrDescription); + } + } + +LExit: + ReleaseNullBSTR(bstrDescription); + ReleaseObject(pIErrorInfoRecord); + ReleaseObject(pIErrorRecords); + ReleaseObject(pIErrorInfo); + + return hr; +} + /******************************************************************** FileSpecToString -- cgit v1.2.3-55-g6feb