wscript: Implemented Host_get_ScriptName.
[wine] / programs / wscript / main.c
1 /*
2  * Copyright 2010 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include <windef.h>
24 #include <winbase.h>
25 #include <winreg.h>
26 #include <ole2.h>
27 #include <activscp.h>
28 #include <initguid.h>
29
30 #include "wscript.h"
31
32 #include <wine/debug.h>
33 #include <wine/unicode.h>
34
35 WINE_DEFAULT_DEBUG_CHANNEL(wscript);
36
37 static const WCHAR wscriptW[] = {'W','S','c','r','i','p','t',0};
38 static const WCHAR wshW[] = {'W','S','H',0};
39 WCHAR scriptFullName[MAX_PATH];
40
41 ITypeInfo *host_ti;
42
43 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface,
44                                                       REFIID riid, void **ppv)
45 {
46     if(IsEqualGUID(riid, &IID_IUnknown)) {
47         WINE_TRACE("(IID_IUnknown %p)\n", ppv);
48         *ppv = iface;
49     }else if(IsEqualGUID(riid, &IID_IActiveScriptSite)) {
50         WINE_TRACE("(IID_IActiveScriptSite %p)\n", ppv);
51         *ppv = iface;
52     }else {
53         *ppv = NULL;
54         WINE_TRACE("(%s %p)\n", wine_dbgstr_guid(riid), ppv);
55         return E_NOINTERFACE;
56     }
57
58     IUnknown_AddRef((IUnknown*)*ppv);
59     return S_OK;
60 }
61
62 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
63 {
64     return 2;
65 }
66
67 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
68 {
69     return 1;
70 }
71
72 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
73 {
74     WINE_TRACE("()\n");
75
76     *plcid = GetUserDefaultLCID();
77     return S_OK;
78 }
79
80 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface,
81         LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppunkItem, ITypeInfo **ppti)
82 {
83     WINE_TRACE("(%s %x %p %p)\n", wine_dbgstr_w(pstrName), dwReturnMask, ppunkItem, ppti);
84
85     if(strcmpW(pstrName, wshW) && strcmpW(pstrName, wscriptW))
86         return E_FAIL;
87
88     if(dwReturnMask & SCRIPTINFO_ITYPEINFO) {
89         ITypeInfo_AddRef(host_ti);
90         *ppti = host_ti;
91     }
92
93     if(dwReturnMask & SCRIPTINFO_IUNKNOWN) {
94         IHost_AddRef(&host_obj);
95         *ppunkItem = (IUnknown*)&host_obj;
96     }
97
98     return S_OK;
99 }
100
101 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface,
102         BSTR *pbstrVersion)
103 {
104     WINE_FIXME("()\n");
105     return E_NOTIMPL;
106 }
107
108 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
109         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
110 {
111     WINE_FIXME("()\n");
112     return E_NOTIMPL;
113 }
114
115 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface,
116         SCRIPTSTATE ssScriptState)
117 {
118     WINE_TRACE("(%x)\n", ssScriptState);
119     return S_OK;
120 }
121
122 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface,
123         IActiveScriptError *pscripterror)
124 {
125     WINE_FIXME("()\n");
126     return E_NOTIMPL;
127 }
128
129 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
130 {
131     WINE_TRACE("()\n");
132     return S_OK;
133 }
134
135 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
136 {
137     WINE_TRACE("()\n");
138     return S_OK;
139 }
140
141 static IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
142     ActiveScriptSite_QueryInterface,
143     ActiveScriptSite_AddRef,
144     ActiveScriptSite_Release,
145     ActiveScriptSite_GetLCID,
146     ActiveScriptSite_GetItemInfo,
147     ActiveScriptSite_GetDocVersionString,
148     ActiveScriptSite_OnScriptTerminate,
149     ActiveScriptSite_OnStateChange,
150     ActiveScriptSite_OnScriptError,
151     ActiveScriptSite_OnEnterScript,
152     ActiveScriptSite_OnLeaveScript
153 };
154
155 IActiveScriptSite script_site = { &ActiveScriptSiteVtbl };
156
157 static BOOL load_typelib(void)
158 {
159     ITypeLib *typelib;
160     HRESULT hres;
161
162     static const WCHAR wscript_exeW[] = {'w','s','c','r','i','p','t','.','e','x','e',0};
163
164     hres = LoadTypeLib(wscript_exeW, &typelib);
165     if(FAILED(hres))
166         return FALSE;
167
168     hres = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IHost, &host_ti);
169
170     ITypeLib_Release(typelib);
171     return SUCCEEDED(hres);
172 }
173
174 static BOOL get_engine_clsid(const WCHAR *ext, CLSID *clsid)
175 {
176     WCHAR fileid[64], progid[64];
177     DWORD res;
178     LONG size;
179     HKEY hkey;
180     HRESULT hres;
181
182     static const WCHAR script_engineW[] =
183         {'\\','S','c','r','i','p','t','E','n','g','i','n','e',0};
184
185     res = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey);
186     if(res != ERROR_SUCCESS)
187         return FALSE;
188
189     size = sizeof(fileid)/sizeof(WCHAR);
190     res = RegQueryValueW(hkey, NULL, fileid, &size);
191     RegCloseKey(hkey);
192     if(res != ERROR_SUCCESS)
193         return FALSE;
194
195     WINE_TRACE("fileid is %s\n", wine_dbgstr_w(fileid));
196
197     strcatW(fileid, script_engineW);
198     res = RegOpenKeyW(HKEY_CLASSES_ROOT, fileid, &hkey);
199     if(res != ERROR_SUCCESS)
200         return FALSE;
201
202     size = sizeof(progid)/sizeof(WCHAR);
203     res = RegQueryValueW(hkey, NULL, progid, &size);
204     RegCloseKey(hkey);
205     if(res != ERROR_SUCCESS)
206         return FALSE;
207
208     WINE_TRACE("ProgID is %s\n", wine_dbgstr_w(progid));
209
210     hres = CLSIDFromProgID(progid, clsid);
211     return SUCCEEDED(hres);
212 }
213
214 static HRESULT create_engine(CLSID *clsid, IActiveScript **script_ret,
215         IActiveScriptParse **parser)
216 {
217     IActiveScript *script;
218     IUnknown *unk;
219     HRESULT hres;
220
221     hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
222             &IID_IUnknown, (void**)&unk);
223     if(FAILED(hres))
224         return FALSE;
225
226     hres = IUnknown_QueryInterface(unk, &IID_IActiveScript, (void**)&script);
227     IUnknown_Release(unk);
228     if(FAILED(hres))
229         return FALSE;
230
231     hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)parser);
232     if(FAILED(hres)) {
233         IActiveScript_Release(script);
234         return FALSE;
235     }
236
237     *script_ret = script;
238     return TRUE;
239 }
240
241 static HRESULT init_engine(IActiveScript *script, IActiveScriptParse *parser)
242 {
243     HRESULT hres;
244
245     if(!load_typelib())
246         return FALSE;
247
248     hres = IActiveScript_SetScriptSite(script, &script_site);
249     if(FAILED(hres))
250         return FALSE;
251
252     hres = IActiveScriptParse64_InitNew(parser);
253     if(FAILED(hres))
254         return FALSE;
255
256     hres = IActiveScript_AddNamedItem(script, wscriptW, SCRIPTITEM_ISVISIBLE);
257     if(FAILED(hres))
258         return FALSE;
259
260     hres = IActiveScript_AddNamedItem(script, wshW, SCRIPTITEM_ISVISIBLE);
261     if(FAILED(hres))
262         return FALSE;
263
264     hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_INITIALIZED);
265     return SUCCEEDED(hres);
266 }
267
268 static BSTR get_script_str(const WCHAR *filename)
269 {
270     const char *file_map;
271     HANDLE file, map;
272     DWORD size, len;
273     BSTR ret;
274
275     file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
276     if(file == INVALID_HANDLE_VALUE)
277         return NULL;
278
279     size = GetFileSize(file, NULL);
280     map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
281     CloseHandle(file);
282     if(map == INVALID_HANDLE_VALUE)
283         return NULL;
284
285     file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
286     CloseHandle(map);
287     if(!file_map)
288         return NULL;
289
290     len = MultiByteToWideChar(CP_ACP, 0, file_map, size, NULL, 0);
291     ret = SysAllocStringLen(NULL, len);
292     MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len);
293
294     UnmapViewOfFile(file_map);
295     return ret;
296 }
297
298 static void run_script(const WCHAR *filename, IActiveScript *script, IActiveScriptParse *parser)
299 {
300     BSTR text;
301     HRESULT hres;
302
303     text = get_script_str(filename);
304     if(!text) {
305         WINE_FIXME("Could not get script text\n");
306         return;
307     }
308
309     hres = IActiveScriptParse64_ParseScriptText(parser, text, NULL, NULL, NULL, 1, 1,
310             SCRIPTTEXT_HOSTMANAGESSOURCE|SCRIPTITEM_ISVISIBLE, NULL, NULL);
311     SysFreeString(text);
312     if(FAILED(hres)) {
313         WINE_FIXME("ParseScriptText failed: %08x\n", hres);
314         return;
315     }
316
317     hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED);
318     if(FAILED(hres))
319         WINE_FIXME("SetScriptState failed: %08x\n", hres);
320 }
321
322 int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow)
323 {
324     const WCHAR *ext, *filename = NULL;
325     IActiveScriptParse *parser;
326     IActiveScript *script;
327     WCHAR **argv;
328     CLSID clsid;
329     int argc, i;
330     DWORD res;
331
332     WINE_TRACE("(%p %p %s %x)\n", hInst, hPrevInst, wine_dbgstr_w(cmdline), cmdshow);
333
334     argv = CommandLineToArgvW(cmdline, &argc);
335     if(!argv)
336         return 1;
337
338     for(i=0; i<argc; i++) {
339         if(*argv[i] == '/' || *argv[i] == '-') {
340             WINE_FIXME("Unsupported argument %s\n", wine_dbgstr_w(argv[i]));
341         }else {
342             filename = argv[i];
343             break;
344         }
345     }
346
347     if(!filename) {
348         WINE_FIXME("No file name specified\n");
349         return 1;
350     }
351     res = GetFullPathNameW(filename, sizeof(scriptFullName)/sizeof(WCHAR), scriptFullName, NULL);
352     if(!res || res > sizeof(scriptFullName)/sizeof(WCHAR))
353         return 1;
354
355     ext = strchrW(filename, '.');
356     if(!ext)
357         ext = filename;
358     if(!get_engine_clsid(ext, &clsid)) {
359         WINE_FIXME("Could not find engine for %s\n", wine_dbgstr_w(ext));
360         return 1;
361     }
362
363     CoInitialize(NULL);
364
365     if(!create_engine(&clsid, &script, &parser)) {
366         WINE_FIXME("Could not create script engine\n");
367         CoUninitialize();
368         return 1;
369     }
370
371     if(init_engine(script, parser)) {
372         run_script(filename, script, parser);
373         IActiveScript_Close(script);
374         ITypeInfo_Release(host_ti);
375     }else {
376         WINE_FIXME("Script initialization failed\n");
377     }
378
379     IActiveScript_Release(script);
380     IUnknown_Release(parser);
381
382     CoUninitialize();
383
384     return 0;
385 }