Commit 4af750a5 authored by Damjan Jovanovic's avatar Damjan Jovanovic Committed by Alexandre Julliard

winemenubuilder: Track, update and clean up file open associations.

parent f8c48322
...@@ -1514,6 +1514,21 @@ static BOOL freedesktop_mime_type_for_extension(struct list *native_mime_types, ...@@ -1514,6 +1514,21 @@ static BOOL freedesktop_mime_type_for_extension(struct list *native_mime_types,
return ret; return ret;
} }
static CHAR* reg_get_valA(HKEY key, LPCSTR subkey, LPCSTR name)
{
DWORD size;
if (RegGetValueA(key, subkey, name, RRF_RT_REG_SZ, NULL, NULL, &size) == ERROR_SUCCESS)
{
CHAR *ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
{
if (RegGetValueA(key, subkey, name, RRF_RT_REG_SZ, NULL, ret, &size) == ERROR_SUCCESS)
return ret;
}
}
return NULL;
}
static WCHAR* reg_get_valW(HKEY key, LPCWSTR subkey, LPCWSTR name) static WCHAR* reg_get_valW(HKEY key, LPCWSTR subkey, LPCWSTR name)
{ {
DWORD size; DWORD size;
...@@ -1529,6 +1544,158 @@ static WCHAR* reg_get_valW(HKEY key, LPCWSTR subkey, LPCWSTR name) ...@@ -1529,6 +1544,158 @@ static WCHAR* reg_get_valW(HKEY key, LPCWSTR subkey, LPCWSTR name)
return NULL; return NULL;
} }
static HKEY open_associations_reg_key(void)
{
static const WCHAR Software_Wine_FileOpenAssociationsW[] = {
'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','F','i','l','e','O','p','e','n','A','s','s','o','c','i','a','t','i','o','n','s',0};
HKEY assocKey;
if (RegCreateKeyW(HKEY_CURRENT_USER, Software_Wine_FileOpenAssociationsW, &assocKey) == ERROR_SUCCESS)
return assocKey;
return NULL;
}
static BOOL has_association_changed(LPCSTR extensionA, LPCWSTR extensionW, LPCSTR mimeType, LPCWSTR progId, LPCSTR appName, LPCWSTR docName)
{
static const WCHAR ProgIDW[] = {'P','r','o','g','I','D',0};
static const WCHAR DocNameW[] = {'D','o','c','N','a','m','e',0};
HKEY assocKey;
BOOL ret;
if ((assocKey = open_associations_reg_key()))
{
CHAR *valueA;
WCHAR *value;
ret = FALSE;
valueA = reg_get_valA(assocKey, extensionA, "MimeType");
if (!valueA || lstrcmpA(valueA, mimeType))
ret = TRUE;
HeapFree(GetProcessHeap(), 0, valueA);
value = reg_get_valW(assocKey, extensionW, ProgIDW);
if (!value || strcmpW(value, progId))
ret = TRUE;
HeapFree(GetProcessHeap(), 0, value);
valueA = reg_get_valA(assocKey, extensionA, "AppName");
if (!valueA || lstrcmpA(valueA, appName))
ret = TRUE;
HeapFree(GetProcessHeap(), 0, valueA);
value = reg_get_valW(assocKey, extensionW, DocNameW);
if (docName && (!value || strcmpW(value, docName)))
ret = TRUE;
HeapFree(GetProcessHeap(), 0, value);
RegCloseKey(assocKey);
}
else
{
WINE_ERR("error opening associations registry key\n");
ret = FALSE;
}
return ret;
}
static void update_association(LPCWSTR extension, LPCSTR mimeType, LPCWSTR progId, LPCSTR appName, LPCWSTR docName, LPCSTR desktopFile)
{
static const WCHAR ProgIDW[] = {'P','r','o','g','I','D',0};
static const WCHAR DocNameW[] = {'D','o','c','N','a','m','e',0};
HKEY assocKey;
if ((assocKey = open_associations_reg_key()))
{
HKEY subkey;
if (RegCreateKeyW(assocKey, extension, &subkey) == ERROR_SUCCESS)
{
RegSetValueExA(subkey, "MimeType", 0, REG_SZ, (BYTE*) mimeType, lstrlenA(mimeType) + 1);
RegSetValueExW(subkey, ProgIDW, 0, REG_SZ, (BYTE*) progId, (lstrlenW(progId) + 1) * sizeof(WCHAR));
RegSetValueExA(subkey, "AppName", 0, REG_SZ, (BYTE*) appName, lstrlenA(appName) + 1);
if (docName)
RegSetValueExW(subkey, DocNameW, 0, REG_SZ, (BYTE*) docName, (lstrlenW(docName) + 1) * sizeof(WCHAR));
RegSetValueExA(subkey, "DesktopFile", 0, REG_SZ, (BYTE*) desktopFile, (lstrlenA(desktopFile) + 1));
RegCloseKey(subkey);
}
else
WINE_ERR("could not create extension subkey\n");
RegCloseKey(assocKey);
}
else
WINE_ERR("could not open file associations key\n");
}
static BOOL cleanup_associations(void)
{
HKEY assocKey;
BOOL hasChanged = FALSE;
if ((assocKey = open_associations_reg_key()))
{
int i;
BOOL done = FALSE;
for (i = 0; !done; i++)
{
WCHAR *extensionW = NULL;
char *extensionA = NULL;
DWORD size = 1024;
LSTATUS ret;
do
{
HeapFree(GetProcessHeap(), 0, extensionW);
extensionW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
if (extensionW == NULL)
{
WINE_ERR("out of memory\n");
ret = ERROR_OUTOFMEMORY;
break;
}
ret = RegEnumKeyExW(assocKey, i, extensionW, &size, NULL, NULL, NULL, NULL);
size *= 2;
} while (ret == ERROR_MORE_DATA);
if (ret == ERROR_SUCCESS)
{
WCHAR *command;
extensionA = wchars_to_utf8_chars(extensionW);
if (extensionA == NULL)
{
WINE_ERR("out of memory\n");
done = TRUE;
goto end;
}
command = assoc_query(ASSOCSTR_COMMAND, extensionW, NULL);
if (command == NULL)
{
char *desktopFile = reg_get_valA(assocKey, extensionA, "DesktopFile");
if (desktopFile)
{
WINE_TRACE("removing file type association for %s\n", wine_dbgstr_a(extensionA));
remove(desktopFile);
}
RegDeleteKeyW(assocKey, extensionW);
hasChanged = TRUE;
HeapFree(GetProcessHeap(), 0, desktopFile);
}
HeapFree(GetProcessHeap(), 0, command);
}
else
{
if (ret != ERROR_NO_MORE_ITEMS)
WINE_ERR("error %d while reading registry\n", ret);
done = TRUE;
}
end:
HeapFree(GetProcessHeap(), 0, extensionA);
HeapFree(GetProcessHeap(), 0, extensionW);
}
RegCloseKey(assocKey);
}
else
WINE_ERR("could not open file associations key\n");
return hasChanged;
}
static BOOL write_freedesktop_mime_type_entry(const char *packages_dir, const char *dot_extension, static BOOL write_freedesktop_mime_type_entry(const char *packages_dir, const char *dot_extension,
const char *mime_type, const char *comment) const char *mime_type, const char *comment)
{ {
...@@ -1732,6 +1899,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package ...@@ -1732,6 +1899,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
else else
goto end; /* no progID => not a file type association */ goto end; /* no progID => not a file type association */
if (has_association_changed(extensionA, extensionW, mimeTypeA, progIdW, friendlyAppNameA, friendlyDocNameW))
{ {
char *desktopPath = heap_printf("%s/wine-extension-%s.desktop", applications_dir, &extensionA[1]); char *desktopPath = heap_printf("%s/wine-extension-%s.desktop", applications_dir, &extensionA[1]);
if (desktopPath) if (desktopPath)
...@@ -1739,6 +1907,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package ...@@ -1739,6 +1907,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
if (write_freedesktop_association_entry(desktopPath, extensionA, friendlyAppNameA, mimeTypeA, progIdA)) if (write_freedesktop_association_entry(desktopPath, extensionA, friendlyAppNameA, mimeTypeA, progIdA))
{ {
hasChanged = TRUE; hasChanged = TRUE;
update_association(extensionW, mimeTypeA, progIdW, friendlyAppNameA, friendlyDocNameW, desktopPath);
} }
HeapFree(GetProcessHeap(), 0, desktopPath); HeapFree(GetProcessHeap(), 0, desktopPath);
} }
...@@ -2232,6 +2401,7 @@ static void RefreshFileTypeAssociations(void) ...@@ -2232,6 +2401,7 @@ static void RefreshFileTypeAssociations(void)
create_directories(applications_dir); create_directories(applications_dir);
hasChanged = generate_associations(xdg_data_dir, packages_dir, applications_dir); hasChanged = generate_associations(xdg_data_dir, packages_dir, applications_dir);
hasChanged |= cleanup_associations();
if (hasChanged) if (hasChanged)
{ {
char *command = heap_printf("update-mime-database %s", mime_dir); char *command = heap_printf("update-mime-database %s", mime_dir);
......
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