mscoree_main.c 26.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Implementation of mscoree.dll
 * Microsoft Component Object Runtime Execution Engine
 *
 * Copyright 2006 Paul Chitescu
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

24
#define COBJMACROS
25 26
#include "windef.h"
#include "winbase.h"
27
#include "winuser.h"
28
#include "winnls.h"
29
#include "winreg.h"
30
#include "ole2.h"
31
#include "ocidl.h"
32
#include "shellapi.h"
33
#include "strongname.h"
34

35
#include "initguid.h"
36
#include "msxml2.h"
37
#include "corerror.h"
38
#include "cor.h"
39
#include "mscoree.h"
40 41
#include "corhdr.h"
#include "cordebug.h"
42
#include "metahost.h"
43
#include "fusion.h"
44
#include "wine/list.h"
45
#include "mscoree_private.h"
46
#include "rpcproxy.h"
47

48 49 50
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
51
WINE_DECLARE_DEBUG_CHANNEL(winediag);
52

53 54 55 56 57 58 59 60
struct print_handler_tls
{
    int length;
    char buffer[1018];
};

static DWORD print_tls_index = TLS_OUT_OF_INDEXES;

61 62
typedef HRESULT (*fnCreateInstance)(REFIID riid, LPVOID *ppObj);

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
char *WtoA(LPCWSTR wstr)
{
    int length;
    char *result;

    length = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);

    result = HeapAlloc(GetProcessHeap(), 0, length);

    if (result)
        WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, length, NULL, NULL);

    return result;
}

78 79
static BOOL get_install_root(LPWSTR install_dir)
{
80 81
    static const WCHAR dotnet_key[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','.','N','E','T','F','r','a','m','e','w','o','r','k','\\',0};
    static const WCHAR install_root[] = {'I','n','s','t','a','l','l','R','o','o','t',0};
82 83 84 85 86 87 88

    DWORD len;
    HKEY key;

    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, dotnet_key, 0, KEY_READ, &key))
        return FALSE;

89
    len = MAX_PATH * sizeof(WCHAR);
90 91 92 93 94 95 96 97 98 99
    if (RegQueryValueExW(key, install_root, 0, NULL, (LPBYTE)install_dir, &len))
    {
        RegCloseKey(key);
        return FALSE;
    }
    RegCloseKey(key);

    return TRUE;
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
typedef struct mscorecf
{
    IClassFactory    IClassFactory_iface;
    LONG ref;

    fnCreateInstance pfnCreateInstance;

    CLSID clsid;
} mscorecf;

static inline mscorecf *impl_from_IClassFactory( IClassFactory *iface )
{
    return CONTAINING_RECORD(iface, mscorecf, IClassFactory_iface);
}

static HRESULT WINAPI mscorecf_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppobj )
{
    TRACE("%s %p\n", debugstr_guid(riid), ppobj);

    if (IsEqualGUID(riid, &IID_IUnknown) ||
        IsEqualGUID(riid, &IID_IClassFactory))
    {
        IClassFactory_AddRef( iface );
        *ppobj = iface;
        return S_OK;
    }

    ERR("interface %s not implemented\n", debugstr_guid(riid));
    return E_NOINTERFACE;
}

static ULONG WINAPI mscorecf_AddRef(IClassFactory *iface )
{
    mscorecf *This = impl_from_IClassFactory(iface);
    ULONG ref = InterlockedIncrement(&This->ref);

136
    TRACE("%p ref=%lu\n", This, ref);
137 138 139 140 141 142 143 144 145

    return ref;
}

static ULONG WINAPI mscorecf_Release(IClassFactory *iface )
{
    mscorecf *This = impl_from_IClassFactory(iface);
    ULONG ref = InterlockedDecrement(&This->ref);

146
    TRACE("%p ref=%lu\n", This, ref);
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178

    if (ref == 0)
    {
        HeapFree(GetProcessHeap(), 0, This);
    }

    return ref;
}

static HRESULT WINAPI mscorecf_CreateInstance(IClassFactory *iface,LPUNKNOWN pOuter,
                            REFIID riid, LPVOID *ppobj )
{
    mscorecf *This = impl_from_IClassFactory( iface );
    HRESULT hr;
    IUnknown *punk;

    TRACE("%p %s %p\n", pOuter, debugstr_guid(riid), ppobj );

    *ppobj = NULL;

    if (pOuter)
        return CLASS_E_NOAGGREGATION;

    hr = This->pfnCreateInstance( &This->clsid, (LPVOID*) &punk );
    if (SUCCEEDED(hr))
    {
        hr = IUnknown_QueryInterface( punk, riid, ppobj );

        IUnknown_Release( punk );
    }
    else
    {
179
        WARN("Cannot create an instance object. 0x%08lx\n", hr);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
    }
    return hr;
}

