[PATCH 3/3] msi: Execute custom actions in a separate process.

Zebediah Figura z.figura12 at gmail.com
Wed Apr 25 20:54:40 CDT 2018


This patch does a few things:

1) Build client and server stubs for winemsi.idl.
2) As a result, the server-side entry points must be renamed, so an s_ prefix
   is added.
3) Execute call_dll_function() via msiexec.exe instead of directly.
4) Add RPC setup and teardown on both client and server side.
5) Initialize COM on both client and server side. This is necessary so that
   streams can be marshalled from the server to the client and vice versa. It
   also fixes the most common symptom of bug 18070.
6) Run the custom action on a separate thread on the client side, so that COM
   is not yet initialized on that thread.
7) Remove CUSTOMPROC_wrapper() since this is (now) already handled by
   call_thread_func_wrapper() on i386.

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/msi/Makefile.in       |  4 +-
 dlls/msi/custom.c          | 97 +++++++++++++++++++++++++++++++++-------------
 dlls/msi/database.c        |  8 ++--
 dlls/msi/handle.c          |  2 +-
 dlls/msi/msi.spec          |  2 +
 dlls/msi/msiquery.c        | 10 ++---
 dlls/msi/package.c         | 42 ++++++++++----------
 dlls/msi/tests/custom.c    |  2 +-
 dlls/msi/winemsi.idl       |  5 ++-
 programs/msiexec/msiexec.c |  9 +++--
 10 files changed, 116 insertions(+), 65 deletions(-)

diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in
index 37c9a7a..1a17d7e 100644
--- a/dlls/msi/Makefile.in
+++ b/dlls/msi/Makefile.in
@@ -1,8 +1,10 @@
 MODULE    = msi.dll
 IMPORTLIB = msi
-IMPORTS   = uuid urlmon wininet comctl32 shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32
+IMPORTS   = uuid urlmon wininet comctl32 shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 rpcrt4
 DELAYIMPORTS = odbccp32 wintrust crypt32 imagehlp mspatcha
 
+EXTRAIDLFLAGS = --prefix-server=s_
+
 C_SRCS = \
 	action.c \
 	alter.c \
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index f9976a0..12fe53e 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -486,35 +486,18 @@ static void handle_msi_break(LPCSTR target)
     DebugBreak();
 }
 
-#ifdef __i386__
-extern UINT CUSTOMPROC_wrapper( MsiCustomActionEntryPoint proc, MSIHANDLE handle );
-__ASM_GLOBAL_FUNC( CUSTOMPROC_wrapper,
-    "pushl %ebp\n\t"
-    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
-    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
-    "movl %esp,%ebp\n\t"
-    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
-    "subl $4,%esp\n\t"
-    "pushl 12(%ebp)\n\t"
-    "movl 8(%ebp),%eax\n\t"
-    "call *%eax\n\t"
-    "leave\n\t"
-    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
-    __ASM_CFI(".cfi_same_value %ebp\n\t")
-    "ret" )
-#else
-static inline UINT CUSTOMPROC_wrapper( MsiCustomActionEntryPoint proc, MSIHANDLE handle )
-{
-    return proc(handle);
-}
-#endif
+static WCHAR ncalrpcW[] = {'n','c','a','l','r','p','c',0};
+static WCHAR endpoint_lrpcW[] = {'m','s','i',0};
 
-static DWORD ACTION_CallDllFunction( const GUID *guid )
+UINT __wine_msi_call_dll_function(const GUID *guid)
 {
     MsiCustomActionEntryPoint fn;
     MSIHANDLE remote_package = 0;
+    RPC_WSTR binding_str;
     MSIHANDLE hPackage;
+    RPC_STATUS status;
     HANDLE hModule;
+    HANDLE thread;
     LPWSTR dll;
     LPSTR proc;
     INT type;
@@ -522,6 +505,23 @@ static DWORD ACTION_CallDllFunction( const GUID *guid )
 
     TRACE("%s\n", debugstr_guid( guid ));
 
+    status = RpcStringBindingComposeW(NULL, ncalrpcW, NULL, endpoint_lrpcW, NULL, &binding_str);
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcStringBindingCompose failed: %#x\n", status);
+        return status;
+    }
+    status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcBindingFromStringBinding failed: %#x\n", status);
+        return status;
+    }
+    RpcStringFreeW(&binding_str);
+
+    /* We need this to unmarshal streams, and some apps expect it to be present. */
+    CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
     r = remote_GetActionInfo(guid, &type, &dll, &proc, &remote_package);
     if (r != ERROR_SUCCESS)
         return r;
@@ -544,7 +544,9 @@ static DWORD ACTION_CallDllFunction( const GUID *guid )
 
             __TRY
             {
-                r = CUSTOMPROC_wrapper( fn, hPackage );
+                thread = CreateThread(NULL, 0, (void *)fn, (void *)(ULONG_PTR) hPackage, 0, NULL);
+                WaitForSingleObject(thread, INFINITE);
+                GetExitCodeThread(thread, &r);
             }
             __EXCEPT_PAGE_FAULT
             {
@@ -568,17 +570,56 @@ static DWORD ACTION_CallDllFunction( const GUID *guid )
     midl_user_free(dll);
     midl_user_free(proc);
 
+    CoUninitialize();
+
+    RpcBindingFree(&rpc_handle);
+
     return r;
 }
 
 static DWORD WINAPI DllThread( LPVOID arg )
 {
-    LPGUID guid = arg;
-    DWORD rc = 0;
+    WCHAR buffer[64] = {'m','s','i','e','x','e','c','.','e','x','e',' ','-','E','m','b','e','d','d','i','n','g',' ',0};
+    PROCESS_INFORMATION pi = {0};
+    STARTUPINFOW si = {0};
+    RPC_STATUS status;
+    GUID *guid = arg;
+    DWORD rc;
 
     TRACE("custom action (%x) started\n", GetCurrentThreadId() );
 
-    rc = ACTION_CallDllFunction( guid );
+    CoInitializeEx(NULL, COINIT_MULTITHREADED); /* needed to marshal streams */
+
+    status = RpcServerUseProtseqEpW(ncalrpcW, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, endpoint_lrpcW, NULL);
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcServerUseProtseqEp failed: %#x\n", status);
+        return status;
+    }
+
+    status = RpcServerRegisterIfEx(s_IWineMsiRemote_v0_0_s_ifspec, NULL, NULL,
+        RPC_IF_AUTOLISTEN, RPC_C_LISTEN_MAX_CALLS_DEFAULT, NULL);
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcServerRegisterIfEx failed: %#x\n", status);
+        return status;
+    }
+
+    StringFromGUID2(guid, buffer + strlenW(buffer), 39);
+    CreateProcessW(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+    WaitForSingleObject(pi.hProcess, INFINITE);
+    GetExitCodeProcess(pi.hProcess, &rc);
+    CloseHandle(pi.hProcess);
+    CloseHandle(pi.hThread);
+
+    status = RpcServerUnregisterIf(s_IWineMsiRemote_v0_0_s_ifspec, NULL, FALSE);
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcServerUnregisterIf failed: %#x\n", status);
+        return status;
+    }
+
+    CoUninitialize();
 
     TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc );
 
@@ -1343,7 +1384,7 @@ void ACTION_FinishCustomActions(const MSIPACKAGE* package)
     LeaveCriticalSection( &msi_custom_action_cs );
 }
 
-UINT __cdecl remote_GetActionInfo(const GUID *guid, int *type, LPWSTR *dll, LPSTR *func, MSIHANDLE *hinst)
+UINT __cdecl s_remote_GetActionInfo(const GUID *guid, int *type, LPWSTR *dll, LPSTR *func, MSIHANDLE *hinst)
 {
     msi_custom_action_info *info;
 
diff --git a/dlls/msi/database.c b/dlls/msi/database.c
index 4a05593..ef0221d 100644
--- a/dlls/msi/database.c
+++ b/dlls/msi/database.c
@@ -1906,12 +1906,12 @@ MSIDBSTATE WINAPI MsiGetDatabaseState( MSIHANDLE handle )
     return ret;
 }
 
-MSICONDITION __cdecl remote_DatabaseIsTablePersistent(MSIHANDLE db, LPCWSTR table)
+MSICONDITION __cdecl s_remote_DatabaseIsTablePersistent(MSIHANDLE db, LPCWSTR table)
 {
     return MsiDatabaseIsTablePersistentW(db, table);
 }
 
