Commit 3d5b3ef9 authored by James Hawkins's avatar James Hawkins Committed by Alexandre Julliard

msi: Reimplement MsiSourceListAddSourceEx to handle reordering the source list.

parent d9a8f0b5
...@@ -46,9 +46,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); ...@@ -46,9 +46,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tagMediaInfo typedef struct tagMediaInfo
{ {
struct list entry;
LPWSTR path; LPWSTR path;
WCHAR szIndex[10]; WCHAR szIndex[10];
WCHAR type; DWORD index;
} media_info; } media_info;
static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions, BOOL user, BOOL create) static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, DWORD dwOptions, BOOL user, BOOL create)
...@@ -131,43 +132,6 @@ static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create) ...@@ -131,43 +132,6 @@ static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
return rc; return rc;
} }
static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
{
DWORD index = 0;
WCHAR szIndex[10];
DWORD size;
DWORD val_size;
LPWSTR val;
UINT rc = ERROR_SUCCESS;
while (rc == ERROR_SUCCESS)
{
val = NULL;
val_size = 0;
size = sizeof(szIndex)/sizeof(szIndex[0]);
rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
if (rc != ERROR_NO_MORE_ITEMS)
{
val = msi_alloc(val_size);
RegEnumValueW(key, index, szIndex, &size, NULL, NULL, (LPBYTE)val,
&val_size);
if (lstrcmpiW(szSource,val)==0)
{
ss->path = val;
strcpyW(ss->szIndex,szIndex);
break;
}
else
strcpyW(ss->szIndex,szIndex);
msi_free(val);
index ++;
}
}
return rc;
}
/****************************************************************** /******************************************************************
* MsiSourceListEnumSourcesA (MSI.@) * MsiSourceListEnumSourcesA (MSI.@)
*/ */
...@@ -578,6 +542,90 @@ UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid, ...@@ -578,6 +542,90 @@ UINT WINAPI MsiSourceListAddSourceExA(LPCSTR szProduct, LPCSTR szUserSid,
return ret; return ret;
} }
static void free_source_list(struct list *sourcelist)
{
while (!list_empty(sourcelist))
{
media_info *info = LIST_ENTRY(list_head(sourcelist), media_info, entry);
list_remove(&info->entry);
msi_free(info->path);
msi_free(info);
}
}
static void add_source_to_list(struct list *sourcelist, media_info *info)
{
media_info *iter;
BOOL found = FALSE;
static const WCHAR fmt[] = {'%','i',0};
if (list_empty(sourcelist))
{
list_add_head(sourcelist, &info->entry);
return;
}
LIST_FOR_EACH_ENTRY(iter, sourcelist, media_info, entry)
{
if (!found && info->index < iter->index)
{
found = TRUE;
list_add_before(&iter->entry, &info->entry);
}
/* update the rest of the list */
if (found)
sprintfW(iter->szIndex, fmt, ++iter->index);
}
if (!found)
list_add_after(&iter->entry, &info->entry);
}
static UINT fill_source_list(struct list *sourcelist, HKEY sourcekey, DWORD *count)
{
UINT r = ERROR_SUCCESS;
DWORD index = 0;
WCHAR name[10];
DWORD size, val_size;
media_info *entry;
*count = 0;
while (r == ERROR_SUCCESS)
{
size = sizeof(name) / sizeof(name[0]);
r = RegEnumValueW(sourcekey, index, name, &size, NULL, NULL, NULL, &val_size);
if (r != ERROR_SUCCESS)
return r;
entry = msi_alloc(sizeof(media_info));
if (!entry)
goto error;
entry->path = msi_alloc(val_size);
if (!entry->path)
goto error;
lstrcpyW(entry->szIndex, name);
entry->index = atoiW(name);
size++;
r = RegEnumValueW(sourcekey, index, name, &size, NULL,
NULL, (LPBYTE)entry->path, &val_size);
if (r != ERROR_SUCCESS)
goto error;
index = ++(*count);
add_source_to_list(sourcelist, entry);
}
error:
*count = -1;
free_source_list(sourcelist);
return ERROR_OUTOFMEMORY;
}
/****************************************************************** /******************************************************************
* MsiSourceListAddSourceExW (MSI.@) * MsiSourceListAddSourceExW (MSI.@)
*/ */
...@@ -588,12 +636,16 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, ...@@ -588,12 +636,16 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
HKEY sourcekey; HKEY sourcekey;
HKEY typekey; HKEY typekey;
UINT rc; UINT rc;
media_info source_struct; struct list sourcelist;
media_info *info;
WCHAR squished_pc[GUID_SIZE]; WCHAR squished_pc[GUID_SIZE];
WCHAR name[10];
LPWSTR source; LPWSTR source;
LPCWSTR postfix; LPCWSTR postfix;
DWORD size; DWORD size, count;
static const WCHAR fmt[] = {'%','i',0};
static const WCHAR one[] = {'1',0};
static const WCHAR backslash[] = {'\\',0}; static const WCHAR backslash[] = {'\\',0};
static const WCHAR forwardslash[] = {'/',0}; static const WCHAR forwardslash[] = {'/',0};
...@@ -653,33 +705,55 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid, ...@@ -653,33 +705,55 @@ UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
lstrcatW(source, postfix); lstrcatW(source, postfix);
} }
source_struct.szIndex[0] = 0; list_init(&sourcelist);
if (find_given_source(typekey, source, &source_struct) == ERROR_SUCCESS) rc = fill_source_list(&sourcelist, typekey, &count);
if (rc != ERROR_NO_MORE_ITEMS)
return rc;
size = (lstrlenW(source) + 1) * sizeof(WCHAR);
if (count == 0)
{
rc = RegSetValueExW(typekey, one, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
goto done;
}
else if (dwIndex > count)
{ {
DWORD current_index = atoiW(source_struct.szIndex); sprintfW(name, fmt, count + 1);
/* found the source */ rc = RegSetValueExW(typekey, name, 0, REG_EXPAND_SZ, (LPBYTE)source, size);
if (dwIndex > 0 && current_index != dwIndex) goto done;
FIXME("Need to reorder the sources!\n");
msi_free( source_struct.path );
} }
else else
{ {
DWORD current_index = 0; /* add to the end of the list */
static const WCHAR fmt[] = {'%','i',0}; if (dwIndex == 0)
DWORD size = lstrlenW(source) * sizeof(WCHAR); dwIndex = count + 1;
if (source_struct.szIndex[0]) sprintfW(name, fmt, dwIndex);
current_index = atoiW(source_struct.szIndex); info = msi_alloc(sizeof(media_info));
/* new source */ if (!info)
if (dwIndex > 0 && dwIndex < current_index) {
FIXME("Need to reorder the sources!\n"); rc = ERROR_OUTOFMEMORY;
goto done;
current_index ++; }
sprintfW(source_struct.szIndex,fmt,current_index);
rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ, info->path = strdupW(source);
(const BYTE *)source, size); lstrcpyW(info->szIndex, name);
info->index = dwIndex;
add_source_to_list(&sourcelist, info);
LIST_FOR_EACH_ENTRY(info, &sourcelist, media_info, entry)
{
size = (lstrlenW(info->path) + 1) * sizeof(WCHAR);
rc = RegSetValueExW(typekey, info->szIndex, 0,
REG_EXPAND_SZ, (LPBYTE)info->path, size);
if (rc != ERROR_SUCCESS)
goto done;
}
} }
done:
free_source_list(&sourcelist);
msi_free(source); msi_free(source);
RegCloseKey(typekey); RegCloseKey(typekey);
RegCloseKey(sourcekey); RegCloseKey(sourcekey);
......
...@@ -449,29 +449,20 @@ static void test_MsiSourceListAddSourceEx(void) ...@@ -449,29 +449,20 @@ static void test_MsiSourceListAddSourceEx(void)
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
{ ok(size == 7, "Expected 7, got %d\n", size);
ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
ok(size == 7, "Expected 7, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
{ ok(size == 11, "Expected 11, got %d\n", size);
ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
ok(size == 11, "Expected 11, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
{ ok(size == 9, "Expected 9, got %d\n", size);
ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
ok(size == 9, "Expected 9, got %d\n", size);
}
/* add another source, index > N */ /* add another source, index > N */
r = pMsiSourceListAddSourceExA(prodcode, usersid, r = pMsiSourceListAddSourceExA(prodcode, usersid,
...@@ -482,29 +473,20 @@ static void test_MsiSourceListAddSourceEx(void) ...@@ -482,29 +473,20 @@ static void test_MsiSourceListAddSourceEx(void)
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
{ ok(size == 7, "Expected 7, got %d\n", size);
ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
ok(size == 7, "Expected 7, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
{ ok(size == 11, "Expected 11, got %d\n", size);
ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
ok(size == 11, "Expected 11, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
{ ok(size == 9, "Expected 9, got %d\n", size);
ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
ok(size == 9, "Expected 9, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size);
...@@ -536,29 +518,20 @@ static void test_MsiSourceListAddSourceEx(void) ...@@ -536,29 +518,20 @@ static void test_MsiSourceListAddSourceEx(void)
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "1", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
{ ok(size == 7, "Expected 7, got %d\n", size);
ok(!lstrcmpA(value, "third/"), "Expected 'third/', got %s\n", value);
ok(size == 7, "Expected 7, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "2", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
{ ok(size == 11, "Expected 11, got %d\n", size);
ok(!lstrcmpA(value, "C:\\source/"), "Expected 'C:\\source/', got %s\n", value);
ok(size == 11, "Expected 11, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "3", NULL, NULL, (LPBYTE)value, &size);
ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
todo_wine ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
{ ok(size == 9, "Expected 9, got %d\n", size);
ok(!lstrcmpA(value, "another/"), "Expected 'another/', got %s\n", value);
ok(size == 9, "Expected 9, got %d\n", size);
}
size = MAX_PATH; size = MAX_PATH;
res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size); res = RegQueryValueExA(url, "4", NULL, NULL, (LPBYTE)value, &size);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment