[PATCH v2 14/15] msi: Write shortcut properties
Jonas Kümmerlin
rgcjonas at gmail.com
Sat Jul 18 11:26:53 CDT 2015
Msi now evaluates the MsiShortcutProperty table and applies the properties
to the created shortcuts.
---
dlls/msi/Makefile.in | 2 +-
dlls/msi/action.c | 120 ++++++++++++++++++++++++++++++++++++++++++++
dlls/msi/tests/Makefile.in | 2 +-
dlls/msi/tests/action.c | 75 +++++++++++++++++++++++++--
dlls/msi/tests/automation.c | 1 -
5 files changed, 194 insertions(+), 6 deletions(-)
diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in
index 79704ad..8df4b26 100644
--- a/dlls/msi/Makefile.in
+++ b/dlls/msi/Makefile.in
@@ -1,7 +1,7 @@
MODULE = msi.dll
IMPORTLIB = msi
IMPORTS = uuid urlmon wininet comctl32 shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32
-DELAYIMPORTS = odbccp32 wintrust crypt32 imagehlp mspatcha
+DELAYIMPORTS = odbccp32 wintrust crypt32 imagehlp mspatcha propsys
C_SRCS = \
action.c \
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index c0ab23d..88f0c34 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -39,6 +39,7 @@
#include "imagehlp.h"
#include "wine/unicode.h"
#include "winver.h"
+#include "propvarutil.h"
#define REG_PROGRESS_VALUE 13200
#define COMPONENT_PROGRESS_VALUE 24000
@@ -3888,6 +3889,122 @@ WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
return path;
}
+struct AddShortcutProperties_closure
+{
+ MSIPACKAGE *package;
+ IShellLinkW *link;
+};
+static UINT ITERATE_AddShortcutProperties(MSIRECORD *row, LPVOID param)
+{
+ struct AddShortcutProperties_closure *closure = param;
+ IShellLinkW *link = closure->link;
+ MSIPACKAGE *package = closure->package;
+ IPropertyStore *store = NULL;
+ IPropertyDescription *desc = NULL;
+ WCHAR *name = NULL, *value = NULL;
+ PROPVARIANT v;
+ PROPERTYKEY key;
+ HRESULT hr;
+
+ PropVariantInit(&v);
+
+ hr = IShellLinkW_QueryInterface(link, &IID_IPropertyStore, (void**)&store);
+ if (FAILED(hr))
+ {
+ ERR("QueryInterface(IID_IPropertyStore): %x\n", hr);
+ return ERROR_SUCCESS;
+ }
+
+ deformat_string(package, MSI_RecordGetString(row, 3), &name);
+ deformat_string(package, MSI_RecordGetString(row, 4), &value);
+
+ hr = PSGetPropertyDescriptionByName(name, &IID_IPropertyDescription, (void**)&desc);
+ if (FAILED(hr))
+ {
+ WARN("Unknown property %s, ignoring\n", debugstr_w(name));
+ goto out;
+ }
+
+ hr = InitPropVariantFromString(value, &v);
+ if (FAILED(hr))
+ {
+ ERR("InitPropVariantFromString hr=%x\n", hr);
+ goto out;
+ }
+
+ hr = IPropertyDescription_GetPropertyKey(desc, &key);
+ if (FAILED(hr))
+ {
+ ERR("IPropertyDescription::GetPropertyKey hr=%x\n", hr);
+ goto out;
+ }
+
+ hr = IPropertyDescription_CoerceToCanonicalValue(desc, &v);
+ if (FAILED(hr))
+ {
+ ERR("IPropertyDescription::CoerceToCanonicalValue hr=%x\n", hr);
+ goto out;
+ }
+
+ hr = IPropertyStore_SetValue(store, &key, &v);
+ if (FAILED(hr))
+ {
+ ERR("IPropertyStore::SetValue hr=%x\n", hr);
+ }
+
+out:
+ PropVariantClear(&v);
+ if (store) IPropertyStore_Release(store);
+ if (desc) IPropertyDescription_Release(desc);
+
+ msi_free(name);
+ msi_free(value);
+
+ return ERROR_SUCCESS; /* fake it if necessary */
+}
+
+static UINT AddShortcutProperties(MSIPACKAGE *package, const WCHAR *shortcut, IShellLinkW *link)
+{
+ static const WCHAR queryTemplate[] = {
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','M','s','i','S','h','o','r','t','c','u','t','P','r','o','p','e','r','t','y','`',' ',
+ 'W','H','E','R','E',' ','`','S','h','o','r','t','c','u','t','_','`',
+ ' ','=',' ','\'','%','s','\'', 0};
+ WCHAR *query;
+ MSIQUERY *view;
+ HRESULT res;
+ UINT rc;
+ struct AddShortcutProperties_closure closure = {
+ package, link
+ };
+
+ query = msi_alloc(sizeof(queryTemplate) + lstrlenW(shortcut)*sizeof(WCHAR));
+ if (!query)
+ {
+ ERR("No memory while querying shortcut properties\n");
+ return ERROR_SUCCESS; /* fake it */
+ }
+
+ sprintfW(query, queryTemplate, shortcut);
+
+ rc = MSI_DatabaseOpenViewW(package->db, query, &view);
+ if (rc != ERROR_SUCCESS)
+ {
+ msi_free(query);
+ return ERROR_SUCCESS;
+ }
+
+ res = CoInitialize( NULL );
+
+ rc = MSI_IterateRecords(view, NULL, ITERATE_AddShortcutProperties, &closure);
+ msiobj_release(&view->hdr);
+
+ if (SUCCEEDED(res)) CoUninitialize();
+
+ msi_free(query);
+ return rc;
+}
+
static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = param;
@@ -3985,6 +4102,9 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
full_path = msi_get_target_folder( package, wkdir );
if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
}
+
+ AddShortcutProperties(package, MSI_RecordGetString(row, 1), sl);
+
link_file = get_link_file(package, row);
TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
diff --git a/dlls/msi/tests/Makefile.in b/dlls/msi/tests/Makefile.in
index 66f8abb..6ea5f9a 100644
--- a/dlls/msi/tests/Makefile.in
+++ b/dlls/msi/tests/Makefile.in
@@ -1,5 +1,5 @@
TESTDLL = msi.dll
-IMPORTS = cabinet msi shell32 ole32 oleaut32 user32 advapi32 version
+IMPORTS = cabinet msi shell32 ole32 oleaut32 user32 advapi32 version uuid
C_SRCS = \
action.c \
diff --git a/dlls/msi/tests/action.c b/dlls/msi/tests/action.c
index 60562f1..f1cafbd 100644
--- a/dlls/msi/tests/action.c
+++ b/dlls/msi/tests/action.c
@@ -23,6 +23,8 @@
#include <stdio.h>
#include <stdlib.h>
+#define COBJMACROS
+
#include <windows.h>
#include <msiquery.h>
#include <msidefs.h>
@@ -30,9 +32,14 @@
#include <fci.h>
#include <srrestoreptapi.h>
#include <wtypes.h>
+#include <shobjidl.h>
#include <shellapi.h>
+#include <propsys.h>
#include <winsvc.h>
+#include <initguid.h>
+#include <propkey.h>
+
#include "wine/test.h"
static UINT (WINAPI *pMsiQueryComponentStateA)
@@ -879,6 +886,12 @@ static const char crs_shortcut_dat[] =
"Shortcut\tShortcut\n"
"shortcut\tMSITESTDIR\tshortcut\tshortcut\t[MSITESTDIR]target.txt\t\t\t\t\t\t\t\n";
+static const char crs_shortcut_prop_dat[] =
+ "MsiShortcutProperty\tShortcut_\tPropertyKey\tPropVariantValue\n"
+ "s255\ts72\ts255\ts255\n"
+ "MsiShortcutProperty\tMsiShortcutProperty\n"
+ "shortcut_prop\tshortcut\tSystem.AppUserModel.ID\tWine.Test.Blub\n";
+
static const char crs_install_exec_seq_dat[] =
"Action\tCondition\tSequence\n"
"s72\tS255\tI2\n"
@@ -1882,6 +1895,7 @@ static const msi_table crs_tables[] =
ADD_TABLE(crs_feature_comp),
ADD_TABLE(crs_file),
ADD_TABLE(crs_shortcut),
+ ADD_TABLE(crs_shortcut_prop),
ADD_TABLE(crs_install_exec_seq),
ADD_TABLE(media),
ADD_TABLE(property)
@@ -2671,13 +2685,18 @@ static BOOL file_exists(LPCSTR file)
return GetFileAttributesA(file) != INVALID_FILE_ATTRIBUTES;
}
+static void pf_fullname(LPCSTR file, CHAR buffer[])
+{
+ lstrcpyA(buffer, PROG_FILES_DIR);
+ lstrcatA(buffer, "\\");
+ lstrcatA(buffer, file);
+}
+
static BOOL pf_exists(LPCSTR file)
{
CHAR path[MAX_PATH];
- lstrcpyA(path, PROG_FILES_DIR);
- lstrcatA(path, "\\");
- lstrcatA(path, file);
+ pf_fullname(file, path);
return file_exists(path);
}
@@ -5825,6 +5844,56 @@ static void test_create_remove_shortcut(void)
ok(pf_exists("msitest\\target.txt"), "file not created\n");
ok(pf_exists("msitest\\shortcut.lnk"), "file not created\n");
+ /* analyze whether the shortcut properties have been written properly */
+ {
+ CHAR lnkpath[MAX_PATH];
+ WCHAR lnkpathW[MAX_PATH];
+ IShellLinkW *link = NULL;
+ IPersistFile *file = NULL;
+ IPropertyStore *store = NULL;
+ HRESULT hr;
+
+ CoInitialize(NULL);
+
+ pf_fullname("msitest\\shortcut.lnk", lnkpath);
+ MultiByteToWideChar(CP_ACP, 0, lnkpath, -1, lnkpathW, MAX_PATH);
+
+ hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW, (void**)&link);
+ ok(hr == S_OK, "CoCreateInstance() failed, hr=%x\n", hr);
+
+ hr = IShellLinkW_QueryInterface(link, &IID_IPersistFile, (void**)&file);
+ ok(hr == S_OK, "QueryInterface, hr=%x\n", hr);
+
+ hr = IPersistFile_Load(file, lnkpathW, STGM_READ);
+ ok(hr == S_OK, "IPersistFile::Load hr=%x\n", hr);
+
+ hr = IShellLinkW_QueryInterface(link, &IID_IPropertyStore, (void**)&store);
+ if (SUCCEEDED(hr))
+ {
+ PROPVARIANT v;
+ WCHAR expected[] = {'W','i','n','e','.','T','e','s','t','.','B','l','u','b',0};
+
+ hr = IPropertyStore_GetValue(store, &PKEY_AppUserModel_ID, &v);
+ ok(hr == S_OK, "IPropertyStore::GetValue hr=%x\n", hr);
+
+ ok(v.vt == VT_LPWSTR, "Unexpected variant type %d\n", v.vt);
+ ok(!lstrcmpW(expected, U(v).pwszVal), "Unexpected value %s\n", wine_dbgstr_w(U(v).pwszVal));
+
+ PropVariantClear(&v);
+ IPropertyStore_Release(store);
+ }
+ else
+ {
+ win_skip("IPropertyStore not implemented for shell links\n");
+ }
+
+ IPersistFile_Release(file);
+ IShellLinkW_Release(link);
+
+ CoUninitialize();
+ }
+
r = MsiInstallProductA(msifile, "REMOVE=ALL");
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
diff --git a/dlls/msi/tests/automation.c b/dlls/msi/tests/automation.c
index 016b1a2..84a3ae4 100644
--- a/dlls/msi/tests/automation.c
+++ b/dlls/msi/tests/automation.c
@@ -23,7 +23,6 @@
#include <stdio.h>
-#include <initguid.h>
#include <windows.h>
#include <msiquery.h>
#include <msidefs.h>
--
2.4.3
More information about the wine-devel
mailing list