@joebigelow / wix-1 / commits / b2c46004

Port missing WiX v3 changes

Rob Mensching committed Apr 8, 2021 at 14:06 UTC b2c4600453f926fbfdc63219126930ad39601f25
7 files changed +254 -35
src/dutil/dirutil.cpp
+31
@@ -352,6 +352,37 @@ LExit:
352 }
353
354
355 +/*******************************************************************
356 +DirDeleteEmptyDirectoriesToRoot - removes an empty directory and as many
357 + of its parents as possible.
358 +
359 + Returns: count of directories deleted.
360 +*******************************************************************/
361 +extern "C" DWORD DAPI DirDeleteEmptyDirectoriesToRoot(
362 + __in_z LPCWSTR wzPath,
363 + __in DWORD /*dwFlags*/
364 + )
365 +{
366 + DWORD cDeletedDirs = 0;
367 + LPWSTR sczPath = NULL;
368 +
369 + while (wzPath && *wzPath && ::RemoveDirectoryW(wzPath))
370 + {
371 + ++cDeletedDirs;
372 +
373 + HRESULT hr = PathGetParentPath(wzPath, &sczPath);
374 + DirExitOnFailure(hr, "Failed to get parent directory for path: %ls", wzPath);
375 +
376 + wzPath = sczPath;
377 + }
378 +
379 +LExit:
380 + ReleaseStr(sczPath);
381 +
382 + return cDeletedDirs;
383 +}
384 +
385 +
386 /*******************************************************************
387 DirGetCurrent - gets the current directory.
388
src/dutil/inc/dirutil.h
+5
@@ -40,6 +40,11 @@ HRESULT DAPI DirEnsureDeleteEx(
40 __in DWORD dwFlags
41 );
42
43 +DWORD DAPI DirDeleteEmptyDirectoriesToRoot(
44 + __in_z LPCWSTR wzPath,
45 + __in DWORD dwFlags
46 + );
47 +
48 HRESULT DAPI DirGetCurrent(
49 __deref_out_z LPWSTR* psczCurrentDirectory
50 );
src/dutil/inc/locutil.h
+12
@@ -49,6 +49,18 @@ HRESULT DAPI LocProbeForFile(
49 __inout LPWSTR* psczPath
50 );
51
52 +/********************************************************************
53 + LocProbeForFileEx - Searches for a localization file on disk.
54 + useUILanguage should be set to TRUE.
55 +*******************************************************************/
56 +HRESULT DAPI LocProbeForFileEx(
57 + __in_z LPCWSTR wzBasePath,
58 + __in_z LPCWSTR wzLocFileName,
59 + __in_z_opt LPCWSTR wzLanguage,
60 + __inout LPWSTR* psczPath,
61 + __in BOOL fUseUILanguage
62 + );
63 +
64 /********************************************************************
65 LocLoadFromFile - Loads a localization file
66
src/dutil/inc/pathutil.h
+8
@@ -46,6 +46,14 @@ DAPI_(HRESULT) PathGetDirectory(
46 __out_z LPWSTR *psczDirectory
47 );
48
49 +/*******************************************************************
50 +PathGetParentPath - extracts the parent directory from a full path.
51 +********************************************************************/
52 +DAPI_(HRESULT) PathGetParentPath(
53 + __in_z LPCWSTR wzPath,
54 + __out_z LPWSTR *psczDirectory
55 + );
56 +
57 /*******************************************************************
58 PathExpand - gets the full path to a file resolving environment
59 variables along the way.
src/dutil/locutil.cpp
+20 -9
@@ -51,7 +51,7 @@ static HRESULT ParseWxlControl(
51 #ifndef MUI_MERGE_SYSTEM_FALLBACK
52 #define MUI_MERGE_SYSTEM_FALLBACK 0x10 // GetThreadPreferredUILanguages merges in parent and base languages
53 #endif
54 -typedef WINBASEAPI BOOL (WINAPI *GET_THREAD_PREFERRED_UI_LANGUAGES) (
54 +typedef WINBASEAPI BOOL (WINAPI *PFN_GET_THREAD_PREFERRED_UI_LANGUAGES) (
55 __in DWORD dwFlags,
56 __out PULONG pulNumLanguages,
57 __out_ecount_opt(*pcchLanguagesBuffer) PZZWSTR pwszLanguagesBuffer,
@@ -64,15 +64,26 @@ extern "C" HRESULT DAPI LocProbeForFile(
64 __in_z_opt LPCWSTR wzLanguage,
65 __inout LPWSTR* psczPath
66 )
67 +{
68 + return LocProbeForFileEx(wzBasePath, wzLocFileName, wzLanguage, psczPath, FALSE);
69 +}
70 +
71 +extern "C" HRESULT DAPI LocProbeForFileEx(
72 + __in_z LPCWSTR wzBasePath,
73 + __in_z LPCWSTR wzLocFileName,
74 + __in_z_opt LPCWSTR wzLanguage,
75 + __inout LPWSTR* psczPath,
76 + __in BOOL fUseUILanguage
77 + )
78 {
79 HRESULT hr = S_OK;
80 LPWSTR sczProbePath = NULL;
81 LANGID langid = 0;
82 LPWSTR sczLangIdFile = NULL;
83 LPWSTR sczLangsBuff = NULL;
73 - GET_THREAD_PREFERRED_UI_LANGUAGES pvfnGetThreadPreferredUILanguages =
74 - reinterpret_cast<GET_THREAD_PREFERRED_UI_LANGUAGES>(
75 - GetProcAddress(GetModuleHandle("Kernel32.dll"), "GetThreadPreferredUILanguages"));
84 + PFN_GET_THREAD_PREFERRED_UI_LANGUAGES pfnGetThreadPreferredUILanguages =
85 + reinterpret_cast<PFN_GET_THREAD_PREFERRED_UI_LANGUAGES>(
86 + ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "GetThreadPreferredUILanguages"));
87
88 // If a language was specified, look for a loc file in that as a directory.
89 if (wzLanguage && *wzLanguage)
@@ -89,12 +100,12 @@ extern "C" HRESULT DAPI LocProbeForFile(
100 }
101 }
102
92 - if (pvfnGetThreadPreferredUILanguages)
103 + if (fUseUILanguage && pfnGetThreadPreferredUILanguages)
104 {
94 - ULONG nLangs;
105 + ULONG nLangs = 0;
106 ULONG cchLangs = 0;
107 DWORD dwFlags = MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK | MUI_MERGE_SYSTEM_FALLBACK;
97 - if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, NULL, &cchLangs))
108 + if (!(*pfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, NULL, &cchLangs))
109 {
110 LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return buffer size.");
111 }
@@ -103,7 +114,7 @@ extern "C" HRESULT DAPI LocProbeForFile(
114 LocExitOnFailure(hr, "Failed to allocate buffer for languages");
115
116 nLangs = 0;
106 - if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, sczLangsBuff, &cchLangs))
117 + if (!(*pfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, sczLangsBuff, &cchLangs))
118 {
119 LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return language list.");
120 }
@@ -129,7 +140,7 @@ extern "C" HRESULT DAPI LocProbeForFile(
140 }
141 }
142
132 - langid = ::GetUserDefaultUILanguage();
143 + langid = fUseUILanguage ? ::GetUserDefaultUILanguage() : ::GetUserDefaultLangID();
144
145 hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
146 LocExitOnFailure(hr, "Failed to format user langid.");
src/dutil/pathutil.cpp
+33
@@ -215,6 +215,39 @@ LExit:
215 }
216
217
218 +DAPI_(HRESULT) PathGetParentPath(
219 + __in_z LPCWSTR wzPath,
220 + __out_z LPWSTR *psczParent
221 + )
222 +{
223 + HRESULT hr = S_OK;
224 + LPCWSTR wzParent = NULL;
225 +
226 + for (LPCWSTR wz = wzPath; *wz; ++wz)
227 + {
228 + if (wz[1] && (L'\\' == *wz || L'/' == *wz))
229 + {
230 + wzParent = wz;
231 + }
232 + }
233 +
234 + if (wzParent)
235 + {
236 + DWORD cchPath = static_cast<DWORD>(wzParent - wzPath) + 1;
237 +
238 + hr = StrAllocString(psczParent, wzPath, cchPath);
239 + PathExitOnFailure(hr, "Failed to copy directory.");
240 + }
241 + else
242 + {
243 + ReleaseNullStr(psczParent);
244 + }
245 +
246 +LExit:
247 + return hr;
248 +}
249 +
250 +
251 DAPI_(HRESULT) PathExpand(
252 __out LPWSTR *psczFullPath,
253 __in_z LPCWSTR wzRelativePath,
src/dutil/sqlutil.cpp
+145 -26
@@ -10,7 +10,22 @@
10 #include "sqlutil.h"
11
12
13 +//Please note that only SQL native client 11 has TLS1.2 support
14 +#define _SQLNCLI_OLEDB_DEPRECATE_WARNING
15 +
16 +#if !defined(SQLNCLI_VER)
17 +#define SQLNCLI_VER 1100
18 +#endif
19 +
20 +#if SQLNCLI_VER >= 1100
21 +#if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_)
22 +#define SQLNCLI_CLSID CLSID_SQLNCLI11
23 +#endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_)
24 +extern const GUID OLEDBDECLSPEC _SQLNCLI_OLEDB_DEPRECATE_WARNING CLSID_SQLNCLI11 = { 0x397C2819L,0x8272,0x4532,{ 0xAD,0x3A,0xFB,0x5E,0x43,0xBE,0xAA,0x39 } };
25 +#endif // SQLNCLI_VER >= 1100
26 +
27 // Exit macros
28 +#define SqlExitTrace(x, s, ...) ExitTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__)
29 #define SqlExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__)
30 #define SqlExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__)
31 #define SqlExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__)
@@ -25,11 +40,18 @@
40 #define SqlExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_SQLUTIL, g, x, s, __VA_ARGS__)
41
42 // private prototypes
43 +static HRESULT InitializeDatabaseConnection(
44 + __in REFCLSID rclsid,
45 + __in_z LPCSTR szFriendlyClsidName,
46 + __in DBPROPSET rgdbpsetInit[],
47 + __in_ecount(rgdbpsetInit) DWORD cdbpsetInit,
48 + __out IDBCreateSession** ppidbSession
49 + );
50 +HRESULT DumpErrorRecords();
51 static HRESULT FileSpecToString(
52 __in const SQL_FILESPEC* psf,
53 __out LPWSTR* ppwz
54 );
32 -
55 static HRESULT EscapeSqlIdentifier(
56 __in_z LPCWSTR wzDatabase,
57 __deref_out_z LPWSTR* ppwz
@@ -55,22 +77,11 @@ extern "C" HRESULT DAPI SqlConnectDatabase(
77 Assert(wzServer && wzDatabase && *wzDatabase && ppidbSession);
78
79 HRESULT hr = S_OK;
58 - IDBInitialize* pidbInitialize = NULL;
59 - IDBProperties* pidbProperties = NULL;
60 -
80 LPWSTR pwzServerInstance = NULL;
62 - DBPROP rgdbpInit[4];
63 - DBPROPSET rgdbpsetInit[1];
81 + DBPROP rgdbpInit[4] = { };
82 + DBPROPSET rgdbpsetInit[1] = { };
83 ULONG cProperties = 0;
84
66 - memset(rgdbpInit, 0, sizeof(rgdbpInit));
67 - memset(rgdbpsetInit, 0, sizeof(rgdbpsetInit));
68 -
69 - //obtain access to the SQLOLEDB provider
70 - hr = ::CoCreateInstance(CLSID_SQLOLEDB, NULL, CLSCTX_INPROC_SERVER,
71 - IID_IDBInitialize, (LPVOID*)&pidbInitialize);
72 - SqlExitOnFailure(hr, "failed to create IID_IDBInitialize object");
73 -
85 // if there is an instance
86 if (wzInstance && *wzInstance)
87 {
@@ -137,17 +148,23 @@ extern "C" HRESULT DAPI SqlConnectDatabase(
148 rgdbpsetInit[0].rgProperties = rgdbpInit;
149 rgdbpsetInit[0].cProperties = cProperties;
150
140 - // create and set the property set
141 - hr = pidbInitialize->QueryInterface(IID_IDBProperties, (LPVOID*)&pidbProperties);
142 - SqlExitOnFailure(hr, "failed to get IID_IDBProperties object");
143 - hr = pidbProperties->SetProperties(1, rgdbpsetInit);
144 - SqlExitOnFailure(hr, "failed to set properties");
145 -
146 - //initialize connection to datasource
147 - hr = pidbInitialize->Initialize();
148 - SqlExitOnFailure(hr, "failed to initialize connection to database: %ls", wzDatabase);
151 + // obtain access to the SQL Native Client provider
152 + hr = InitializeDatabaseConnection(SQLNCLI_CLSID, "SQL Native Client", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession);
153 + if (FAILED(hr))
154 + {
155 + SqlExitTrace(hr, "Could not initialize SQL Native Client, falling back to SQL OLE DB...");
156
150 - hr = pidbInitialize->QueryInterface(IID_IDBCreateSession, (LPVOID*)ppidbSession);
157 + // try OLE DB but if that fails return original error failure
158 + HRESULT hr2 = InitializeDatabaseConnection(CLSID_SQLOLEDB, "SQL OLE DB", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession);
159 + if (FAILED(hr2))
160 + {
161 + SqlExitTrace(hr2, "Could not initialize SQL OLE DB either, giving up.");
162 + }
163 + else
164 + {
165 + hr = S_OK;
166 + }
167 + }
168
169 LExit:
170 for (; 0 < cProperties; cProperties--)
@@ -155,8 +172,6 @@ LExit:
172 ::VariantClear(&rgdbpInit[cProperties - 1].vValue);
173 }
174
158 - ReleaseObject(pidbProperties);
159 - ReleaseObject(pidbInitialize);
175 ReleaseStr(pwzServerInstance);
176
177 return hr;
@@ -787,6 +802,110 @@ LExit:
802 // private
803 //
804
805 +static HRESULT InitializeDatabaseConnection(
806 + __in REFCLSID rclsid,
807 + __in_z LPCSTR szFriendlyClsidName,
808 + __in DBPROPSET rgdbpsetInit[],
809 + __in_ecount(rgdbpsetInit) DWORD cdbpsetInit,
810 + __out IDBCreateSession** ppidbSession
811 +)
812 +{
813 + Unused(szFriendlyClsidName); // only used in DEBUG builds
814 +
815 + HRESULT hr = S_OK;
816 + IDBInitialize* pidbInitialize = NULL;
817 + IDBProperties* pidbProperties = NULL;
818 +
819 + hr = ::CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (LPVOID*)&pidbInitialize);
820 + SqlExitOnFailure(hr, "failed to initialize %s", szFriendlyClsidName);
821 +
822 + // create and set the property set
823 + hr = pidbInitialize->QueryInterface(IID_IDBProperties, (LPVOID*)&pidbProperties);
824 + SqlExitOnFailure(hr, "failed to get IID_IDBProperties for %s", szFriendlyClsidName);
825 +
826 + hr = pidbProperties->SetProperties(cdbpsetInit, rgdbpsetInit);
827 + SqlExitOnFailure(hr, "failed to set properties for %s", szFriendlyClsidName);
828 +
829 + // initialize connection to datasource
830 + hr = pidbInitialize->Initialize();
831 + if (FAILED(hr))
832 + {
833 + DumpErrorRecords();
834 + }
835 + SqlExitOnFailure(hr, "failed to initialize connection for %s", szFriendlyClsidName);
836 +
837 + hr = pidbInitialize->QueryInterface(IID_IDBCreateSession, (LPVOID*)ppidbSession);
838 + SqlExitOnFailure(hr, "failed to query for connection session for %s", szFriendlyClsidName);
839 +
840 +LExit:
841 + ReleaseObject(pidbProperties);
842 + ReleaseObject(pidbInitialize);
843 +
844 + return hr;
845 +}
846 +
847 +HRESULT DumpErrorRecords()
848 +{
849 + HRESULT hr = S_OK;
850 + IErrorInfo* pIErrorInfo = NULL;
851 + IErrorRecords* pIErrorRecords = NULL;
852 + IErrorInfo* pIErrorInfoRecord = NULL;
853 + BSTR bstrDescription = NULL;
854 + ULONG i = 0;
855 + ULONG cRecords = 0;
856 + ERRORINFO ErrorInfo = { };
857 +
858 + // Get IErrorInfo pointer from OLE.
859 + hr = ::GetErrorInfo(0, &pIErrorInfo);
860 + if (FAILED(hr))
861 + {
862 + ExitFunction();
863 + }
864 +
865 + // QI for IID_IErrorRecords.
866 + hr = pIErrorInfo->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords);
867 + if (FAILED(hr))
868 + {
869 + ExitFunction();
870 + }
871 +
872 + // Get error record count.
873 + hr = pIErrorRecords->GetRecordCount(&cRecords);
874 + if (FAILED(hr))
875 + {
876 + ExitFunction();
877 + }
878 +
879 + // Loop through the error records.
880 + for (i = 0; i < cRecords; i++)
881 + {
882 + // Get pIErrorInfo from pIErrorRecords.
883 + hr = pIErrorRecords->GetErrorInfo(i, 1033, &pIErrorInfoRecord);
884 +
885 + if (SUCCEEDED(hr))
886 + {
887 + // Get error description and source.
888 + hr = pIErrorInfoRecord->GetDescription(&bstrDescription);
889 +
890 + // Retrieve the ErrorInfo structures.
891 + hr = pIErrorRecords->GetBasicErrorInfo(i, &ErrorInfo);
892 +
893 + SqlExitTrace(ErrorInfo.hrError, "SQL error %lu/%lu: %ls", i + 1, cRecords, bstrDescription);
894 +
895 + ReleaseNullObject(pIErrorInfoRecord);
896 + ReleaseNullBSTR(bstrDescription);
897 + }
898 + }
899 +
900 +LExit:
901 + ReleaseNullBSTR(bstrDescription);
902 + ReleaseObject(pIErrorInfoRecord);
903 + ReleaseObject(pIErrorRecords);
904 + ReleaseObject(pIErrorInfo);
905 +
906 + return hr;
907 +}
908 +
909 /********************************************************************
910 FileSpecToString
911