https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3ec0ea99c6563fbe930a7…
commit 3ec0ea99c6563fbe930a7177928864b36e73be59
Author: winesync <ros-dev(a)reactos.org>
AuthorDate: Sat Mar 12 15:12:11 2022 +0100
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Sun Mar 20 19:27:43 2022 +0100
[WINESYNC] msi: Set the correct values for ProgramFiles64Folder and
CommonFiles64Folder.
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard(a)winehq.org>
wine commit id a6e9622439c4fd22578e737e60ca2af44a32f8b1 by Zebediah Figura
<z.figura12(a)gmail.com>
---
dll/win32/msi/package.c | 37 +++-
modules/rostests/winetests/msi/package.c | 292 ++++++++-----------------------
2 files changed, 101 insertions(+), 228 deletions(-)
diff --git a/dll/win32/msi/package.c b/dll/win32/msi/package.c
index 55789f50594..58943536b46 100644
--- a/dll/win32/msi/package.c
+++ b/dll/win32/msi/package.c
@@ -662,7 +662,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
WCHAR *ptr;
OSVERSIONINFOEXW OSVersion;
MEMORYSTATUSEX msex;
- DWORD verval, len;
+ DWORD verval, len, type;
WCHAR pth[MAX_PATH], verstr[11], bufstr[22];
HDC dc;
HKEY hkey;
@@ -708,6 +708,10 @@ static VOID set_installer_properties(MSIPACKAGE *package)
static const WCHAR szSystem64Folder[] = {
'S','y','s','t','e','m','6','4','F','o','l','d','e','r',0
};
static const WCHAR szCommonFiles64Folder[] = {
'C','o','m','m','o','n','F','i','l','e','s','6','4','F','o','l','d','e','r',0
};
static const WCHAR szProgramFiles64Folder[] = {
'P','r','o','g','r','a','m','F','i','l','e','s','6','4','F','o','l','d','e','r',0
};
+ static const WCHAR szProgramFilesDir[] =
{'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',0};
+ static const WCHAR szProgramFilesDirx86[] =
{'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r','
','(','x','8','6',')',0};
+ static const WCHAR szCommonFilesDir[] =
{'C','o','m','m','o','n','F','i','l','e','s','D','i','r',0};
+ static const WCHAR szCommonFilesDirx86[] =
{'C','o','m','m','o','n','F','i','l','e','s','D','i','r','
','(','x','8','6',')',0};
static const WCHAR szVersionNT64[] = {
'V','e','r','s','i','o','n','N','T','6','4',0
};
static const WCHAR szUserInfo[] = {
'S','O','F','T','W','A','R','E','\\',
@@ -718,6 +722,12 @@ static VOID set_installer_properties(MSIPACKAGE *package)
static const WCHAR szDefName[] = {
'D','e','f','N','a','m','e',0 };
static const WCHAR szDefCompany[] = {
'D','e','f','C','o','m','p','a','n','y',0
};
static const WCHAR szCurrentVersion[] = {
+
'S','O','F','T','W','A','R','E','\\',
+
'M','i','c','r','o','s','o','f','t','\\',
+
'W','i','n','d','o','w','s','\\',
+
'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0
+ };
+ static const WCHAR szCurrentVersionNT[] = {
'S','O','F','T','W','A','R','E','\\',
'M','i','c','r','o','s','o','f','t','\\',
'W','i','n','d','o','w','s','
','N','T','\\',
@@ -867,6 +877,9 @@ static VOID set_installer_properties(MSIPACKAGE *package)
len = sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100 );
msi_set_property( package->db, szVersionDatabase, bufstr, len );
+ RegOpenKeyExW(HKEY_LOCAL_MACHINE, szCurrentVersion, 0,
+ KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hkey);
+
GetNativeSystemInfo( &sys_info );
len = sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
msi_set_property( package->db, szIntel, bufstr, len );
@@ -876,11 +889,13 @@ static VOID set_installer_properties(MSIPACKAGE *package)
PathAddBackslashW( pth );
msi_set_property( package->db, szSystemFolder, pth, -1 );
- SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
+ len = MAX_PATH;
+ RegQueryValueExW(hkey, szProgramFilesDir, 0, &type, (BYTE *)pth, &len);
PathAddBackslashW( pth );
msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
- SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
+ len = MAX_PATH;
+ RegQueryValueExW(hkey, szCommonFilesDir, 0, &type, (BYTE *)pth, &len);
PathAddBackslashW( pth );
msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
}
@@ -898,23 +913,29 @@ static VOID set_installer_properties(MSIPACKAGE *package)
PathAddBackslashW( pth );
msi_set_property( package->db, szSystemFolder, pth, -1 );
- SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth );
+ len = MAX_PATH;
+ RegQueryValueExW(hkey, szProgramFilesDir, 0, &type, (BYTE *)pth, &len);
PathAddBackslashW( pth );
msi_set_property( package->db, szProgramFiles64Folder, pth, -1 );
- SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, pth );
+ len = MAX_PATH;
+ RegQueryValueExW(hkey, szProgramFilesDirx86, 0, &type, (BYTE *)pth,
&len);
PathAddBackslashW( pth );
msi_set_property( package->db, szProgramFilesFolder, pth, -1 );
- SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth );
+ len = MAX_PATH;
+ RegQueryValueExW(hkey, szCommonFilesDir, 0, &type, (BYTE *)pth, &len);
PathAddBackslashW( pth );
msi_set_property( package->db, szCommonFiles64Folder, pth, -1 );
- SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES_COMMONX86, NULL, 0, pth );
+ len = MAX_PATH;
+ RegQueryValueExW(hkey, szCommonFilesDirx86, 0, &type, (BYTE *)pth,
&len);
PathAddBackslashW( pth );
msi_set_property( package->db, szCommonFilesFolder, pth, -1 );
}
+ RegCloseKey(hkey);
+
/* Screen properties. */
dc = GetDC(0);
len = sprintfW( bufstr, szIntFormat, GetDeviceCaps(dc, HORZRES) );
@@ -941,7 +962,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
CloseHandle( hkey );
}
if ((!username || !companyname) &&
- RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey ) == ERROR_SUCCESS)
+ RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersionNT, &hkey ) ==
ERROR_SUCCESS)
{
if (!username &&
(username = msi_reg_get_val_str( hkey, szRegisteredUser )))
diff --git a/modules/rostests/winetests/msi/package.c
b/modules/rostests/winetests/msi/package.c
index d26e2fdb56f..09d2e0b61b8 100644
--- a/modules/rostests/winetests/msi/package.c
+++ b/modules/rostests/winetests/msi/package.c
@@ -2140,12 +2140,12 @@ static void test_condition(void)
static void check_prop(MSIHANDLE hpkg, const char *prop, const char *expect)
{
- char buffer[20] = "x";
+ char buffer[MAX_PATH] = "x";
DWORD sz = sizeof(buffer);
UINT r = MsiGetPropertyA(hpkg, prop, buffer, &sz);
ok(!r, "'%s': got %u\n", prop, r);
ok(sz == lstrlenA(buffer), "'%s': expected %u, got %u\n", prop,
lstrlenA(buffer), sz);
- ok(!strcmp(buffer, expect), "expected '%s', got '%s'\n",
expect, buffer);
+ ok(!strcmp(buffer, expect), "'%s': expected '%s', got
'%s'\n", prop, expect, buffer);
}
static void test_props(void)
@@ -5463,7 +5463,7 @@ static void test_installprops(void)
CHAR path[MAX_PATH], buf[MAX_PATH];
DWORD size, type;
LANGID langid;
- HKEY hkey1, hkey2;
+ HKEY hkey1, hkey2, pathkey;
int res;
UINT r;
REGSAM access = KEY_ALL_ACCESS;
@@ -5516,6 +5516,8 @@ static void test_installprops(void)
RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\MS Setup (ACME)\\User
Info", &hkey1);
RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows
NT\\CurrentVersion", 0, access, &hkey2);
+ RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
+ 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &pathkey);
size = MAX_PATH;
type = REG_SZ;
@@ -5616,228 +5618,78 @@ static void test_installprops(void)
r = MsiGetPropertyA(hpkg, "MsiNetAssemblySupport", buf, &size);
if (r == ERROR_SUCCESS) trace( "MsiNetAssemblySupport \"%s\"\n",
buf );
- if (pGetSystemInfo && pSHGetFolderPathA)
- {
+ if (pGetNativeSystemInfo)
+ pGetNativeSystemInfo(&si);
+ else
pGetSystemInfo(&si);
- if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
- {
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "Intel", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "MsiAMD64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "Msix64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "System64Folder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- GetSystemDirectoryA(path, MAX_PATH);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "SystemFolder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pGetSystemWow64DirectoryA(path, MAX_PATH);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "ProgramFiles64Folder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "ProgramFilesFolder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "CommonFiles64Folder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "CommonFilesFolder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES_COMMONX86, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "VersionNT64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
- }
- else if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
- {
- if (!is_wow64)
- {
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "Intel", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "MsiAMD64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "Msix64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "System64Folder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "SystemFolder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- GetSystemDirectoryA(path, MAX_PATH);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "ProgramFiles64Folder", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "ProgramFilesFolder", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "CommonFiles64Folder", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "CommonFilesFolder", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "VersionNT64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
- }
- else
- {
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "Intel", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "MsiAMD64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "Msix64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "System64Folder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- GetSystemDirectoryA(path, MAX_PATH);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "SystemFolder", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pGetSystemWow64DirectoryA(path, MAX_PATH);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "ProgramFilesFolder64", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "ProgramFilesFolder", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "CommonFilesFolder64", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(!buf[0], "property set\n");
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "CommonFilesFolder", buf,
&size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- pSHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES_COMMONX86, NULL, 0, path);
- if (size) buf[size - 1] = 0;
- ok(!lstrcmpiA(path, buf), "expected \"%s\", got
\"%s\"\n", path, buf);
-
- buf[0] = 0;
- size = MAX_PATH;
- r = MsiGetPropertyA(hpkg, "VersionNT64", buf, &size);
- ok(r == ERROR_SUCCESS, "failed to get property: %d\n", r);
- ok(buf[0], "property not set\n");
- }
- }
+
+ if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ {
+ sprintf(buf, "%d", si.wProcessorLevel);
+ check_prop(hpkg, "Intel", buf);
+ check_prop(hpkg, "MsiAMD64", buf);
+ check_prop(hpkg, "Msix64", buf);
+ sprintf(buf, "%d", LOBYTE(LOWORD(GetVersion())) * 100 +
HIBYTE(LOWORD(GetVersion())));
+ check_prop(hpkg, "VersionNT64", buf);
+
+ GetSystemDirectoryA(path, MAX_PATH);
+ strcat(path, "\\");
+ check_prop(hpkg, "System64Folder", path);
+
+ pGetSystemWow64DirectoryA(path, MAX_PATH);
+ strcat(path, "\\");
+ check_prop(hpkg, "SystemFolder", path);
+
+ size = MAX_PATH;
+ r = RegQueryValueExA(pathkey, "ProgramFilesDir (x86)", 0, &type,
(BYTE *)path, &size);
+ strcat(path, "\\");
+ check_prop(hpkg, "ProgramFilesFolder", path);
+
+ size = MAX_PATH;
+ RegQueryValueExA(pathkey, "ProgramFilesDir", 0, &type, (BYTE
*)path, &size);
+ strcat(path, "\\");
+ check_prop(hpkg, "ProgramFiles64Folder", path);
+
+ size = MAX_PATH;
+ RegQueryValueExA(pathkey, "CommonFilesDir (x86)", 0, &type, (BYTE
*)path, &size);
+ strcat(path, "\\");
+ check_prop(hpkg, "CommonFilesFolder", path);
+
+ size = MAX_PATH;
+ RegQueryValueExA(pathkey, "CommonFilesDir", 0, &type, (BYTE *)path,
&size);
+ strcat(path, "\\");
+ check_prop(hpkg, "CommonFiles64Folder", path);
+ }
+ else if (S(U(si)).wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
+ {
+ sprintf(buf, "%d", si.wProcessorLevel);
+ check_prop(hpkg, "Intel", buf);
+
+ GetSystemDirectoryA(path, MAX_PATH);
+ strcat(path, "\\");
+ check_prop(hpkg, "SystemFolder", path);
+
+ size = MAX_PATH;
+ RegQueryValueExA(pathkey, "ProgramFilesDir", 0, &type, (BYTE
*)path, &size);
+ strcat(path, "\\");
+ check_prop(hpkg, "ProgramFilesFolder", path);
+
+ size = MAX_PATH;
+ RegQueryValueExA(pathkey, "CommonFilesDir", 0, &type, (BYTE *)path,
&size);
+ strcat(path, "\\");
+ check_prop(hpkg, "CommonFilesFolder", path);
+
+ check_prop(hpkg, "MsiAMD64", "");
+ check_prop(hpkg, "Msix64", "");
+ check_prop(hpkg, "VersionNT64", "");
+ check_prop(hpkg, "System64Folder", "");
+ check_prop(hpkg, "ProgramFiles64Dir", "");
+ check_prop(hpkg, "CommonFiles64Dir", "");
}
CloseHandle(hkey1);
CloseHandle(hkey2);
+ RegCloseKey(pathkey);
MsiCloseHandle(hpkg);
DeleteFileA(msifile);
MsiSetInternalUI(uilevel, NULL);