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