msi: Build the key path from the display name if the component is an assembly.
[wine] / dlls / msi / msi_main.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "shlwapi.h"
30 #include "oleauto.h"
31 #include "rpcproxy.h"
32 #include "msipriv.h"
33 #include "msiserver.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msi);
38
39 static LONG dll_count;
40
41 /* the UI level */
42 INSTALLUILEVEL           gUILevel         = INSTALLUILEVEL_BASIC;
43 HWND                     gUIhwnd          = 0;
44 INSTALLUI_HANDLERA       gUIHandlerA      = NULL;
45 INSTALLUI_HANDLERW       gUIHandlerW      = NULL;
46 INSTALLUI_HANDLER_RECORD gUIHandlerRecord = NULL;
47 DWORD                    gUIFilter        = 0;
48 LPVOID                   gUIContext       = NULL;
49 WCHAR                   *gszLogFile       = NULL;
50 HINSTANCE msi_hInstance;
51
52 static WCHAR msi_path[MAX_PATH];
53 static ITypeLib *msi_typelib;
54
55 /*
56  * Dll lifetime tracking declaration
57  */
58 static void LockModule(void)
59 {
60     InterlockedIncrement(&dll_count);
61 }
62
63 static void UnlockModule(void)
64 {
65     InterlockedDecrement(&dll_count);
66 }
67
68 /******************************************************************
69  *      DllMain
70  */
71 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
72 {
73     switch (fdwReason)
74     {
75     case DLL_PROCESS_ATTACH:
76         msi_hInstance = hinstDLL;
77         DisableThreadLibraryCalls(hinstDLL);
78         break;
79     case DLL_PROCESS_DETACH:
80         if (msi_typelib) ITypeLib_Release( msi_typelib );
81         msi_dialog_unregister_class();
82         msi_free_handle_table();
83         msi_free( gszLogFile );
84         break;
85     }
86     return TRUE;
87 }
88
89 static CRITICAL_SECTION MSI_typelib_cs;
90 static CRITICAL_SECTION_DEBUG MSI_typelib_cs_debug =
91 {
92     0, 0, &MSI_typelib_cs,
93     { &MSI_typelib_cs_debug.ProcessLocksList,
94       &MSI_typelib_cs_debug.ProcessLocksList },
95       0, 0, { (DWORD_PTR)(__FILE__ ": MSI_typelib_cs") }
96 };
97 static CRITICAL_SECTION MSI_typelib_cs = { &MSI_typelib_cs_debug, -1, 0, 0, 0, 0 };
98
99 ITypeLib *get_msi_typelib( LPWSTR *path )
100 {
101     EnterCriticalSection( &MSI_typelib_cs );
102
103     if (!msi_typelib)
104     {
105         TRACE("loading typelib\n");
106
107         if (GetModuleFileNameW( msi_hInstance, msi_path, MAX_PATH ))
108             LoadTypeLib( msi_path, &msi_typelib );
109     }
110
111     LeaveCriticalSection( &MSI_typelib_cs );
112
113     if (path)
114         *path = msi_path;
115
116     if (msi_typelib)
117         ITypeLib_AddRef( msi_typelib );
118
119     return msi_typelib;
120 }
121
122 typedef struct tagIClassFactoryImpl {
123     IClassFactory IClassFactory_iface;
124     HRESULT (*create_object)( IUnknown*, LPVOID* );
125 } IClassFactoryImpl;
126
127 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
128 {
129     return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
130 }
131
132 static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
133                 REFIID riid,LPVOID *ppobj)
134 {
135     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
136
137     TRACE("%p %s %p\n",This,debugstr_guid(riid),ppobj);
138
139     if( IsEqualCLSID( riid, &IID_IUnknown ) ||
140         IsEqualCLSID( riid, &IID_IClassFactory ) )
141     {
142         IClassFactory_AddRef( iface );
143         *ppobj = iface;
144         return S_OK;
145     }
146     return E_NOINTERFACE;
147 }
148
149 static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
150 {
151     LockModule();
152     return 2;
153 }
154
155 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
156 {
157     UnlockModule();
158     return 1;
159 }
160
161 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
162     LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
163 {
164     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
165     IUnknown *unk = NULL;
166     HRESULT r;
167
168     TRACE("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
169
170     r = This->create_object( pOuter, (LPVOID*) &unk );
171     if (SUCCEEDED(r))
172     {
173         r = IUnknown_QueryInterface( unk, riid, ppobj );
174         IUnknown_Release( unk );
175     }
176     return r;
177 }
178
179 static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
180 {
181     TRACE("%p %d\n", iface, dolock);
182
183     if (dolock)
184         LockModule();
185     else
186         UnlockModule();
187
188     return S_OK;
189 }
190
191 static const IClassFactoryVtbl MsiCF_Vtbl =
192 {
193     MsiCF_QueryInterface,
194     MsiCF_AddRef,
195     MsiCF_Release,
196     MsiCF_CreateInstance,
197     MsiCF_LockServer
198 };
199
200 static IClassFactoryImpl MsiServer_CF = { { &MsiCF_Vtbl }, create_msiserver };
201 static IClassFactoryImpl WineMsiCustomRemote_CF = { { &MsiCF_Vtbl }, create_msi_custom_remote };
202 static IClassFactoryImpl WineMsiRemotePackage_CF = { { &MsiCF_Vtbl }, create_msi_remote_package };
203
204 /******************************************************************
205  * DllGetClassObject          [MSI.@]
206  */
207 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
208 {
209     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
210
211     if ( IsEqualCLSID (rclsid, &CLSID_MsiInstaller) )
212     {
213         *ppv = &MsiServer_CF;
214         return S_OK;
215     }
216
217     if ( IsEqualCLSID (rclsid, &CLSID_WineMsiRemoteCustomAction) )
218     {
219         *ppv = &WineMsiCustomRemote_CF;
220         return S_OK;
221     }
222
223     if ( IsEqualCLSID (rclsid, &CLSID_WineMsiRemotePackage) )
224     {
225         *ppv = &WineMsiRemotePackage_CF;
226         return S_OK;
227     }
228
229     if( IsEqualCLSID (rclsid, &CLSID_MsiServerMessage) ||
230         IsEqualCLSID (rclsid, &CLSID_MsiServer) ||
231         IsEqualCLSID (rclsid, &CLSID_PSFactoryBuffer) ||
232         IsEqualCLSID (rclsid, &CLSID_MsiServerX3) )
233     {
234         FIXME("create %s object\n", debugstr_guid( rclsid ));
235     }
236
237     return CLASS_E_CLASSNOTAVAILABLE;
238 }
239
240 /******************************************************************
241  * DllGetVersion              [MSI.@]
242  */
243 HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
244 {
245     TRACE("%p\n",pdvi);
246
247     if (pdvi->cbSize < sizeof(DLLVERSIONINFO))
248         return E_INVALIDARG;
249
250     pdvi->dwMajorVersion = MSI_MAJORVERSION;
251     pdvi->dwMinorVersion = MSI_MINORVERSION;
252     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
253     pdvi->dwPlatformID = DLLVER_PLATFORM_WINDOWS;
254
255     return S_OK;
256 }
257
258 /******************************************************************
259  * DllCanUnloadNow            [MSI.@]
260  */
261 HRESULT WINAPI DllCanUnloadNow(void)
262 {
263     return dll_count == 0 ? S_OK : S_FALSE;
264 }
265
266 /***********************************************************************
267  *              DllRegisterServer (MSI.@)
268  */
269 HRESULT WINAPI DllRegisterServer(void)
270 {
271     return __wine_register_resources( msi_hInstance, NULL );
272 }
273
274 /***********************************************************************
275  *              DllUnregisterServer (MSI.@)
276  */
277 HRESULT WINAPI DllUnregisterServer(void)
278 {
279     return __wine_unregister_resources( msi_hInstance, NULL );
280 }