-UINT __cdecl remote_DatabaseGetPrimaryKeys(MSIHANDLE db, LPCWSTR table, struct wire_record **rec)
+UINT __cdecl s_remote_DatabaseGetPrimaryKeys(MSIHANDLE db, LPCWSTR table, struct wire_record **rec)
 {
     MSIHANDLE handle;
     UINT r = MsiDatabaseGetPrimaryKeysW(db, table, &handle);
@@ -1922,12 +1922,12 @@ UINT __cdecl remote_DatabaseGetPrimaryKeys(MSIHANDLE db, LPCWSTR table, struct w
     return r;
 }
 
-UINT __cdecl remote_DatabaseGetSummaryInformation(MSIHANDLE db, UINT updatecount, MSIHANDLE *suminfo)
+UINT __cdecl s_remote_DatabaseGetSummaryInformation(MSIHANDLE db, UINT updatecount, MSIHANDLE *suminfo)
 {
     return MsiGetSummaryInformationW(db, NULL, updatecount, suminfo);
 }
 
-UINT __cdecl remote_DatabaseOpenView(MSIHANDLE db, LPCWSTR query, MSIHANDLE *view)
+UINT __cdecl s_remote_DatabaseOpenView(MSIHANDLE db, LPCWSTR query, MSIHANDLE *view)
 {
     return MsiDatabaseOpenViewW(db, query, view);
 }
diff --git a/dlls/msi/handle.c b/dlls/msi/handle.c
index 1002f9d..0881833 100644
--- a/dlls/msi/handle.c
+++ b/dlls/msi/handle.c
@@ -344,7 +344,7 @@ UINT WINAPI MsiCloseAllHandles(void)
     return n;
 }
 
-UINT __cdecl remote_CloseHandle(MSIHANDLE handle)
+UINT __cdecl s_remote_CloseHandle(MSIHANDLE handle)
 {
     return MsiCloseHandle(handle);
 }
diff --git a/dlls/msi/msi.spec b/dlls/msi/msi.spec
index 4288c9d..aecba1b 100644
--- a/dlls/msi/msi.spec
+++ b/dlls/msi/msi.spec
@@ -294,3 +294,5 @@
 @ stdcall -private DllGetClassObject(ptr ptr ptr)
 @ stdcall -private DllRegisterServer()
 @ stdcall -private DllUnregisterServer()
+
+@ cdecl __wine_msi_call_dll_function(ptr)
diff --git a/dlls/msi/msiquery.c b/dlls/msi/msiquery.c
index 42ee8c7..7dcfa7f 100644
--- a/dlls/msi/msiquery.c
+++ b/dlls/msi/msiquery.c
@@ -1093,12 +1093,12 @@ MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
     return r;
 }
 
-UINT __cdecl remote_ViewClose(MSIHANDLE view)
+UINT __cdecl s_remote_ViewClose(MSIHANDLE view)
 {
     return MsiViewClose(view);
 }
 
-UINT __cdecl remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
+UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
 {
     MSIHANDLE rec = 0;
     UINT r;
@@ -1112,7 +1112,7 @@ UINT __cdecl remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
     return r;
 }
 
-UINT __cdecl remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
+UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
 {
     MSIHANDLE handle;
     UINT r = MsiViewFetch(view, &handle);
@@ -1123,7 +1123,7 @@ UINT __cdecl remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
     return r;
 }
 
-UINT __cdecl remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
+UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
 {
     MSIHANDLE handle;
     UINT r = MsiViewGetColumnInfo(view, info, &handle);
@@ -1134,7 +1134,7 @@ UINT __cdecl remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wi
     return r;
 }
 
-UINT __cdecl remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
+UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
     struct wire_record *remote_rec, struct wire_record **remote_refreshed)
 {
     MSIHANDLE handle = 0;
diff --git a/dlls/msi/package.c b/dlls/msi/package.c
index 067e571..a2fa785 100644
--- a/dlls/msi/package.c
+++ b/dlls/msi/package.c
@@ -2421,12 +2421,12 @@ UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
     return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
 }
 
-MSIHANDLE __cdecl remote_GetActiveDatabase(MSIHANDLE hinst)
+MSIHANDLE __cdecl s_remote_GetActiveDatabase(MSIHANDLE hinst)
 {
     return MsiGetActiveDatabase(hinst);
 }
 
