Module: wine Branch: master Commit: 4af750a57824f2c4b93c509883120e61d7adb5e7 URL: http://source.winehq.org/git/wine.git/?a=commit;h=4af750a57824f2c4b93c509883...
Author: Damjan Jovanovic damjan.jov@gmail.com Date: Thu Jun 4 21:57:45 2009 +0200
winemenubuilder: Track, update and clean up file open associations.
---
programs/winemenubuilder/winemenubuilder.c | 170 ++++++++++++++++++++++++++++ 1 files changed, 170 insertions(+), 0 deletions(-)
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index bd9c30d..eeded0e 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -1514,6 +1514,21 @@ static BOOL freedesktop_mime_type_for_extension(struct list *native_mime_types, 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) { DWORD size; @@ -1529,6 +1544,158 @@ static WCHAR* reg_get_valW(HKEY key, LPCWSTR subkey, LPCWSTR name) 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, const char *mime_type, const char *comment) { @@ -1732,6 +1899,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package else 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]); if (desktopPath) @@ -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)) { hasChanged = TRUE; + update_association(extensionW, mimeTypeA, progIdW, friendlyAppNameA, friendlyDocNameW, desktopPath); } HeapFree(GetProcessHeap(), 0, desktopPath); } @@ -2232,6 +2401,7 @@ static void RefreshFileTypeAssociations(void) create_directories(applications_dir);
hasChanged = generate_associations(xdg_data_dir, packages_dir, applications_dir); + hasChanged |= cleanup_associations(); if (hasChanged) { char *command = heap_printf("update-mime-database %s", mime_dir);