static HRESULT WINAPI mscorecf_LockServer(IClassFactory *iface, BOOL dolock)
{
    FIXME("(%p)->(%d),stub!\n",iface,dolock);
    return S_OK;
}

static const struct IClassFactoryVtbl mscorecf_vtbl =
{
    mscorecf_QueryInterface,
    mscorecf_AddRef,
    mscorecf_Release,
    mscorecf_CreateInstance,
    mscorecf_LockServer
};

199 200 201 202 203
HRESULT WINAPI CorBindToRuntimeHost(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor,
                                    LPCWSTR pwszHostConfigFile, VOID *pReserved,
                                    DWORD startupFlags, REFCLSID rclsid,
                                    REFIID riid, LPVOID *ppv)
{
204 205 206
    HRESULT ret;
    ICLRRuntimeInfo *info;

207
    TRACE("(%s, %s, %s, %p, %ld, %s, %s, %p)\n", debugstr_w(pwszVersion),
208
          debugstr_w(pwszBuildFlavor), debugstr_w(pwszHostConfigFile), pReserved,
209
          startupFlags, debugstr_guid(rclsid), debugstr_guid(riid), ppv);
210

211 212
    *ppv = NULL;

213
    ret = get_runtime_info(NULL, pwszVersion, pwszHostConfigFile, NULL, startupFlags, 0, TRUE, &info);
214 215

    if (SUCCEEDED(ret))
216
    {
217 218 219
        ret = ICLRRuntimeInfo_GetInterface(info, rclsid, riid, ppv);

        ICLRRuntimeInfo_Release(info);
220 221
    }

222
    return ret;
223 224
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
void CDECL mono_print_handler_fn(const char *string, INT is_stdout)
{
    struct print_handler_tls *tls = TlsGetValue(print_tls_index);

    if (!tls)
    {
        tls = HeapAlloc(GetProcessHeap(), 0, sizeof(*tls));
        tls->length = 0;
        TlsSetValue(print_tls_index, tls);
    }

    while (*string)
    {
        int remaining_buffer = sizeof(tls->buffer) - tls->length;
        int length = strlen(string);
        const char *newline = memchr(string, '\n', min(length, remaining_buffer));

        if (newline)
        {
            length = newline - string + 1;
            wine_dbg_printf("%.*s%.*s", tls->length, tls->buffer, length, string);
            tls->length = 0;
            string += length;
        }
        else if (length > remaining_buffer)
        {
            /* this would overflow Wine's debug buffer */
            wine_dbg_printf("%.*s%.*s\n", tls->length, tls->buffer, remaining_buffer, string);
            tls->length = 0;
            string += remaining_buffer;
        }
        else
        {
            memcpy(tls->buffer + tls->length, string, length);
            tls->length += length;
            break;
        }
    }
}

265 266
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
267
    TRACE("(%p, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);
268 269 270 271

    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
272
        runtimehost_init();
273 274 275 276 277 278 279 280 281 282

        print_tls_index = TlsAlloc();

        if (print_tls_index == TLS_OUT_OF_INDEXES)
            return FALSE;

        break;
    case DLL_THREAD_DETACH:
        if (print_tls_index != TLS_OUT_OF_INDEXES)
            HeapFree(GetProcessHeap(), 0, TlsGetValue(print_tls_index));
283 284
        break;
    case DLL_PROCESS_DETACH:
285
        expect_no_runtimes();
286 287
        if (lpvReserved) break; /* process is terminating */
        runtimehost_uninit();
288 289 290 291 292
        if (print_tls_index != TLS_OUT_OF_INDEXES)
        {
            HeapFree(GetProcessHeap(), 0, TlsGetValue(print_tls_index));
            TlsFree(print_tls_index);
        }
293 294 295 296 297
        break;
    }
    return TRUE;
}

298
__int32 WINAPI _CorExeMain2(PBYTE ptrMemory, DWORD cntMemory, LPWSTR imageName, LPWSTR loaderName, LPWSTR cmdLine)
299
{
300
    TRACE("(%p, %lu, %s, %s, %s)\n", ptrMemory, cntMemory, debugstr_w(imageName), debugstr_w(loaderName), debugstr_w(cmdLine));
301 302 303 304
    FIXME("Directly running .NET applications not supported.\n");
    return -1;
}