-UINT __cdecl remote_GetProperty(MSIHANDLE hinst, LPCWSTR property, LPWSTR *value, DWORD *size)
+UINT __cdecl s_remote_GetProperty(MSIHANDLE hinst, LPCWSTR property, LPWSTR *value, DWORD *size)
 {
     WCHAR empty[1];
     UINT r;
@@ -2444,12 +2444,12 @@ UINT __cdecl remote_GetProperty(MSIHANDLE hinst, LPCWSTR property, LPWSTR *value
     return r;
 }
 
-UINT __cdecl remote_SetProperty(MSIHANDLE hinst, LPCWSTR property, LPCWSTR value)
+UINT __cdecl s_remote_SetProperty(MSIHANDLE hinst, LPCWSTR property, LPCWSTR value)
 {
     return MsiSetPropertyW(hinst, property, value);
 }
 
-int __cdecl remote_ProcessMessage(MSIHANDLE hinst, INSTALLMESSAGE message, struct wire_record *remote_rec)
+int __cdecl s_remote_ProcessMessage(MSIHANDLE hinst, INSTALLMESSAGE message, struct wire_record *remote_rec)
 {
     MSIHANDLE rec;
     int ret;
@@ -2464,17 +2464,17 @@ int __cdecl remote_ProcessMessage(MSIHANDLE hinst, INSTALLMESSAGE message, struc
     return ret;
 }
 
-UINT __cdecl remote_DoAction(MSIHANDLE hinst, LPCWSTR action)
+UINT __cdecl s_remote_DoAction(MSIHANDLE hinst, LPCWSTR action)
 {
     return MsiDoActionW(hinst, action);
 }
 
-UINT __cdecl remote_Sequence(MSIHANDLE hinst, LPCWSTR table, int sequence)
+UINT __cdecl s_remote_Sequence(MSIHANDLE hinst, LPCWSTR table, int sequence)
 {
     return MsiSequenceW(hinst, table, sequence);
 }
 
-UINT __cdecl remote_GetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
+UINT __cdecl s_remote_GetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
 {
     WCHAR empty[1];
     DWORD size = 0;
@@ -2491,12 +2491,12 @@ UINT __cdecl remote_GetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value
     return r;
 }
 
-UINT __cdecl remote_SetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPCWSTR value)
+UINT __cdecl s_remote_SetTargetPath(MSIHANDLE hinst, LPCWSTR folder, LPCWSTR value)
 {
     return MsiSetTargetPathW(hinst, folder, value);
 }
 
-UINT __cdecl remote_GetSourcePath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
+UINT __cdecl s_remote_GetSourcePath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value)
 {
     WCHAR empty[1];
     DWORD size = 1;
@@ -2513,49 +2513,49 @@ UINT __cdecl remote_GetSourcePath(MSIHANDLE hinst, LPCWSTR folder, LPWSTR *value
     return r;
 }
 
-BOOL __cdecl remote_GetMode(MSIHANDLE hinst, MSIRUNMODE mode)
+BOOL __cdecl s_remote_GetMode(MSIHANDLE hinst, MSIRUNMODE mode)
 {
     return MsiGetMode(hinst, mode);
 }
 
-UINT __cdecl remote_SetMode(MSIHANDLE hinst, MSIRUNMODE mode, BOOL state)
+UINT __cdecl s_remote_SetMode(MSIHANDLE hinst, MSIRUNMODE mode, BOOL state)
 {
     return MsiSetMode(hinst, mode, state);
 }
 
-UINT __cdecl remote_GetFeatureState(MSIHANDLE hinst, LPCWSTR feature,
+UINT __cdecl s_remote_GetFeatureState(MSIHANDLE hinst, LPCWSTR feature,
                                     INSTALLSTATE *installed, INSTALLSTATE *action)
 {
     return MsiGetFeatureStateW(hinst, feature, installed, action);
 }
 
-UINT __cdecl remote_SetFeatureState(MSIHANDLE hinst, LPCWSTR feature, INSTALLSTATE state)
+UINT __cdecl s_remote_SetFeatureState(MSIHANDLE hinst, LPCWSTR feature, INSTALLSTATE state)
 {
     return MsiSetFeatureStateW(hinst, feature, state);
 }
 
-UINT __cdecl remote_GetComponentState(MSIHANDLE hinst, LPCWSTR component,
+UINT __cdecl s_remote_GetComponentState(MSIHANDLE hinst, LPCWSTR component,
                                       INSTALLSTATE *installed, INSTALLSTATE *action)
 {
     return MsiGetComponentStateW(hinst, component, installed, action);
 }
 
-UINT __cdecl remote_SetComponentState(MSIHANDLE hinst, LPCWSTR component, INSTALLSTATE state)
+UINT __cdecl s_remote_SetComponentState(MSIHANDLE hinst, LPCWSTR component, INSTALLSTATE state)
 {
     return MsiSetComponentStateW(hinst, component, state);
 }
 
-LANGID __cdecl remote_GetLanguage(MSIHANDLE hinst)
+LANGID __cdecl s_remote_GetLanguage(MSIHANDLE hinst)
 {
     return MsiGetLanguage(hinst);
 }
 
-UINT __cdecl remote_SetInstallLevel(MSIHANDLE hinst, int level)
+UINT __cdecl s_remote_SetInstallLevel(MSIHANDLE hinst, int level)
 {
     return MsiSetInstallLevel(hinst, level);
 }
 
-UINT __cdecl remote_FormatRecord(MSIHANDLE hinst, struct wire_record *remote_rec, LPWSTR *value)
+UINT __cdecl s_remote_FormatRecord(MSIHANDLE hinst, struct wire_record *remote_rec, LPWSTR *value)
 {
     WCHAR empty[1];
     DWORD size = 0;
@@ -2578,18 +2578,18 @@ UINT __cdecl remote_FormatRecord(MSIHANDLE hinst, struct wire_record *remote_rec
     return r;
 }
 
-MSICONDITION __cdecl remote_EvaluateCondition(MSIHANDLE hinst, LPCWSTR condition)
+MSICONDITION __cdecl s_remote_EvaluateCondition(MSIHANDLE hinst, LPCWSTR condition)
 {
     return MsiEvaluateConditionW(hinst, condition);
 }
 
-UINT __cdecl remote_GetFeatureCost(MSIHANDLE hinst, LPCWSTR feature,
+UINT __cdecl s_remote_GetFeatureCost(MSIHANDLE hinst, LPCWSTR feature,
     MSICOSTTREE cost_tree, INSTALLSTATE state, INT *cost)
 {
     return MsiGetFeatureCostW(hinst, feature, cost_tree, state, cost);
 }
 
-UINT __cdecl remote_EnumComponentCosts(MSIHANDLE hinst, LPCWSTR component,
+UINT __cdecl s_remote_EnumComponentCosts(MSIHANDLE hinst, LPCWSTR component,
     DWORD index, INSTALLSTATE state, LPWSTR drive, INT *cost, INT *temp)
 {
     DWORD size = 3;
diff --git a/dlls/msi/tests/custom.c b/dlls/msi/tests/custom.c
index 35b3d71..04946d9 100644
--- a/dlls/msi/tests/custom.c
+++ b/dlls/msi/tests/custom.c
@@ -993,7 +993,7 @@ UINT WINAPI main_test(MSIHANDLE hinst)
 
     /* Test for an MTA apartment */
     hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
-    todo_wine_ok(hinst, hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
+    ok(hinst, hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
 
     if (unk) IUnknown_Release(unk);
 
diff --git a/dlls/msi/winemsi.idl b/dlls/msi/winemsi.idl
index 8af1759..50f62fc 100644
--- a/dlls/msi/winemsi.idl
+++ b/dlls/msi/winemsi.idl
@@ -18,6 +18,8 @@
  */
 
 #pragma makedep header
+#pragma makedep client
+#pragma makedep server
 
 import "objidl.idl";
 
@@ -55,7 +57,8 @@ struct wire_record {
 };
 
 [
-    uuid(56D58B64-8780-4c22-A8BC-8B0B29E4A9F8)
+    uuid(56D58B64-8780-4c22-A8BC-8B0B29E4A9F8),
+    implicit_handle(handle_t rpc_handle)
 ]
 interface IWineMsiRemote
 {
diff --git a/programs/msiexec/msiexec.c b/programs/msiexec/msiexec.c
index 8dcd216..2ed0557 100644
--- a/programs/msiexec/msiexec.c
+++ b/programs/msiexec/msiexec.c
@@ -393,10 +393,13 @@ static DWORD DoUnregServer(void)
     return ret;
 }
 
-static INT DoEmbedding( LPWSTR key )
+extern UINT __wine_msi_call_dll_function(GUID *guid);
+
+static int DoEmbedding(LPCWSTR key)
 {
-	printf("Remote custom actions are not supported yet\n");
-	return 1;
+    GUID guid;
+    CLSIDFromString(key, &guid);
+    return __wine_msi_call_dll_function(&guid);
 }
 
 /*
-- 
2.7.4




More information about the wine-devel mailing list