305 306
void WINAPI CorExitProcess(int exitCode)
{
307
    TRACE("(%x)\n", exitCode);
308
    CLRMetaHost_ExitProcess(0, exitCode);
309 310
}

311
VOID WINAPI _CorImageUnloading(PVOID imageBase)
312 313 314 315
{
    TRACE("(%p): stub\n", imageBase);
}

316
HRESULT WINAPI _CorValidateImage(PVOID* imageBase, LPCWSTR imageName)
317 318 319 320
{
    TRACE("(%p, %s): stub\n", imageBase, debugstr_w(imageName));
    return E_FAIL;
}
321

322 323
HRESULT WINAPI GetCORSystemDirectory(LPWSTR pbuffer, DWORD cchBuffer, DWORD *dwLength)
{
324 325
    ICLRRuntimeInfo *info;
    HRESULT ret;
326

327
    TRACE("(%p, %ld, %p)!\n", pbuffer, cchBuffer, dwLength);
328

329
    if (!dwLength || !pbuffer)
330 331
        return E_POINTER;

332
    ret = get_runtime_info(NULL, NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
333

334
    if (SUCCEEDED(ret))
335
    {
336 337
        *dwLength = cchBuffer;
        ret = ICLRRuntimeInfo_GetRuntimeDirectory(info, pbuffer, dwLength);
338

339
        ICLRRuntimeInfo_Release(info);
340
    }
341

342
    return ret;
343 344
}

345 346
HRESULT WINAPI GetCORVersion(LPWSTR pbuffer, DWORD cchBuffer, DWORD *dwLength)
{
347 348
    ICLRRuntimeInfo *info;
    HRESULT ret;
349

350
    TRACE("(%p, %ld, %p)!\n", pbuffer, cchBuffer, dwLength);
351

352
    if (!dwLength || !pbuffer)
353 354
        return E_POINTER;

355
    ret = get_runtime_info(NULL, NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
356

357 358 359 360
    if (SUCCEEDED(ret))
    {
        *dwLength = cchBuffer;
        ret = ICLRRuntimeInfo_GetVersionString(info, pbuffer, dwLength);
361

362 363
        ICLRRuntimeInfo_Release(info);
    }
364

365
    return ret;
366
}
367

368 369 370 371 372 373 374 375 376 377
HRESULT WINAPI CorIsLatestSvc(int *unk1, int *unk2)
{
    ERR_(winediag)("If this function is called, it is likely the result of a broken .NET installation\n");

    if (!unk1 || !unk2)
        return E_POINTER;

    return S_OK;
}

378 379 380 381 382 383 384
HRESULT WINAPI CorGetSvc(void *unk)
{
    ERR_(winediag)("If this function is called, it is likely the result of a broken .NET installation\n");

    return E_NOTIMPL;
}

385 386 387 388
HRESULT WINAPI GetRequestedRuntimeInfo(LPCWSTR pExe, LPCWSTR pwszVersion, LPCWSTR pConfigurationFile,
    DWORD startupFlags, DWORD runtimeInfoFlags, LPWSTR pDirectory, DWORD dwDirectory, DWORD *dwDirectoryLength,
    LPWSTR pVersion, DWORD cchBuffer, DWORD *dwlength)
{
389
    HRESULT ret;
390 391
    ICLRRuntimeInfo *info;
    DWORD length_dummy;
392

393
    TRACE("(%s, %s, %s, 0x%08lx, 0x%08lx, %p, 0x%08lx, %p, %p, 0x%08lx, %p)\n", debugstr_w(pExe),
394 395
          debugstr_w(pwszVersion), debugstr_w(pConfigurationFile), startupFlags, runtimeInfoFlags, pDirectory,
          dwDirectory, dwDirectoryLength, pVersion, cchBuffer, dwlength);
396

397
    if (!dwDirectoryLength) dwDirectoryLength = &length_dummy;
398

399
    if (!dwlength) dwlength = &length_dummy;
400

401
    ret = get_runtime_info(pExe, pwszVersion, pConfigurationFile, NULL, startupFlags, runtimeInfoFlags, TRUE, &info);
402

403 404 405 406
    if (SUCCEEDED(ret))
    {
        *dwlength = cchBuffer;
        ret = ICLRRuntimeInfo_GetVersionString(info, pVersion, dwlength);
407

408
        if (SUCCEEDED(ret))
409
        {
410 411 412
            if(pwszVersion)
                pVersion[0] = pwszVersion[0];

413 414
            *dwDirectoryLength = dwDirectory;
            ret = ICLRRuntimeInfo_GetRuntimeDirectory(info, pDirectory, dwDirectoryLength);
415
        }
416 417

        ICLRRuntimeInfo_Release(info);
418
    }
419

420
    return ret;
421 422
}

423 424
HRESULT WINAPI GetRequestedRuntimeVersion(LPWSTR pExe, LPWSTR pVersion, DWORD cchBuffer, DWORD *dwlength)
{
425
    TRACE("(%s, %p, %ld, %p)\n", debugstr_w(pExe), pVersion, cchBuffer, dwlength);
426 427 428 429 430 431 432

    if(!dwlength)
        return E_POINTER;

    return GetRequestedRuntimeInfo(pExe, NULL, NULL, 0, 0, NULL, 0, NULL, pVersion, cchBuffer, dwlength);
}

433 434 435 436 437 438
HRESULT WINAPI GetRealProcAddress(LPCSTR procname, void **ppv)
{
    FIXME("(%s, %p)\n", debugstr_a(procname), ppv);
    return CLR_E_SHIM_RUNTIMEEXPORT;
}

439 440
HRESULT WINAPI GetFileVersion(LPCWSTR szFilename, LPWSTR szBuffer, DWORD cchBuffer, DWORD *dwLength)
{
441
    TRACE("(%s, %p, %ld, %p)\n", debugstr_w(szFilename), szBuffer, cchBuffer, dwLength);
442 443 444 445 446 447 448 449

    if (!szFilename || !dwLength)
        return E_POINTER;

    *dwLength = cchBuffer;
    return CLRMetaHost_GetVersionFromFile(0, szFilename, szBuffer, dwLength);
}

450 451
HRESULT WINAPI LoadLibraryShim( LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE * phModDll)
{
452 453 454 455 456 457
    HRESULT ret=S_OK;
    WCHAR dll_filename[MAX_PATH];
    WCHAR version[MAX_PATH];
    static const WCHAR default_version[] = {'v','1','.','1','.','4','3','2','2',0};
    static const WCHAR slash[] = {'\\',0};
    DWORD dummy;
458

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
    TRACE("(%p %s, %p, %p, %p)\n", szDllName, debugstr_w(szDllName), szVersion, pvReserved, phModDll);

    if (!szDllName || !phModDll)
        return E_POINTER;

    if (!get_install_root(dll_filename))
    {
        ERR("error reading registry key for installroot\n");
        dll_filename[0] = 0;
    }
    else
    {
        if (!szVersion)
        {
            ret = GetCORVersion(version, MAX_PATH, &dummy);
            if (SUCCEEDED(ret))
                szVersion = version;
            else
                szVersion = default_version;
        }
479 480
        lstrcatW(dll_filename, szVersion);
        lstrcatW(dll_filename, slash);
481 482
    }

483
    lstrcatW(dll_filename, szDllName);
484 485 486 487

    *phModDll = LoadLibraryW(dll_filename);

    return *phModDll ? S_OK : E_HANDLE;
488 489
}

490 491 492 493 494 495
HRESULT WINAPI LockClrVersion(FLockClrVersionCallback hostCallback, FLockClrVersionCallback *pBeginHostSetup, FLockClrVersionCallback *pEndHostSetup)
{
    FIXME("(%p %p %p): stub\n", hostCallback, pBeginHostSetup, pEndHostSetup);
    return S_OK;
}

496 497
HRESULT WINAPI CoInitializeCor(DWORD fFlags)
{
498
    FIXME("(0x%08lx): stub\n", fFlags);
499 500 501 502 503
    return S_OK;
}

HRESULT WINAPI GetAssemblyMDImport(LPCWSTR szFileName, REFIID riid, IUnknown **ppIUnk)
{
504
    FIXME("(%p %s, %s, %p): stub\n", szFileName, debugstr_w(szFileName), debugstr_guid(riid), *ppIUnk);
505 506
    return ERROR_CALL_NOT_IMPLEMENTED;
}
507 508 509

HRESULT WINAPI GetVersionFromProcess(HANDLE hProcess, LPWSTR pVersion, DWORD cchBuffer, DWORD *dwLength)
{
510
    FIXME("(%p, %p, %ld, %p): stub\n", hProcess, pVersion, cchBuffer, dwLength);
511 512
    return E_NOTIMPL;
}
513

514 515 516 517 518 519 520
HRESULT WINAPI LoadStringRCEx(LCID culture, UINT resId, LPWSTR pBuffer, int iBufLen, int bQuiet, int* pBufLen)
{
    HRESULT res = S_OK;
    if ((iBufLen <= 0) || !pBuffer)
        return E_INVALIDARG;
    pBuffer[0] = 0;
    if (resId) {
521
        FIXME("(%ld, %x, %p, %d, %d, %p): semi-stub\n", culture, resId, pBuffer, iBufLen, bQuiet, pBufLen);
522 523 524 525 526 527 528 529 530 531 532 533 534 535
        res = E_NOTIMPL;
    }
    else
        res = E_FAIL;
    if (pBufLen)
        *pBufLen = lstrlenW(pBuffer);
    return res;
}

HRESULT WINAPI LoadStringRC(UINT resId, LPWSTR pBuffer, int iBufLen, int bQuiet)
{
    return LoadStringRCEx(-1, resId, pBuffer, iBufLen, bQuiet, NULL);
}

536 537 538
HRESULT WINAPI CorBindToRuntimeEx(LPWSTR szVersion, LPWSTR szBuildFlavor, DWORD nflags, REFCLSID rslsid,
                                  REFIID riid, LPVOID *ppv)
{
539 540 541
    HRESULT ret;
    ICLRRuntimeInfo *info;

542
    TRACE("%s %s %ld %s %s %p\n", debugstr_w(szVersion), debugstr_w(szBuildFlavor), nflags, debugstr_guid( rslsid ),
543 544
          debugstr_guid( riid ), ppv);

545 546
    *ppv = NULL;

547
    ret = get_runtime_info(NULL, szVersion, NULL, NULL, nflags, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
548 549

    if (SUCCEEDED(ret))
550
    {
551 552 553
        ret = ICLRRuntimeInfo_GetInterface(info, rslsid, riid, ppv);

        ICLRRuntimeInfo_Release(info);
554
    }
555 556

    return ret;
557 558
}

559 560
HRESULT WINAPI CorBindToCurrentRuntime(LPCWSTR filename, REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
561 562 563 564 565 566 567
    HRESULT ret;
    ICLRRuntimeInfo *info;

    TRACE("(%s, %s, %s, %p)\n", debugstr_w(filename), debugstr_guid(rclsid), debugstr_guid(riid), ppv);

    *ppv = NULL;

568
    ret = get_runtime_info(NULL, NULL, filename, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
569 570 571 572 573 574 575 576 577

    if (SUCCEEDED(ret))
    {
        ret = ICLRRuntimeInfo_GetInterface(info, rclsid, riid, ppv);

        ICLRRuntimeInfo_Release(info);
    }

    return ret;
578 579
}

580 581
STDAPI ClrCreateManagedInstance(LPCWSTR pTypeName, REFIID riid, void **ppObject)
{
582 583 584 585 586 587 588 589 590
    HRESULT ret;
    ICLRRuntimeInfo *info;
    RuntimeHost *host;
    MonoObject *obj;
    IUnknown *unk;

    TRACE("(%s,%s,%p)\n", debugstr_w(pTypeName), debugstr_guid(riid), ppObject);

    /* FIXME: How to determine which runtime version to use? */
591
    ret = get_runtime_info(NULL, NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, TRUE, &info);
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

    if (SUCCEEDED(ret))
    {
        ret = ICLRRuntimeInfo_GetRuntimeHost(info, &host);

        ICLRRuntimeInfo_Release(info);
    }

    if (SUCCEEDED(ret))
        ret = RuntimeHost_CreateManagedInstance(host, pTypeName, NULL, &obj);

    if (SUCCEEDED(ret))
        ret = RuntimeHost_GetIUnknownForObject(host, obj, &unk);

    if (SUCCEEDED(ret))
    {
        ret = IUnknown_QueryInterface(unk, riid, ppObject);
        IUnknown_Release(unk);
    }

    return ret;
613 614
}

615
BOOLEAN WINAPI StrongNameSignatureVerification(LPCWSTR filename, DWORD inFlags, DWORD *pOutFlags)
616
{
617
    FIXME("(%s, 0x%lX, %p): stub\n", debugstr_w(filename), inFlags, pOutFlags);
618 619 620
    return FALSE;
}

621
BOOLEAN WINAPI StrongNameSignatureVerificationEx(LPCWSTR filename, BOOLEAN forceVerification, BOOLEAN *pVerified)
622 623
{
    FIXME("(%s, %u, %p): stub\n", debugstr_w(filename), forceVerification, pVerified);
624 625
    *pVerified = TRUE;
    return TRUE;
626 627
}

628
HRESULT WINAPI CreateDebuggingInterfaceFromVersion(int nDebugVersion, LPCWSTR version, IUnknown **ppv)
629
{
630
    static const WCHAR v2_0[] = {'v','2','.','0','.','5','0','7','2','7',0};
631 632 633 634 635 636 637 638 639 640 641 642 643
    HRESULT hr = E_FAIL;
    ICLRRuntimeInfo *runtimeinfo;

    if(nDebugVersion < 1 || nDebugVersion > 4)
        return E_INVALIDARG;

    TRACE("(%d %s, %p): stub\n", nDebugVersion, debugstr_w(version), ppv);

    if(!ppv)
        return E_INVALIDARG;

    *ppv = NULL;

644
    if(wcscmp(version, v2_0) != 0)
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
    {
        FIXME("Currently .NET Version '%s' not support.\n", debugstr_w(version));
        return E_INVALIDARG;
    }

    if(nDebugVersion != 3)
        return E_INVALIDARG;

    hr = CLRMetaHost_GetRuntime(0, version, &IID_ICLRRuntimeInfo, (void**)&runtimeinfo);
    if(hr == S_OK)
    {
        hr = ICLRRuntimeInfo_GetInterface(runtimeinfo, &CLSID_CLRDebuggingLegacy, &IID_ICorDebug, (void**)ppv);

        ICLRRuntimeInfo_Release(runtimeinfo);
    }

    if(!*ppv)
        return E_FAIL;

    return hr;
665 666
}

667 668
HRESULT WINAPI CLRCreateInstance(REFCLSID clsid, REFIID riid, LPVOID *ppInterface)
{
669
    TRACE("(%s,%s,%p)\n", debugstr_guid(clsid), debugstr_guid(riid), ppInterface);
670

671 672
    if (IsEqualGUID(clsid, &CLSID_CLRMetaHost))
        return CLRMetaHost_CreateInstance(riid, ppInterface);
673 674
    if (IsEqualGUID(clsid, &CLSID_CLRMetaHostPolicy))
        return CLRMetaHostPolicy_CreateInstance(riid, ppInterface);
675 676 677 678

    FIXME("not implemented for class %s\n", debugstr_guid(clsid));

    return CLASS_E_CLASSNOTAVAILABLE;
679 680
}

681 682 683 684 685 686 687
HRESULT WINAPI CreateInterface(REFCLSID clsid, REFIID riid, LPVOID *ppInterface)
{
    TRACE("(%s,%s,%p)\n", debugstr_guid(clsid), debugstr_guid(riid), ppInterface);

    return CLRCreateInstance(clsid, riid, ppInterface);
}

688 689
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
690 691 692 693 694
    mscorecf *This;
    HRESULT hr;

    TRACE("(%s, %s, %p): stub\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);

695 696 697
    if(!ppv)
        return E_INVALIDARG;

698 699 700
    This = HeapAlloc(GetProcessHeap(), 0, sizeof(mscorecf));

    This->IClassFactory_iface.lpVtbl = &mscorecf_vtbl;
701
    This->pfnCreateInstance = create_monodata;
702 703 704 705 706 707 708
    This->ref = 1;
    This->clsid = *rclsid;

    hr = IClassFactory_QueryInterface( &This->IClassFactory_iface, riid, ppv );
    IClassFactory_Release(&This->IClassFactory_iface);

    return hr;
709 710
}

711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
static void parse_msi_version_string(const char *version, int *parts)
{
    const char *minor_start, *build_start;

    parts[0] = atoi(version);

    parts[1] = parts[2] = 0;

    minor_start = strchr(version, '.');
    if (minor_start)
    {
        minor_start++;
        parts[1] = atoi(minor_start);

        build_start = strchr(minor_start, '.');
        if (build_start)
            parts[2] = atoi(build_start+1);
    }
}

731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
static int compare_versions(const char *a, const char *b)
{
    int a_parts[3], b_parts[3], i;

    parse_msi_version_string(a, a_parts);
    parse_msi_version_string(b, b_parts);

    for (i=0; i<3; i++)
        if (a_parts[i] != b_parts[i])
            return a_parts[i] - b_parts[i];

    return 0;
}

static BOOL invoke_appwiz(void)
{
    PROCESS_INFORMATION pi;
    STARTUPINFOW si;
    WCHAR app[MAX_PATH];
    WCHAR *args;
    LONG len;
    BOOL ret;

    static const WCHAR controlW[] = {'\\','c','o','n','t','r','o','l','.','e','x','e',0};
    static const WCHAR argsW[] =
        {' ','a','p','p','w','i','z','.','c','p','l',' ','i','n','s','t','a','l','l','_','m','o','n','o',0};

    len = GetSystemDirectoryW(app, MAX_PATH - ARRAY_SIZE(controlW));
    memcpy(app+len, controlW, sizeof(controlW));

    args = HeapAlloc(GetProcessHeap(), 0, (len*sizeof(WCHAR) + sizeof(controlW) + sizeof(argsW)));
    if(!args)
        return FALSE;

    memcpy(args, app, len*sizeof(WCHAR) + sizeof(controlW));
    memcpy(args + len + ARRAY_SIZE(controlW) - 1, argsW, sizeof(argsW));

    TRACE("starting %s\n", debugstr_w(args));

    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);
    ret = CreateProcessW(app, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    HeapFree(GetProcessHeap(), 0, args);
    if (ret) {
        CloseHandle(pi.hThread);
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
    }

    return ret;
}

783
static BOOL get_support_msi(LPCWSTR mono_path, LPWSTR msi_path)
784
{
785
    static const WCHAR support_msi_relative[] = {'\\','s','u','p','p','o','r','t','\\','w','i','n','e','m','o','n','o','-','s','u','p','p','o','r','t','.','m','s','i',0};
786 787 788 789 790 791 792 793 794 795 796 797
    UINT (WINAPI *pMsiOpenPackageW)(LPCWSTR,ULONG*);
    UINT (WINAPI *pMsiGetProductPropertyA)(ULONG,LPCSTR,LPSTR,LPDWORD);
    UINT (WINAPI *pMsiCloseHandle)(ULONG);
    HMODULE hmsi = NULL;
    char versionstringbuf[15];
    UINT res;
    DWORD buffer_size;
    ULONG msiproduct;
    BOOL ret=FALSE;

    hmsi = GetModuleHandleA("msi");

798 799
    lstrcpyW(msi_path, mono_path);
    lstrcatW(msi_path, support_msi_relative);
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831

    pMsiOpenPackageW = (void*)GetProcAddress(hmsi, "MsiOpenPackageW");

    res = pMsiOpenPackageW(msi_path, &msiproduct);

    if (res == ERROR_SUCCESS)
    {
        buffer_size = sizeof(versionstringbuf);

        pMsiGetProductPropertyA = (void*)GetProcAddress(hmsi, "MsiGetProductPropertyA");

        res = pMsiGetProductPropertyA(msiproduct, "ProductVersion", versionstringbuf, &buffer_size);

        pMsiCloseHandle = (void*)GetProcAddress(hmsi, "MsiCloseHandle");

        pMsiCloseHandle(msiproduct);
    }

    if (res == ERROR_SUCCESS) {
        TRACE("found support msi version %s at %s\n", versionstringbuf, debugstr_w(msi_path));

        if (compare_versions(WINE_MONO_VERSION, versionstringbuf) <= 0)
        {
            ret = TRUE;
        }
    }

    return ret;
}

static BOOL install_wine_mono(void)
{
832
    BOOL is_wow64 = FALSE;
833 834
    HMODULE hmsi = NULL;
    HRESULT initresult = E_FAIL;
835
    UINT (WINAPI *pMsiEnumRelatedProductsA)(LPCSTR,DWORD,DWORD,LPSTR);
836
    UINT (WINAPI *pMsiGetProductInfoA)(LPCSTR,LPCSTR,LPSTR,DWORD*);
837
    UINT (WINAPI *pMsiInstallProductW)(LPCWSTR,LPCWSTR);
838
    char versionstringbuf[15];
839
    char productcodebuf[39];
840 841 842
    UINT res;
    DWORD buffer_size;
    BOOL ret;
843 844
    WCHAR mono_path[MAX_PATH];
    WCHAR support_msi_path[MAX_PATH];
845

846
    static const char* mono_upgrade_code = "{DE624609-C6B5-486A-9274-EF0B854F6BC5}";
847 848 849 850 851 852 853 854 855

    IsWow64Process(GetCurrentProcess(), &is_wow64);

    if (is_wow64)
    {
        TRACE("not installing mono in wow64 process\n");
        return TRUE;
    }

856 857
    TRACE("searching for mono runtime\n");

858
    if (!get_mono_path(mono_path, FALSE))
859 860 861 862 863 864 865
    {
        TRACE("mono runtime not found\n");
        return invoke_appwiz();
    }

    TRACE("mono runtime is at %s\n", debugstr_w(mono_path));

866 867 868 869 870 871 872 873
    hmsi = LoadLibraryA("msi");

    if (!hmsi)
    {
        ERR("couldn't load msi.dll\n");
        return FALSE;
    }

874
    pMsiEnumRelatedProductsA = (void*)GetProcAddress(hmsi, "MsiEnumRelatedProductsA");
875

876
    res = pMsiEnumRelatedProductsA(mono_upgrade_code, 0, 0, productcodebuf);
877

878 879 880 881 882 883 884 885 886 887 888 889
    if (res == ERROR_SUCCESS)
    {
        pMsiGetProductInfoA = (void*)GetProcAddress(hmsi, "MsiGetProductInfoA");

        buffer_size = sizeof(versionstringbuf);

        res = pMsiGetProductInfoA(productcodebuf, "VersionString", versionstringbuf, &buffer_size);
    }
    else if (res != ERROR_NO_MORE_ITEMS)
    {
        ERR("MsiEnumRelatedProducts failed, err=%u\n", res);
    }
890

891 892 893 894 895 896 897 898 899 900 901 902 903 904
    if (res == ERROR_SUCCESS)
    {
        TRACE("found installed support package %s\n", versionstringbuf);

        if (compare_versions(WINE_MONO_VERSION, versionstringbuf) <= 0)
        {
            TRACE("support package is at least %s, quitting\n", WINE_MONO_VERSION);
            ret = TRUE;
            goto end;
        }
    }

    initresult = CoInitialize(NULL);

905 906
    ret = get_support_msi(mono_path, support_msi_path);
    if (!ret)
907
    {
908 909 910
        /* Try looking outside c:\windows\mono */
        ret = (get_mono_path(mono_path, TRUE) &&
            get_support_msi(mono_path, support_msi_path));
911 912
    }

913 914 915
    if (ret)
    {
        TRACE("installing support msi\n");
916

917
        pMsiInstallProductW = (void*)GetProcAddress(hmsi, "MsiInstallProductW");
918

919
        res = pMsiInstallProductW(support_msi_path, NULL);
920

921 922 923 924
        if (res == ERROR_SUCCESS)
        {
            ret = TRUE;
            goto end;
925
        }
926 927
        else
            ERR("MsiInstallProduct failed, err=%i\n", res);
928 929
    }

930 931 932 933 934 935 936
    ret = invoke_appwiz();

end:
    if (hmsi)
        FreeLibrary(hmsi);
    if (SUCCEEDED(initresult))
        CoUninitialize();
937 938 939
    return ret;
}

940 941
HRESULT WINAPI DllRegisterServer(void)
{
942 943
    install_wine_mono();

944
    return __wine_register_resources();
945 946 947 948
}

HRESULT WINAPI DllUnregisterServer(void)
{
949
    return __wine_unregister_resources();
950 951
}

952 953 954 955 956
void WINAPI CoEEShutDownCOM(void)
{
    FIXME("stub.\n");
}

957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
INT WINAPI ND_RU1( const void *ptr, INT offset )
{
    return *((const BYTE *)ptr + offset);
}

INT WINAPI ND_RI2( const void *ptr, INT offset )
{
    return *(const SHORT *)((const BYTE *)ptr + offset);
}

INT WINAPI ND_RI4( const void *ptr, INT offset )
{
    return *(const INT *)((const BYTE *)ptr + offset);
}

INT64 WINAPI ND_RI8( const void *ptr, INT offset )
{
    return *(const INT64 *)((const BYTE *)ptr + offset);
}

void WINAPI ND_WU1( void *ptr, INT offset, BYTE val )
{
    *((BYTE *)ptr + offset) = val;
}

void WINAPI ND_WI2( void *ptr, INT offset, SHORT val )
{
    *(SHORT *)((BYTE *)ptr + offset) = val;
}

void WINAPI ND_WI4( void *ptr, INT offset, INT val )
{
    *(INT *)((BYTE *)ptr + offset) = val;
}

void WINAPI ND_WI8( void *ptr, INT offset, INT64 val )
{
    *(INT64 *)((BYTE *)ptr + offset) = val;
}

void WINAPI ND_CopyObjDst( const void *src, void *dst, INT offset, INT size )
{
    memcpy( (BYTE *)dst + offset, src, size );
}

void WINAPI ND_CopyObjSrc( const void *src, INT offset, void *dst, INT size )
{
    memcpy( dst, (const BYTE *)src + offset, size );
}