typelib.c 242 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *	TYPELIB
 *
 *	Copyright 1997	Marcus Meissner
5
 *		      1999  Rein Klazes
6
 *		      2000  Francois Jacques
7
 *		      2001  Huw D M Davies for CodeWeavers
8
 *		      2005  Robert Shearman, for CodeWeavers
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
22
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23
 *
24 25 26 27
 * --------------------------------------------------------------------------------------
 * Known problems (2000, Francois Jacques)
 *
 * - Tested using OLEVIEW (Platform SDK tool) only.
28 29 30
 *
 * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
 *   creating by doing a straight copy of the dispinterface instance and just changing
31
 *   its typekind. Pointed structures aren't copied - only the address of the pointers.
32
 *
33 34
 * - locale stuff is partially implemented but hasn't been tested.
 *
35
 * - typelib file is still read in its entirety, but it is released now.
36 37 38 39
 *
 * --------------------------------------------------------------------------------------
 *  Known problems left from previous implementation (1999, Rein Klazes) :
 *
40 41 42 43 44
 * -. Data structures are straightforward, but slow for look-ups.
 * -. (related) nothing is hashed
 * -. Most error return values are just guessed not checked with windows
 *      behaviour.
 * -. lousy fatal error handling
45
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
46 47
 */

48
#include "config.h"
Steven Edwards's avatar
Steven Edwards committed
49
#include "wine/port.h"
50

Alexandre Julliard's avatar
Alexandre Julliard committed
51 52
#include <stdlib.h>
#include <string.h>
53
#include <stdarg.h>
54
#include <stdio.h>
55
#include <ctype.h>
56

57
#define COBJMACROS
58 59
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
60

Alexandre Julliard's avatar
Alexandre Julliard committed
61
#include "winerror.h"
62
#include "windef.h"
63 64 65
#include "winbase.h"
#include "winnls.h"
#include "winreg.h"
66
#include "winuser.h"
67
#include "lzexpand.h"
68

69
#include "wine/unicode.h"
70
#include "objbase.h"
71
#include "typelib.h"
72
#include "wine/debug.h"
73
#include "variant.h"
74
#include "wine/list.h"
75

76 77
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(typelib);
78

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
typedef struct
{
    WORD     offset;
    WORD     length;
    WORD     flags;
    WORD     id;
    WORD     handle;
    WORD     usage;
} NE_NAMEINFO;

typedef struct
{
    WORD        type_id;   /* Type identifier */
    WORD        count;     /* Number of resources of this type */
    DWORD       resloader; /* SetResourceHandler() */
    /*
     * Name info array.
     */
} NE_TYPEINFO;

99
static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
100
static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
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
/****************************************************************************
 *              FromLExxx
 *
 * Takes p_iVal (which is in little endian) and returns it
 *   in the host machine's byte order.
 */
#ifdef WORDS_BIGENDIAN
static WORD FromLEWord(WORD p_iVal)
{
  return (((p_iVal & 0x00FF) << 8) |
	  ((p_iVal & 0xFF00) >> 8));
}


static DWORD FromLEDWord(DWORD p_iVal)
{
  return (((p_iVal & 0x000000FF) << 24) |
	  ((p_iVal & 0x0000FF00) <<  8) |
	  ((p_iVal & 0x00FF0000) >>  8) |
	  ((p_iVal & 0xFF000000) >> 24));
}
#else
#define FromLEWord(X)  (X)
#define FromLEDWord(X) (X)
#endif

128 129
#define DISPATCH_HREF_OFFSET 0x01000000
#define DISPATCH_HREF_MASK   0xff000000
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

/****************************************************************************
 *              FromLExxx
 *
 * Fix byte order in any structure if necessary
 */
#ifdef WORDS_BIGENDIAN
static void FromLEWords(void *p_Val, int p_iSize)
{
  WORD *Val = p_Val;

  p_iSize /= sizeof(WORD);

  while (p_iSize) {
    *Val = FromLEWord(*Val);
    Val++;
    p_iSize--;
  }
}


static void FromLEDWords(void *p_Val, int p_iSize)
{
  DWORD *Val = p_Val;

  p_iSize /= sizeof(DWORD);

  while (p_iSize) {
    *Val = FromLEDWord(*Val);
    Val++;
    p_iSize--;
  }
}
#else
#define FromLEWords(X,Y) /*nothing*/
#define FromLEDWords(X,Y) /*nothing*/
#endif

168 169 170
/*
 * Find a typelib key which matches a requested maj.min version.
 */
171
static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
172 173 174 175 176
{
    static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
    WCHAR buffer[60];
    char key_name[16];
    DWORD len, i;
177
    INT best_maj = -1, best_min = -1;
178 179 180 181 182 183 184 185 186 187 188 189 190 191
    HKEY hkey;

    memcpy( buffer, typelibW, sizeof(typelibW) );
    StringFromGUID2( guid, buffer + strlenW(buffer), 40 );

    if (RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ) != ERROR_SUCCESS)
        return FALSE;

    len = sizeof(key_name);
    i = 0;
    while (RegEnumKeyExA(hkey, i++, key_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
    {
        INT v_maj, v_min;

192
        if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
193
        {
194
            TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
195

196
            if (*wMaj == 0xffff && *wMin == 0xffff)
197
            {
198 199 200 201 202 203 204
                if (v_maj > best_maj) best_maj = v_maj;
                if (v_min > best_min) best_min = v_min;
            }
            else if (*wMaj == v_maj)
            {
                best_maj = v_maj;

205 206 207 208 209
                if (*wMin == v_min)
                {
                    best_min = v_min;
                    break; /* exact match */
                }
210
                if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
211 212 213 214 215
            }
        }
        len = sizeof(key_name);
    }
    RegCloseKey( hkey );
216 217 218 219 220 221 222 223 224 225 226 227 228 229

    TRACE("found best_maj %d, best_min %d\n", best_maj, best_min);

    if (*wMaj == 0xffff && *wMin == 0xffff)
    {
        if (best_maj >= 0 && best_min >= 0)
        {
            *wMaj = best_maj;
            *wMin = best_min;
            return TRUE;
        }
    }

    if (*wMaj == best_maj && best_min >= 0)
230 231 232 233 234 235 236
    {
        *wMin = best_min;
        return TRUE;
    }
    return FALSE;
}

237 238 239 240 241
/* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */
/* buffer must be at least 60 characters long */
static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer )
{
    static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0};
242
    static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267

    memcpy( buffer, TypelibW, sizeof(TypelibW) );
    StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
    sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin );
    return buffer;
}

/* get the path of an interface key, in the form "Interface\\<guid>" */
/* buffer must be at least 50 characters long */
static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer )
{
    static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0};

    memcpy( buffer, InterfaceW, sizeof(InterfaceW) );
    StringFromGUID2( guid, buffer + strlenW(buffer), 40 );
    return buffer;
}

/* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */
/* buffer must be at least 16 characters long */
static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer )
{
    static const WCHAR LcidFormatW[] = {'%','l','x','\\',0};
    static const WCHAR win16W[] = {'w','i','n','1','6',0};
    static const WCHAR win32W[] = {'w','i','n','3','2',0};
268
    static const WCHAR win64W[] = {'w','i','n','6','4',0};
269 270 271 272 273 274

    sprintfW( buffer, LcidFormatW, lcid );
    switch(syskind)
    {
    case SYS_WIN16: strcatW( buffer, win16W ); break;
    case SYS_WIN32: strcatW( buffer, win32W ); break;
275
    case SYS_WIN64: strcatW( buffer, win64W ); break;
276 277 278 279 280 281 282
    default:
        TRACE("Typelib is for unsupported syskind %i\n", syskind);
        return NULL;
    }
    return buffer;
}

283
static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
284

285

286 287 288
/* Get the path to a registered type library. Helper for QueryPathOfRegTypeLib. */
static HRESULT query_typelib_path( REFGUID guid, WORD wMaj, WORD wMin,
                                   SYSKIND syskind, LCID lcid, LPBSTR path )
289
{
290
    HRESULT hr = TYPE_E_LIBNOTREGISTERED;
291 292 293 294
    LCID myLCID = lcid;
    HKEY hkey;
    WCHAR buffer[60];
    WCHAR Path[MAX_PATH];
295
    LONG res;
296

297
    TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
298

299
    if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
300 301
    get_typelib_key( guid, wMaj, wMin, buffer );

302 303
    res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
    if (res == ERROR_FILE_NOT_FOUND)
304 305
    {
        TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
306 307 308 309 310 311
        return TYPE_E_LIBNOTREGISTERED;
    }
    else if (res != ERROR_SUCCESS)
    {
        TRACE_(typelib)("failed to open %s for read access\n", debugstr_w(buffer));
        return TYPE_E_REGISTRYACCESS;
312 313 314 315
    }

    while (hr != S_OK)
    {
Mike McCormack's avatar
Mike McCormack committed
316
        LONG dwPathLen = sizeof(Path);
317

318
        get_lcid_subkey( myLCID, syskind, buffer );
319 320

        if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
321
        {
322 323 324
            if (!lcid)
                break;
            else if (myLCID == lcid)
325 326 327 328
            {
                /* try with sub-langid */
                myLCID = SUBLANGID(lcid);
            }
329
            else if ((myLCID == SUBLANGID(lcid)) && myLCID)
330 331 332 333 334 335 336 337 338 339 340
            {
                /* try with system langid */
                myLCID = 0;
            }
            else
            {
                break;
            }
        }
        else
        {
341 342
            *path = SysAllocString( Path );
            hr = S_OK;
343 344
        }
    }
345
    RegCloseKey( hkey );
346
    TRACE_(typelib)("-- 0x%08x\n", hr);
347
    return hr;
Alexandre Julliard's avatar
Alexandre Julliard committed
348 349
}

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
/****************************************************************************
 *		QueryPathOfRegTypeLib	[OLEAUT32.164]
 *
 * Gets the path to a registered type library.
 *
 * PARAMS
 *  guid [I] referenced guid
 *  wMaj [I] major version
 *  wMin [I] minor version
 *  lcid [I] locale id
 *  path [O] path of typelib
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: If the type library is not registered then TYPE_E_LIBNOTREGISTERED
 *  or TYPE_E_REGISTRYACCESS if the type library registration key couldn't be
 *  opened.
 */
HRESULT WINAPI QueryPathOfRegTypeLib( REFGUID guid, WORD wMaj, WORD wMin, LCID lcid, LPBSTR path )
{
370 371 372 373 374
#ifdef _WIN64
    HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path );
    if(SUCCEEDED(hres))
        return hres;
#endif
375 376 377
    return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path );
}

378
/******************************************************************************
379
 * CreateTypeLib [OLEAUT32.160]  creates a typelib
380 381 382 383 384 385
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI CreateTypeLib(
Francois Gouget's avatar
Francois Gouget committed
386
	SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
387 388 389 390
) {
    FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
    return E_FAIL;
}
391

Alexandre Julliard's avatar
Alexandre Julliard committed
392
/******************************************************************************
393
 *		LoadTypeLib	[OLEAUT32.161]
394 395 396 397 398 399
 *
 * Loads a type library
 *
 * PARAMS
 *  szFile [I] Name of file to load from.
 *  pptLib [O] Pointer that receives ITypeLib object on success.
Alexandre Julliard's avatar
Alexandre Julliard committed
400 401 402 403
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
404 405 406
 *
 * SEE
 *  LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
Alexandre Julliard's avatar
Alexandre Julliard committed
407
 */
408
HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
409
{
410
    TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
411 412 413 414 415
    return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
}

/******************************************************************************
 *		LoadTypeLibEx	[OLEAUT32.183]
416
 *
417 418 419 420 421 422 423
 * Loads and optionally registers a type library
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI LoadTypeLibEx(
Francois Gouget's avatar
Francois Gouget committed
424
    LPCOLESTR szFile,  /* [in] Name of file to load from */
425
    REGKIND  regkind,  /* [in] Specify kind of registration */
426
    ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
Alexandre Julliard's avatar
Alexandre Julliard committed
427
{
428
    WCHAR szPath[MAX_PATH+1];
429
    HRESULT res;
430

431
    TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
432

433
    *pptLib = NULL;
434

435
    res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
436

437 438 439 440
    if (SUCCEEDED(res))
        switch(regkind)
        {
            case REGKIND_DEFAULT:
441
                /* don't register typelibs supplied with full path. Experimentation confirms the following */
442
                if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
443
                    (szFile[0] && (szFile[1] == ':'))) break;
444
                /* else fall-through */
445

446
            case REGKIND_REGISTER:
447
                if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
448 449 450 451 452 453 454 455 456
                {
                    IUnknown_Release(*pptLib);
                    *pptLib = 0;
                }
                break;
            case REGKIND_NONE:
                break;
        }

457
    TRACE(" returns %08x\n",res);
458
    return res;
Alexandre Julliard's avatar
Alexandre Julliard committed
459 460
}

461 462
/******************************************************************************
 *		LoadRegTypeLib	[OLEAUT32.162]
463 464 465 466 467 468 469 470 471 472 473 474 475 476
 *
 * Loads a registered type library.
 *
 * PARAMS
 *  rguid     [I] GUID of the registered type library.
 *  wVerMajor [I] major version.
 *  wVerMinor [I] minor version.
 *  lcid      [I] locale ID.
 *  ppTLib    [O] pointer that receives an ITypeLib object on success.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: Any HRESULT code returned from QueryPathOfRegTypeLib or
 *  LoadTypeLib.
477
 */
478
HRESULT WINAPI LoadRegTypeLib(
479 480 481 482 483
	REFGUID rguid,
	WORD wVerMajor,
	WORD wVerMinor,
	LCID lcid,
	ITypeLib **ppTLib)
484
{
485
    BSTR bstr=NULL;
486 487 488 489 490
    HRESULT res;

    *ppTLib = NULL;

    res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
491 492 493

    if(SUCCEEDED(res))
    {
494 495 496
        res= LoadTypeLib(bstr, ppTLib);
        SysFreeString(bstr);
    }
497 498 499

    TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);

500
    return res;
501
}
502 503


504 505 506 507 508 509 510
/* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */
static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0};
static const WCHAR FLAGSW[] = {'F','L','A','G','S',0};
static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0};
static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0};
static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};

Alexandre Julliard's avatar
Alexandre Julliard committed
511
/******************************************************************************
512
 *		RegisterTypeLib	[OLEAUT32.163]
513
 * Adds information about a type library to the System Registry
Alexandre Julliard's avatar
Alexandre Julliard committed
514 515
 * NOTES
 *    Docs: ITypeLib FAR * ptlib
516 517
 *    Docs: OLECHAR FAR* szFullPath
 *    Docs: OLECHAR FAR* szHelpDir
Alexandre Julliard's avatar
Alexandre Julliard committed
518 519 520 521 522
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
523
HRESULT WINAPI RegisterTypeLib(
524 525 526
     ITypeLib * ptlib,     /* [in] Pointer to the library*/
     OLECHAR * szFullPath, /* [in] full Path of the library*/
     OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
527
							 may be NULL*/
528
{
529 530 531
    static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-',
                                 '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-',
                                 '0','0','0','0','0','0','0','0','0','0','4','6','}',0};
532 533
    HRESULT res;
    TLIBATTR *attr;
534 535
    WCHAR keyName[60];
    WCHAR tmp[16];
536
    HKEY key, subKey;
537 538
    UINT types, tidx;
    TYPEKIND kind;
539
    DWORD disposition;
540 541 542 543

    if (ptlib == NULL || szFullPath == NULL)
        return E_INVALIDARG;

544
    if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
545 546
        return E_FAIL;

547 548 549 550 551 552
#ifdef _WIN64
    if (attr->syskind != SYS_WIN64) return TYPE_E_BADMODULEKIND;
#else
    if (attr->syskind != SYS_WIN32 && attr->syskind != SYS_WIN16) return TYPE_E_BADMODULEKIND;
#endif

553
    get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
554 555

    res = S_OK;
556
    if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
557 558 559 560
        KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
    {
        LPOLESTR doc;

561
        /* Set the human-readable name of the typelib */
562 563 564
        if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
            res = E_FAIL;
        else if (doc)
565 566
        {
            if (RegSetValueExW(key, NULL, 0, REG_SZ,
567
                (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
568 569 570 571 572
                res = E_FAIL;

            SysFreeString(doc);
        }

573
        /* Make up the name of the typelib path subkey */
574
        if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
575 576

        /* Create the typelib path subkey */
577
        if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
578 579 580
            KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
        {
            if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
581
                (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
582 583 584 585 586 587 588
                res = E_FAIL;

            RegCloseKey(subKey);
        }
        else
            res = E_FAIL;

589
        /* Create the flags subkey */
590
        if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
591 592 593
            KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
        {
            /* FIXME: is %u correct? */
594 595 596 597 598
            static const WCHAR formatW[] = {'%','u',0};
            WCHAR buf[20];
            sprintfW(buf, formatW, attr->wLibFlags);
            if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
                               (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS)
599
                res = E_FAIL;
600 601 602 603 604 605 606

            RegCloseKey(subKey);
        }
        else
            res = E_FAIL;

        /* create the helpdir subkey */
607
        if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
            KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS)
        {
            BOOL freeHelpDir = FALSE;
            OLECHAR* pIndexStr;

            /* if we created a new key, and helpDir was null, set the helpdir
               to the directory which contains the typelib. However,
               if we just opened an existing key, we leave the helpdir alone */
            if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) {
                szHelpDir = SysAllocString(szFullPath);
                pIndexStr = strrchrW(szHelpDir, '\\');
                if (pIndexStr) {
                    *pIndexStr = 0;
                }
                freeHelpDir = TRUE;
            }

            /* if we have an szHelpDir, set it! */
            if (szHelpDir != NULL) {
                if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
                    (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) {
                    res = E_FAIL;
                }
            }

            /* tidy up */
            if (freeHelpDir) SysFreeString(szHelpDir);
            RegCloseKey(subKey);

        } else {
            res = E_FAIL;
639
        }
640

641 642 643 644 645
        RegCloseKey(key);
    }
    else
        res = E_FAIL;

646 647 648 649 650 651
    /* register OLE Automation-compatible interfaces for this typelib */
    types = ITypeLib_GetTypeInfoCount(ptlib);
    for (tidx=0; tidx<types; tidx++) {
	if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) {
	    LPOLESTR name = NULL;
	    ITypeInfo *tinfo = NULL;
652

653
	    ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
654

655 656 657 658 659
	    switch (kind) {
	    case TKIND_INTERFACE:
		TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
		ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
		break;
660

661 662
	    case TKIND_DISPATCH:
		TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
663
                ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
664
		break;
665

666 667 668 669
	    default:
		TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
		break;
	    }
670

671 672 673
	    if (tinfo) {
		TYPEATTR *tattr = NULL;
		ITypeInfo_GetTypeAttr(tinfo, &tattr);
674

675
		if (tattr) {
676
		    TRACE_(typelib)("guid=%s, flags=%04x (",
677 678
				    debugstr_guid(&tattr->guid),
				    tattr->wTypeFlags);
679

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
		    if (TRACE_ON(typelib)) {
#define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|");
			XX(FAPPOBJECT);
			XX(FCANCREATE);
			XX(FLICENSED);
			XX(FPREDECLID);
			XX(FHIDDEN);
			XX(FCONTROL);
			XX(FDUAL);
			XX(FNONEXTENSIBLE);
			XX(FOLEAUTOMATION);
			XX(FRESTRICTED);
			XX(FAGGREGATABLE);
			XX(FREPLACEABLE);
			XX(FDISPATCHABLE);
			XX(FREVERSEBIND);
			XX(FPROXY);
#undef XX
			MESSAGE("\n");
		    }
700

701 702 703 704
                    /* Register all dispinterfaces (which includes dual interfaces) and
                       oleautomation interfaces */
		    if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
                        kind == TKIND_DISPATCH)
705
		    {
706
			/* register interface<->typelib coupling */
707
			get_interface_key( &tattr->guid, keyName );
708 709 710
			if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
					    KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
			{
711 712
			    if (name)
				RegSetValueExW(key, NULL, 0, REG_SZ,
713
					       (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
714

715
			    if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
716
				KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
717
				RegSetValueExW(subKey, NULL, 0, REG_SZ,
718
					       (const BYTE *)PSOA, sizeof PSOA);
719 720
				RegCloseKey(subKey);
			    }
721

722
			    if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
723
				KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) {
724
				RegSetValueExW(subKey, NULL, 0, REG_SZ,
725
					       (const BYTE *)PSOA, sizeof PSOA);
726 727 728
				RegCloseKey(subKey);
			    }

729
			    if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
730 731
				KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
			    {
732
				WCHAR buffer[40];
733
				static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
734
				static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
735

736
				StringFromGUID2(&attr->guid, buffer, 40);
737
				RegSetValueExW(subKey, NULL, 0, REG_SZ,
738 739 740 741
					       (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
				sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum);
				RegSetValueExW(subKey, VersionW, 0, REG_SZ,
					       (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
742 743
				RegCloseKey(subKey);
			    }
744

745 746 747
			    RegCloseKey(key);
			}
		    }
748

749 750
		    ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
		}
751

752 753
		ITypeInfo_Release(tinfo);
	    }
754

755 756 757 758
	    SysFreeString(name);
	}
    }

759
    ITypeLib_ReleaseTLibAttr(ptlib, attr);
760

761
    return res;
Alexandre Julliard's avatar
Alexandre Julliard committed
762
}
Alexandre Julliard's avatar
Alexandre Julliard committed
763

764 765 766

/******************************************************************************
 *	UnRegisterTypeLib	[OLEAUT32.186]
767
 * Removes information about a type library from the System Registry
768 769 770 771 772 773 774 775 776 777 778 779
 * NOTES
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI UnRegisterTypeLib(
    REFGUID libid,	/* [in] Guid of the library */
	WORD wVerMajor,	/* [in] major version */
	WORD wVerMinor,	/* [in] minor version */
	LCID lcid,	/* [in] locale id */
	SYSKIND syskind)
780
{
781 782
    BSTR tlibPath = NULL;
    DWORD tmpLength;
783 784
    WCHAR keyName[60];
    WCHAR subKeyName[50];
785 786 787 788 789 790 791 792 793 794 795
    int result = S_OK;
    DWORD i = 0;
    BOOL deleteOtherStuff;
    HKEY key = NULL;
    HKEY subKey = NULL;
    TYPEATTR* typeAttr = NULL;
    TYPEKIND kind;
    ITypeInfo* typeInfo = NULL;
    ITypeLib* typeLib = NULL;
    int numTypes;

796
    TRACE("(IID: %s)\n",debugstr_guid(libid));
797 798

    /* Create the path to the key */
799
    get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
800

801
    if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
802
    {
803 804 805 806 807 808
        TRACE("Unsupported syskind %i\n", syskind);
        result = E_INVALIDARG;
        goto end;
    }

    /* get the path to the typelib on disk */
809
    if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath) != S_OK) {
810 811 812 813 814
        result = E_INVALIDARG;
        goto end;
    }

    /* Try and open the key to the type library. */
815
    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
816 817 818 819 820
        result = E_INVALIDARG;
        goto end;
    }

    /* Try and load the type library */
821
    if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib) != S_OK) {
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
        result = TYPE_E_INVALIDSTATE;
        goto end;
    }

    /* remove any types registered with this typelib */
    numTypes = ITypeLib_GetTypeInfoCount(typeLib);
    for (i=0; i<numTypes; i++) {
        /* get the kind of type */
        if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) {
            goto enddeleteloop;
        }

        /* skip non-interfaces, and get type info for the type */
        if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) {
            goto enddeleteloop;
        }
        if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) {
            goto enddeleteloop;
        }
        if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) {
            goto enddeleteloop;
        }

845 846 847 848 849
        if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
            kind == TKIND_DISPATCH)
        {
            /* the path to the type */
            get_interface_key( &typeAttr->guid, subKeyName );
850

851 852 853 854 855 856 857 858 859 860
            /* Delete its bits */
            if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != ERROR_SUCCESS)
                goto enddeleteloop;

            RegDeleteKeyW(subKey, ProxyStubClsidW);
            RegDeleteKeyW(subKey, ProxyStubClsid32W);
            RegDeleteKeyW(subKey, TypeLibW);
            RegCloseKey(subKey);
            subKey = NULL;
            RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName);
861 862 863 864 865 866 867 868 869 870
        }

enddeleteloop:
        if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
        typeAttr = NULL;
        if (typeInfo) ITypeInfo_Release(typeInfo);
        typeInfo = NULL;
    }

    /* Now, delete the type library path subkey */
871 872 873 874
    get_lcid_subkey( lcid, syskind, subKeyName );
    RegDeleteKeyW(key, subKeyName);
    *strrchrW( subKeyName, '\\' ) = 0;  /* remove last path component */
    RegDeleteKeyW(key, subKeyName);
875 876 877

    /* check if there is anything besides the FLAGS/HELPDIR keys.
       If there is, we don't delete them */
878
    tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
879 880
    deleteOtherStuff = TRUE;
    i = 0;
881
    while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
882
        tmpLength = sizeof(subKeyName)/sizeof(WCHAR);
883 884

        /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
885 886
        if (!strcmpW(subKeyName, FLAGSW)) continue;
        if (!strcmpW(subKeyName, HELPDIRW)) continue;
887 888 889 890 891 892
        deleteOtherStuff = FALSE;
        break;
    }

    /* only delete the other parts of the key if we're absolutely sure */
    if (deleteOtherStuff) {
893 894
        RegDeleteKeyW(key, FLAGSW);
        RegDeleteKeyW(key, HELPDIRW);
895 896 897
        RegCloseKey(key);
        key = NULL;

898 899 900
        RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
        *strrchrW( keyName, '\\' ) = 0;  /* remove last path component */
        RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
901 902 903
    }

end:
904
    SysFreeString(tlibPath);
905 906 907 908
    if (typeLib) ITypeLib_Release(typeLib);
    if (subKey) RegCloseKey(subKey);
    if (key) RegCloseKey(key);
    return result;
909 910
}

911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
/******************************************************************************
 *		RegisterTypeLibForUser	[OLEAUT32.442]
 * Adds information about a type library to the user registry
 * NOTES
 *    Docs: ITypeLib FAR * ptlib
 *    Docs: OLECHAR FAR* szFullPath
 *    Docs: OLECHAR FAR* szHelpDir
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI RegisterTypeLibForUser(
     ITypeLib * ptlib,     /* [in] Pointer to the library*/
     OLECHAR * szFullPath, /* [in] full Path of the library*/
     OLECHAR * szHelpDir)  /* [in] dir to the helpfile for the library,
							 may be NULL*/
{
    FIXME("(%p, %s, %s) registering the typelib system-wide\n", ptlib,
          debugstr_w(szFullPath), debugstr_w(szHelpDir));
    return RegisterTypeLib(ptlib, szFullPath, szHelpDir);
}

934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
/******************************************************************************
 *	UnRegisterTypeLibForUser	[OLEAUT32.443]
 * Removes information about a type library from the user registry
 *
 * RETURNS
 *    Success: S_OK
 *    Failure: Status
 */
HRESULT WINAPI UnRegisterTypeLibForUser(
    REFGUID libid,	/* [in] GUID of the library */
    WORD wVerMajor,	/* [in] major version */
    WORD wVerMinor,	/* [in] minor version */
    LCID lcid,	/* [in] locale id */
    SYSKIND syskind)
{
    FIXME("(%s, %u, %u, %u, %u) unregistering the typelib system-wide\n",
          debugstr_guid(libid), wVerMajor, wVerMinor, lcid, syskind);
    return UnRegisterTypeLib(libid, wVerMajor, wVerMinor, lcid, syskind);
}

954
/*======================= ITypeLib implementation =======================*/
955

956
typedef struct tagTLBCustData
957 958 959
{
    GUID guid;
    VARIANT data;
960
    struct list entry;
961
} TLBCustData;
962

963 964 965
/* data structure for import typelibs */
typedef struct tagTLBImpLib
{
966 967 968 969
    int offset;                 /* offset in the file (MSFT)
				   offset in nametable (SLTG)
				   just used to identify library while reading
				   data from file */
970
    GUID guid;                  /* libid */
971
    BSTR name;                  /* name */
972

973
    LCID lcid;                  /* lcid of imported typelib */
974

975
    WORD wVersionMajor;         /* major version number */
976 977
    WORD wVersionMinor;         /* minor version number */

978 979
    struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
					    NULL if not yet loaded */
980
    struct list entry;
981
} TLBImpLib;
982

983 984 985
/* internal ITypeLib data */
typedef struct tagITypeLibImpl
{
986 987
    const ITypeLib2Vtbl *lpVtbl;
    const ITypeCompVtbl *lpVtblTypeComp;
988
    LONG ref;
989
    TLIBATTR LibAttr;            /* guid,lcid,syskind,version,flags */
990
    LCID lcid;
991

992
    /* strings can be stored in tlb as multibyte strings BUT they are *always*
993 994 995
     * exported to the application as a UNICODE string.
     */
    BSTR Name;
996 997 998
    BSTR DocString;
    BSTR HelpFile;
    BSTR HelpStringDll;
999
    DWORD dwHelpContext;
1000
    int TypeInfoCount;          /* nr of typeinfo's in librarry */
1001
    struct tagITypeInfoImpl **typeinfos;
1002
    struct list custdata_list;
1003
    struct list implib_list;
1004
    int ctTypeDesc;             /* number of items in type desc array */
1005
    TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
1006
				   library. Only used while reading MSFT
1007
				   typelibs */
1008
    struct list ref_list;       /* list of ref types in this typelib */
1009 1010 1011
    HREFTYPE dispatch_href;     /* reference to IDispatch, -1 if unused */


1012
    /* typelibs are cached, keyed by path and index, so store the linked list info within them */
1013
    struct list entry;
1014
    WCHAR *path;
1015
    INT index;
1016 1017
} ITypeLibImpl;

1018 1019
static const ITypeLib2Vtbl tlbvt;
static const ITypeCompVtbl tlbtcvt;
1020

1021 1022 1023 1024
static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
{
    return (ITypeLibImpl *)((char*)iface - FIELD_OFFSET(ITypeLibImpl, lpVtblTypeComp));
}
1025

1026
/* ITypeLib methods */
1027 1028
static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
1029 1030 1031

/*======================= ITypeInfo implementation =======================*/

1032
/* data for referenced types */
1033 1034
typedef struct tagTLBRefType
{
1035 1036 1037 1038
    INT index;              /* Type index for internal ref or for external ref
			       it the format is SLTG.  -2 indicates to
			       use guid */

1039
    GUID guid;              /* guid of the referenced type */
1040 1041 1042 1043 1044 1045
                            /* if index == TLB_REF_USE_GUID */

    HREFTYPE reference;     /* The href of this ref */
    TLBImpLib *pImpTLInfo;  /* If ref is external ptr to library data
			       TLB_REF_INTERNAL for internal refs
			       TLB_REF_NOT_FOUND for broken refs */
1046

1047
    struct list entry;
1048 1049
} TLBRefType;

1050 1051 1052 1053 1054
#define TLB_REF_USE_GUID -2

#define TLB_REF_INTERNAL (void*)-2
#define TLB_REF_NOT_FOUND (void*)-1

1055 1056 1057
/* internal Parameter data */
typedef struct tagTLBParDesc
{
1058
    BSTR Name;
1059
    struct list custdata_list;
1060 1061 1062 1063 1064 1065
} TLBParDesc;

/* internal Function data */
typedef struct tagTLBFuncDesc
{
    FUNCDESC funcdesc;      /* lots of info on the function and its attributes. */
1066
    BSTR Name;             /* the name of this function */
1067
    TLBParDesc *pParamDesc; /* array with param names and custom data */
1068 1069
    int helpcontext;
    int HelpStringContext;
1070
    BSTR HelpString;
1071
    BSTR Entry;            /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
1072
    struct list custdata_list;
1073 1074 1075 1076 1077 1078
} TLBFuncDesc;

/* internal Variable data */
typedef struct tagTLBVarDesc
{
    VARDESC vardesc;        /* lots of info on the variable and its attributes. */
1079
    BSTR Name;             /* the name of this variable */
1080
    int HelpContext;
1081
    int HelpStringContext;
1082
    BSTR HelpString;
1083
    struct list custdata_list;
1084 1085
} TLBVarDesc;

1086 1087 1088 1089 1090
/* internal implemented interface data */
typedef struct tagTLBImplType
{
    HREFTYPE hRef;          /* hRef of interface */
    int implflags;          /* IMPLFLAG_*s */
1091
    struct list custdata_list;
1092 1093
} TLBImplType;

1094 1095 1096
/* internal TypeInfo data */
typedef struct tagITypeInfoImpl
{
1097 1098
    const ITypeInfo2Vtbl *lpVtbl;
    const ITypeCompVtbl  *lpVtblTypeComp;
1099
    LONG ref;
1100
    BOOL not_attached_to_typelib;
1101 1102 1103
    TYPEATTR TypeAttr ;         /* _lots_ of type information. */
    ITypeLibImpl * pTypeLib;        /* back pointer to typelib */
    int index;                  /* index in this typelib; */
1104
    HREFTYPE hreftype;          /* hreftype for app object binding */
1105
    /* type libs seem to store the doc strings in ascii
1106 1107
     * so why should we do it in unicode?
     */
1108 1109
    BSTR Name;
    BSTR DocString;
1110
    BSTR DllName;
1111 1112
    DWORD dwHelpContext;
    DWORD dwHelpStringContext;
1113

1114
    /* functions  */
1115
    TLBFuncDesc *funcdescs;
1116

1117
    /* variables  */
1118
    TLBVarDesc *vardescs;
1119

1120
    /* Implemented Interfaces  */
1121
    TLBImplType *impltypes;
1122

1123
    struct list custdata_list;
1124
} ITypeInfoImpl;
1125

1126 1127 1128 1129 1130
static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
{
    return (ITypeInfoImpl *)((char*)iface - FIELD_OFFSET(ITypeInfoImpl, lpVtblTypeComp));
}

1131 1132
static const ITypeInfo2Vtbl tinfvt;
static const ITypeCompVtbl  tcompvt;
1133

1134 1135
static ITypeInfoImpl* ITypeInfoImpl_Constructor(void);
static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This);
1136

1137 1138 1139 1140 1141 1142
typedef struct tagTLBContext
{
	unsigned int oStart;  /* start of TLB in file */
	unsigned int pos;     /* current pos */
	unsigned int length;  /* total length */
	void *mapping;        /* memory mapping */
1143
	MSFT_SegDir * pTblDir;
1144 1145
	ITypeLibImpl* pLibInfo;
} TLBContext;
1146

1147

1148
static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL, int offset);
1149

1150 1151 1152
/*
 debug
*/
1153
static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
1154 1155 1156 1157 1158 1159 1160 1161 1162
    if (pTD->vt & VT_RESERVED)
	szVarType += strlen(strcpy(szVarType, "reserved | "));
    if (pTD->vt & VT_BYREF)
	szVarType += strlen(strcpy(szVarType, "ref to "));
    if (pTD->vt & VT_ARRAY)
	szVarType += strlen(strcpy(szVarType, "array of "));
    if (pTD->vt & VT_VECTOR)
	szVarType += strlen(strcpy(szVarType, "vector of "));
    switch(pTD->vt & VT_TYPEMASK) {
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
    case VT_UI1: sprintf(szVarType, "VT_UI1"); break;
    case VT_I2: sprintf(szVarType, "VT_I2"); break;
    case VT_I4: sprintf(szVarType, "VT_I4"); break;
    case VT_R4: sprintf(szVarType, "VT_R4"); break;
    case VT_R8: sprintf(szVarType, "VT_R8"); break;
    case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break;
    case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break;
    case VT_CY: sprintf(szVarType, "VT_CY"); break;
    case VT_DATE: sprintf(szVarType, "VT_DATE"); break;
    case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break;
1173
    case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
1174 1175 1176 1177 1178 1179 1180 1181
    case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break;
    case VT_I1: sprintf(szVarType, "VT_I1"); break;
    case VT_UI2: sprintf(szVarType, "VT_UI2"); break;
    case VT_UI4: sprintf(szVarType, "VT_UI4"); break;
    case VT_INT: sprintf(szVarType, "VT_INT"); break;
    case VT_UINT: sprintf(szVarType, "VT_UINT"); break;
    case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break;
    case VT_VOID: sprintf(szVarType, "VT_VOID"); break;
1182
    case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
1183
    case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
1184
				 pTD->u.hreftype); break;
1185 1186
    case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
    case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
    case VT_PTR: sprintf(szVarType, "ptr to ");
      dump_TypeDesc(pTD->u.lptdesc, szVarType + 7);
      break;
    case VT_SAFEARRAY: sprintf(szVarType, "safearray of ");
      dump_TypeDesc(pTD->u.lptdesc, szVarType + 13);
      break;
    case VT_CARRAY: sprintf(szVarType, "%d dim array of ",
			    pTD->u.lpadesc->cDims); /* FIXME print out sizes */
      dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType));
      break;

1198
    default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
1199 1200 1201
    }
}

1202
static void dump_ELEMDESC(const ELEMDESC *edesc) {
1203
  char buf[200];
1204
  USHORT flags = edesc->u.paramdesc.wParamFlags;
1205
  dump_TypeDesc(&edesc->tdesc,buf);
1206
  MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
  MESSAGE("\t\tu.paramdesc.wParamFlags");
  if (!flags) MESSAGE(" PARAMFLAGS_NONE");
  if (flags & PARAMFLAG_FIN) MESSAGE(" PARAMFLAG_FIN");
  if (flags & PARAMFLAG_FOUT) MESSAGE(" PARAMFLAG_FOUT");
  if (flags & PARAMFLAG_FLCID) MESSAGE(" PARAMFLAG_FLCID");
  if (flags & PARAMFLAG_FRETVAL) MESSAGE(" PARAMFLAG_FRETVAL");
  if (flags & PARAMFLAG_FOPT) MESSAGE(" PARAMFLAG_FOPT");
  if (flags & PARAMFLAG_FHASDEFAULT) MESSAGE(" PARAMFLAG_FHASDEFAULT");
  if (flags & PARAMFLAG_FHASCUSTDATA) MESSAGE(" PARAMFLAG_FHASCUSTDATA");
  MESSAGE("\n\t\tu.paramdesc.lpex %p\n",edesc->u.paramdesc.pparamdescex);
1217
}
1218
static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
1219
  int i;
1220
  MESSAGE("memid is %08x\n",funcdesc->memid);
1221 1222 1223 1224
  for (i=0;i<funcdesc->cParams;i++) {
      MESSAGE("Param %d:\n",i);
      dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
  }
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
  MESSAGE("\tfunckind: %d (",funcdesc->funckind);
  switch (funcdesc->funckind) {
  case FUNC_VIRTUAL: MESSAGE("virtual");break;
  case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break;
  case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break;
  case FUNC_STATIC: MESSAGE("static");break;
  case FUNC_DISPATCH: MESSAGE("dispatch");break;
  default: MESSAGE("unknown");break;
  }
  MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind);
  switch (funcdesc->invkind) {
  case INVOKE_FUNC: MESSAGE("func");break;
  case INVOKE_PROPERTYGET: MESSAGE("property get");break;
  case INVOKE_PROPERTYPUT: MESSAGE("property put");break;
  case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break;
  }
  MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv);
  switch (funcdesc->callconv) {
  case CC_CDECL: MESSAGE("cdecl");break;
  case CC_PASCAL: MESSAGE("pascal");break;
  case CC_STDCALL: MESSAGE("stdcall");break;
  case CC_SYSCALL: MESSAGE("syscall");break;
  default:break;
  }
  MESSAGE(")\n\toVft: %d\n", funcdesc->oVft);
  MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt);
  MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags);
1252 1253 1254

  MESSAGE("\telemdescFunc (return value type):\n");
  dump_ELEMDESC(&funcdesc->elemdescFunc);
1255
}
1256

1257
static const char * const typekind_desc[] =
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
{
	"TKIND_ENUM",
	"TKIND_RECORD",
	"TKIND_MODULE",
	"TKIND_INTERFACE",
	"TKIND_DISPATCH",
	"TKIND_COCLASS",
	"TKIND_ALIAS",
	"TKIND_UNION",
	"TKIND_MAX"
};

1270
static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
{
  int i;
  MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams);
  for (i=0;i<pfd->funcdesc.cParams;i++)
      MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name));


  dump_FUNCDESC(&(pfd->funcdesc));

  MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString));
1281
  MESSAGE("\tentry: %s\n", (pfd->Entry == (void *)-1) ? "invalid" : debugstr_w(pfd->Entry));
1282
}
1283
static void dump_TLBFuncDesc(const TLBFuncDesc * pfd, UINT n)
1284
{
1285
	while (n)
1286
	{
1287
	  dump_TLBFuncDescOne(pfd);
1288 1289 1290
	  ++pfd;
	  --n;
	}
1291
}
1292
static void dump_TLBVarDesc(const TLBVarDesc * pvd, UINT n)
1293
{
1294
	while (n)
1295
	{
1296
	  TRACE_(typelib)("%s\n", debugstr_w(pvd->Name));
1297 1298 1299
	  ++pvd;
	  --n;
	}
1300
}
1301

1302
static void dump_TLBImpLib(const TLBImpLib *import)
1303 1304 1305
{
    TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)),
		    debugstr_w(import->name));
1306
    TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
1307 1308 1309
		    import->wVersionMinor, import->lcid, import->offset);
}

1310
static void dump_TLBRefType(const ITypeLibImpl *pTL)
1311
{
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
    TLBRefType *ref;

    LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
    {
        TRACE_(typelib)("href:0x%08x\n", ref->reference);
        if(ref->index == -1)
	    TRACE_(typelib)("%s\n", debugstr_guid(&(ref->guid)));
        else
	    TRACE_(typelib)("type no: %d\n", ref->index);

        if(ref->pImpTLInfo != TLB_REF_INTERNAL && ref->pImpTLInfo != TLB_REF_NOT_FOUND)
        {
            TRACE_(typelib)("in lib\n");
            dump_TLBImpLib(ref->pImpTLInfo);
        }
    }
1328
}
1329

1330
static void dump_TLBImplType(const TLBImplType * impl, UINT n)
1331
{
1332 1333 1334 1335 1336 1337 1338
    if(!impl)
        return;
    while (n) {
        TRACE_(typelib)("implementing/inheriting interface hRef = %x implflags %x\n",
            impl->hRef, impl->implflags);
        ++impl;
        --n;
1339 1340
    }
}
1341

1342
static void dump_Variant(const VARIANT * pvar)
1343
{
1344
    SYSTEMTIME st;
1345

1346
    TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar));
1347

1348
    if (pvar)
1349
    {
1350 1351 1352 1353 1354 1355 1356
      if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN ||
          V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD)
      {
        TRACE(",%p", V_BYREF(pvar));
      }
      else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar))
      {
1357
        TRACE(",%p", V_ARRAY(pvar));
1358 1359 1360 1361 1362 1363 1364 1365
      }
      else switch (V_TYPE(pvar))
      {
      case VT_I1:   TRACE(",%d", V_I1(pvar)); break;
      case VT_UI1:  TRACE(",%d", V_UI1(pvar)); break;
      case VT_I2:   TRACE(",%d", V_I2(pvar)); break;
      case VT_UI2:  TRACE(",%d", V_UI2(pvar)); break;
      case VT_INT:
1366
      case VT_I4:   TRACE(",%d", V_I4(pvar)); break;
1367
      case VT_UINT:
1368 1369
      case VT_UI4:  TRACE(",%d", V_UI4(pvar)); break;
      case VT_I8:   TRACE(",0x%08x,0x%08x", (ULONG)(V_I8(pvar) >> 32),
1370
                          (ULONG)(V_I8(pvar) & 0xffffffff)); break;
1371
      case VT_UI8:  TRACE(",0x%08x,0x%08x", (ULONG)(V_UI8(pvar) >> 32),
1372 1373 1374 1375 1376
                          (ULONG)(V_UI8(pvar) & 0xffffffff)); break;
      case VT_R4:   TRACE(",%3.3e", V_R4(pvar)); break;
      case VT_R8:   TRACE(",%3.3e", V_R8(pvar)); break;
      case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break;
      case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break;
1377
      case VT_CY:   TRACE(",0x%08x,0x%08x", V_CY(pvar).s.Hi,
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
                           V_CY(pvar).s.Lo); break;
      case VT_DATE:
        if(!VariantTimeToSystemTime(V_DATE(pvar), &st))
          TRACE(",<invalid>");
        else
          TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
                st.wHour, st.wMinute, st.wSecond);
        break;
      case VT_ERROR:
      case VT_VOID:
      case VT_USERDEFINED:
      case VT_EMPTY:
      case VT_NULL:  break;
      default:       TRACE(",?"); break;
      }
1393
    }
1394
    TRACE("}\n");
1395
}
1396

1397
static void dump_DispParms(const DISPPARAMS * pdp)
1398
{
1399
    unsigned int index;
1400

1401 1402
    TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);

1403 1404
    if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
    {
1405
        TRACE("named args:\n");
1406 1407 1408
        for (index = 0; index < pdp->cNamedArgs; index++)
            TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
    }
1409

1410 1411
    if (pdp->cArgs && pdp->rgvarg)
    {
1412
        TRACE("args:\n");
1413 1414 1415
        for (index = 0; index < pdp->cArgs; index++)
            dump_Variant( &pdp->rgvarg[index] );
    }
1416 1417
}

1418
static void dump_TypeInfo(const ITypeInfoImpl * pty)
1419
{
1420
    TRACE("%p ref=%u\n", pty, pty->ref);
1421
    TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString));
1422 1423 1424 1425
    TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid)));
    TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]);
    TRACE("fct:%u var:%u impl:%u\n",
      pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes);
1426
    TRACE("wTypeFlags: 0x%04x\n", pty->TypeAttr.wTypeFlags);
1427
    TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
1428
    if (pty->TypeAttr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(pty->DllName));
1429
    if (TRACE_ON(ole))
1430
        dump_TLBFuncDesc(pty->funcdescs, pty->TypeAttr.cFuncs);
1431
    dump_TLBVarDesc(pty->vardescs, pty->TypeAttr.cVars);
1432
    dump_TLBImplType(pty->impltypes, pty->TypeAttr.cImplTypes);
1433 1434
}

1435
static void dump_VARDESC(const VARDESC *v)
1436
{
1437
    MESSAGE("memid %d\n",v->memid);
1438
    MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
1439
    MESSAGE("oInst %d\n",v->u.oInst);
1440 1441 1442 1443 1444
    dump_ELEMDESC(&(v->elemdescVar));
    MESSAGE("wVarFlags %x\n",v->wVarFlags);
    MESSAGE("varkind %d\n",v->varkind);
}

1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
static TYPEDESC std_typedesc[VT_LPWSTR+1] =
{
    /* VT_LPWSTR is largest type that, may appear in type description */
    {{0}, VT_EMPTY},  {{0}, VT_NULL},        {{0}, VT_I2},      {{0}, VT_I4},
    {{0}, VT_R4},     {{0}, VT_R8},          {{0}, VT_CY},      {{0}, VT_DATE},
    {{0}, VT_BSTR},   {{0}, VT_DISPATCH},    {{0}, VT_ERROR},   {{0}, VT_BOOL},
    {{0}, VT_VARIANT},{{0}, VT_UNKNOWN},     {{0}, VT_DECIMAL}, {{0}, 15}, /* unused in VARENUM */
    {{0}, VT_I1},     {{0}, VT_UI1},         {{0}, VT_UI2},     {{0}, VT_UI4},
    {{0}, VT_I8},     {{0}, VT_UI8},         {{0}, VT_INT},     {{0}, VT_UINT},
    {{0}, VT_VOID},   {{0}, VT_HRESULT},     {{0}, VT_PTR},     {{0}, VT_SAFEARRAY},
    {{0}, VT_CARRAY}, {{0}, VT_USERDEFINED}, {{0}, VT_LPSTR},   {{0}, VT_LPWSTR}
1456
};
1457

1458
static void TLB_abort(void)
1459
{
1460
    DebugBreak();
1461
}
1462

1463
void* __WINE_ALLOC_SIZE(1) heap_alloc_zero(unsigned size)
1464
{
1465 1466 1467 1468 1469
    void *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
    if (!ret) ERR("cannot allocate memory\n");
    return ret;
}

1470
void* __WINE_ALLOC_SIZE(1) heap_alloc(unsigned size)
1471 1472 1473
{
    void *ret = HeapAlloc(GetProcessHeap(), 0, size);
    if (!ret) ERR("cannot allocate memory\n");
1474 1475 1476
    return ret;
}

1477 1478 1479 1480 1481 1482
void* __WINE_ALLOC_SIZE(2) heap_realloc(void *ptr, unsigned size)
{
    return HeapReAlloc(GetProcessHeap(), 0, ptr, size);
}

void heap_free(void *ptr)
1483 1484 1485
{
    HeapFree(GetProcessHeap(), 0, ptr);
}
1486

1487 1488 1489
/* returns the size required for a deep copy of a typedesc into a
 * flat buffer */
static SIZE_T TLB_SizeTypeDesc( const TYPEDESC *tdesc, BOOL alloc_initial_space )
1490
{
1491 1492 1493 1494 1495 1496 1497
    SIZE_T size = 0;

    if (alloc_initial_space)
        size += sizeof(TYPEDESC);

    switch (tdesc->vt)
    {
1498
    case VT_PTR:
1499 1500 1501
    case VT_SAFEARRAY:
        size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
        break;
1502
    case VT_CARRAY:
1503 1504 1505
        size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
        size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
        break;
1506
    }
1507
    return size;
1508 1509
}

1510 1511
/* deep copy a typedesc into a flat buffer */
static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
1512
{
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
    if (!dest)
    {
        dest = buffer;
        buffer = (char *)buffer + sizeof(TYPEDESC);
    }

    *dest = *src;

    switch (src->vt)
    {
1523
    case VT_PTR:
1524 1525 1526 1527
    case VT_SAFEARRAY:
        dest->u.lptdesc = buffer;
        buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
        break;
1528
    case VT_CARRAY:
1529 1530 1531 1532 1533
        dest->u.lpadesc = buffer;
        memcpy(dest->u.lpadesc, src->u.lpadesc, FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]));
        buffer = (char *)buffer + FIELD_OFFSET(ARRAYDESC, rgbounds[src->u.lpadesc->cDims]);
        buffer = TLB_CopyTypeDesc(&dest->u.lpadesc->tdescElem, &src->u.lpadesc->tdescElem, buffer);
        break;
1534
    }
1535
    return buffer;
1536
}
1537

1538
/* free custom data allocated by MSFT_CustData */
1539
static inline void TLB_FreeCustData(struct list *custdata_list)
1540
{
1541 1542
    TLBCustData *cd, *cdn;
    LIST_FOR_EACH_ENTRY_SAFE(cd, cdn, custdata_list, TLBCustData, entry)
1543
    {
1544 1545 1546
        list_remove(&cd->entry);
        VariantClear(&cd->data);
        heap_free(cd);
1547 1548 1549
    }
}

1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561
static BSTR TLB_MultiByteToBSTR(const char *ptr)
{
    DWORD len;
    BSTR ret;

    len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0);
    ret = SysAllocStringLen(NULL, len - 1);
    if (!ret) return ret;
    MultiByteToWideChar(CP_ACP, 0, ptr, -1, ret, len);
    return ret;
}

1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
static inline TLBFuncDesc *TLB_get_funcdesc_by_memberid(TLBFuncDesc *funcdescs,
        UINT n, MEMBERID memid)
{
    while(n){
        if(funcdescs->funcdesc.memid == memid)
            return funcdescs;
        ++funcdescs;
        --n;
    }
    return NULL;
}

static inline TLBFuncDesc *TLB_get_funcdesc_by_name(TLBFuncDesc *funcdescs,
        UINT n, const OLECHAR *name)
{
    while(n){
        if(!lstrcmpiW(funcdescs->Name, name))
            return funcdescs;
        ++funcdescs;
        --n;
    }
    return NULL;
}

1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
static inline TLBVarDesc *TLB_get_vardesc_by_memberid(TLBVarDesc *vardescs,
        UINT n, MEMBERID memid)
{
    while(n){
        if(vardescs->vardesc.memid == memid)
            return vardescs;
        ++vardescs;
        --n;
    }
    return NULL;
}

static inline TLBVarDesc *TLB_get_vardesc_by_name(TLBVarDesc *vardescs,
        UINT n, const OLECHAR *name)
{
    while(n){
        if(!lstrcmpiW(vardescs->Name, name))
            return vardescs;
        ++vardescs;
        --n;
    }
    return NULL;
}

1610
static inline TLBCustData *TLB_get_custdata_by_guid(struct list *custdata_list, REFGUID guid)
1611
{
1612 1613
    TLBCustData *cust_data;
    LIST_FOR_EACH_ENTRY(cust_data, custdata_list, TLBCustData, entry)
1614 1615 1616 1617 1618
        if(IsEqualIID(&cust_data->guid, guid))
            return cust_data;
    return NULL;
}

1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
static TLBVarDesc *TLBVarDesc_Constructor(UINT n)
{
    TLBVarDesc *ret;

    ret = heap_alloc_zero(sizeof(TLBVarDesc) * n);
    if(!ret)
        return NULL;

    while(n){
        list_init(&ret[n-1].custdata_list);
        --n;
    }

    return ret;
}

static TLBParDesc *TLBParDesc_Constructor(UINT n)
{
    TLBParDesc *ret;

    ret = heap_alloc_zero(sizeof(TLBParDesc) * n);
    if(!ret)
        return NULL;

    while(n){
        list_init(&ret[n-1].custdata_list);
        --n;
    }

    return ret;
}

static TLBFuncDesc *TLBFuncDesc_Constructor(UINT n)
{
    TLBFuncDesc *ret;

    ret = heap_alloc_zero(sizeof(TLBFuncDesc) * n);
    if(!ret)
        return NULL;

    while(n){
        list_init(&ret[n-1].custdata_list);
        --n;
    }

    return ret;
}

static TLBImplType *TLBImplType_Constructor(UINT n)
{
    TLBImplType *ret;

    ret = heap_alloc_zero(sizeof(TLBImplType) * n);
    if(!ret)
        return NULL;

    while(n){
        list_init(&ret[n-1].custdata_list);
        --n;
    }

    return ret;
}

1683 1684 1685 1686
/**********************************************************************
 *
 *  Functions for reading MSFT typelibs (those created by CreateTypeLib2)
 */
1687
static inline unsigned int MSFT_Tell(const TLBContext *pcx)
1688
{
1689 1690
    return pcx->pos;
}
1691

1692
static inline void MSFT_Seek(TLBContext *pcx, LONG where)
1693
{
1694 1695 1696 1697 1698 1699
    if (where != DO_NOT_SEEK)
    {
        where += pcx->oStart;
        if (where > pcx->length)
        {
            /* FIXME */
1700
            ERR("seek beyond end (%d/%d)\n", where, pcx->length );
1701 1702 1703 1704
            TLB_abort();
        }
        pcx->pos = where;
    }
1705 1706 1707
}

/* read function */
1708
static DWORD MSFT_Read(void *buffer,  DWORD count, TLBContext *pcx, LONG where )
1709
{
1710
    TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
1711 1712 1713
       pcx->pos, count, pcx->oStart, pcx->length, where);

    MSFT_Seek(pcx, where);
1714 1715 1716 1717
    if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
    memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
    pcx->pos += count;
    return count;
1718 1719
}

1720
static DWORD MSFT_ReadLEDWords(void *buffer,  DWORD count, TLBContext *pcx,
1721
                               LONG where )
1722
{
1723
  DWORD ret;
1724

1725 1726 1727 1728 1729 1730 1731
  ret = MSFT_Read(buffer, count, pcx, where);
  FromLEDWords(buffer, ret);

  return ret;
}

static DWORD MSFT_ReadLEWords(void *buffer,  DWORD count, TLBContext *pcx,
1732
                              LONG where )
1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743
{
  DWORD ret;

  ret = MSFT_Read(buffer, count, pcx, where);
  FromLEWords(buffer, ret);

  return ret;
}

static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx)
{
1744 1745 1746 1747
    if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){
        memset(pGuid,0, sizeof(GUID));
        return;
    }
1748
    MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset );
1749 1750 1751 1752
    pGuid->Data1 = FromLEDWord(pGuid->Data1);
    pGuid->Data2 = FromLEWord(pGuid->Data2);
    pGuid->Data3 = FromLEWord(pGuid->Data3);
    TRACE_(typelib)("%s\n", debugstr_guid(pGuid));
1753 1754
}

1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770
static HREFTYPE MSFT_ReadHreftype( TLBContext *pcx, int offset )
{
    MSFT_NameIntro niName;

    if (offset < 0)
    {
        ERR_(typelib)("bad offset %d\n", offset);
        return -1;
    }

    MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
		      pcx->pTblDir->pNametab.offset+offset);

    return niName.hreftype;
}

1771
static BSTR MSFT_ReadName( TLBContext *pcx, int offset)
1772 1773
{
    char * name;
1774
    MSFT_NameIntro niName;
1775 1776
    int lengthInChars;
    BSTR bstrName = NULL;
1777

1778 1779 1780 1781 1782
    if (offset < 0)
    {
        ERR_(typelib)("bad offset %d\n", offset);
        return NULL;
    }
1783 1784
    MSFT_ReadLEDWords(&niName, sizeof(niName), pcx,
		      pcx->pTblDir->pNametab.offset+offset);
1785
    niName.namelen &= 0xFF; /* FIXME: correct ? */
1786
    name = heap_alloc_zero((niName.namelen & 0xff) +1);
1787
    MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK);
1788
    name[niName.namelen & 0xff]='\0';
1789 1790

    lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1791
                                        name, -1, NULL, 0);
1792 1793 1794 1795

    /* no invalid characters in string */
    if (lengthInChars)
    {
1796
        bstrName = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1797 1798

        /* don't check for invalid character since this has been done previously */
1799
        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, bstrName, lengthInChars);
1800
    }
1801
    heap_free(name);
1802

1803
    TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars);
1804
    return bstrName;
1805
}
1806

1807
static BSTR MSFT_ReadString( TLBContext *pcx, int offset)
1808 1809 1810
{
    char * string;
    INT16 length;
1811 1812
    int lengthInChars;
    BSTR bstr = NULL;
1813

1814
    if(offset<0) return NULL;
1815
    MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset);
1816
    if(length <= 0) return 0;
1817
    string = heap_alloc_zero(length +1);
1818
    MSFT_Read(string, length, pcx, DO_NOT_SEEK);
1819
    string[length]='\0';
1820 1821

    lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
1822
                                        string, -1, NULL, 0);
1823 1824 1825 1826

    /* no invalid characters in string */
    if (lengthInChars)
    {
1827
        bstr = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
1828 1829

        /* don't check for invalid character since this has been done previously */
1830
        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, bstr, lengthInChars);
1831
    }
1832
    heap_free(string);
1833

1834
    TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars);
1835
    return bstr;
1836 1837
}
/*
1838
 * read a value and fill a VARIANT structure
1839
 */
1840
static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
1841 1842
{
    int size;
1843

1844
    TRACE_(typelib)("\n");
1845

1846
    if(offset <0) { /* data are packed in here */
1847
        V_VT(pVar) = (offset & 0x7c000000 )>> 26;
1848
        V_I4(pVar) = offset & 0x3ffffff;
1849 1850
        return;
    }
1851 1852
    MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
                     pcx->pTblDir->pCustData.offset + offset );
1853 1854
    TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
    switch (V_VT(pVar)){
1855 1856 1857 1858 1859
        case VT_EMPTY:  /* FIXME: is this right? */
        case VT_NULL:   /* FIXME: is this right? */
        case VT_I2  :   /* this should not happen */
        case VT_I4  :
        case VT_R4  :
1860 1861 1862 1863 1864 1865 1866 1867
        case VT_ERROR   :
        case VT_BOOL    :
        case VT_I1  :
        case VT_UI1 :
        case VT_UI2 :
        case VT_UI4 :
        case VT_INT :
        case VT_UINT    :
1868
        case VT_VOID    : /* FIXME: is this right? */
1869
        case VT_HRESULT :
1870 1871 1872
            size=4; break;
        case VT_R8  :
        case VT_CY  :
1873 1874 1875
        case VT_DATE    :
        case VT_I8  :
        case VT_UI8 :
1876 1877 1878 1879 1880 1881
        case VT_DECIMAL :  /* FIXME: is this right? */
        case VT_FILETIME :
            size=8;break;
            /* pointer types with known behaviour */
        case VT_BSTR    :{
            char * ptr;
1882
            MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
1883
	    if(size < 0) {
1884 1885 1886 1887 1888 1889 1890 1891 1892
                char next;
                DWORD origPos = MSFT_Tell(pcx), nullPos;

                do {
                    MSFT_Read(&next, 1, pcx, DO_NOT_SEEK);
                } while (next);
                nullPos = MSFT_Tell(pcx);
                size = nullPos - origPos;
                MSFT_Seek(pcx, origPos);
1893
	    }
1894
            ptr = heap_alloc_zero(size);/* allocate temp buffer */
1895 1896 1897
            MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */
            V_BSTR(pVar)=SysAllocStringLen(NULL,size);
            /* FIXME: do we need a AtoW conversion here? */
1898
            V_UNION(pVar, bstrVal[size])='\0';
1899
            while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
1900
            heap_free(ptr);
1901 1902
	}
	size=-4; break;
1903 1904
    /* FIXME: this will not work AT ALL when the variant contains a pointer */
        case VT_DISPATCH :
1905 1906 1907
        case VT_VARIANT :
        case VT_UNKNOWN :
        case VT_PTR :
1908
        case VT_SAFEARRAY :
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922
        case VT_CARRAY  :
        case VT_USERDEFINED :
        case VT_LPSTR   :
        case VT_LPWSTR  :
        case VT_BLOB    :
        case VT_STREAM  :
        case VT_STORAGE :
        case VT_STREAMED_OBJECT :
        case VT_STORED_OBJECT   :
        case VT_BLOB_OBJECT :
        case VT_CF  :
        case VT_CLSID   :
        default:
            size=0;
1923
            FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
1924
                V_VT(pVar));
1925 1926 1927
    }

    if(size>0) /* (big|small) endian correct? */
1928
        MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
1929
    return;
1930 1931 1932 1933
}
/*
 * create a linked list with custom data
 */
1934
static int MSFT_CustData( TLBContext *pcx, int offset, struct list *custdata_list)
1935
{
1936
    MSFT_CDGuid entry;
1937 1938
    TLBCustData* pNew;
    int count=0;
1939

1940
    TRACE_(typelib)("\n");
1941

1942 1943
    if (pcx->pTblDir->pCDGuids.offset < 0) return 0;

1944 1945
    while(offset >=0){
        count++;
1946
        pNew=heap_alloc_zero(sizeof(TLBCustData));
1947
        MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
1948 1949
        MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx);
        MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
1950
        list_add_head(custdata_list, &pNew->entry);
1951 1952 1953 1954 1955
        offset = entry.next;
    }
    return count;
}

1956 1957
static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd,
			  ITypeInfoImpl *pTI)
1958 1959 1960 1961 1962
{
    if(type <0)
        pTd->vt=type & VT_TYPEMASK;
    else
        *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
1963

1964
    if(pTd->vt == VT_USERDEFINED)
1965
      MSFT_DoRefType(pcx, pTI->pTypeLib, pTd->u.hreftype);
1966

1967
    TRACE_(typelib)("vt type = %X\n", pTd->vt);
1968
}
1969

1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985
static void MSFT_ResolveReferencedTypes(TLBContext *pcx, ITypeInfoImpl *pTI, TYPEDESC *lpTypeDesc)
{
    /* resolve referenced type if any */
    while (lpTypeDesc)
    {
        switch (lpTypeDesc->vt)
        {
        case VT_PTR:
            lpTypeDesc = lpTypeDesc->u.lptdesc;
            break;

        case VT_CARRAY:
            lpTypeDesc = & (lpTypeDesc->u.lpadesc->tdescElem);
            break;

        case VT_USERDEFINED:
1986
            MSFT_DoRefType(pcx, pTI->pTypeLib,
1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997
                           lpTypeDesc->u.hreftype);

            lpTypeDesc = NULL;
            break;

        default:
            lpTypeDesc = NULL;
        }
    }
}

1998
static void
1999 2000
MSFT_DoFuncs(TLBContext*     pcx,
	    ITypeInfoImpl*  pTI,
2001
            int             cFuncs,
2002
            int             cVars,
2003
            int             offset,
2004
            TLBFuncDesc**   pptfd)
2005
{
2006
    /*
2007 2008 2009
     * member information is stored in a data structure at offset
     * indicated by the memoffset field of the typeinfo structure
     * There are several distinctive parts.
2010
     * The first part starts with a field that holds the total length
2011 2012 2013
     * of this (first) part excluding this field. Then follow the records,
     * for each member there is one record.
     *
2014
     * The first entry is always the length of the record (including this
2015
     * length word).
2016 2017
     * The rest of the record depends on the type of the member. If there is
     * a field indicating the member type (function, variable, interface, etc)
2018 2019 2020
     * I have not found it yet. At this time we depend on the information
     * in the type info and the usual order how things are stored.
     *
2021
     * Second follows an array sized nrMEM*sizeof(INT) with a member id
2022
     * for each member;
2023
     *
2024
     * Third is an equal sized array with file offsets to the name entry
2025
     * of each member.
2026
     *
2027 2028
     * The fourth and last (?) part is an array with offsets to the records
     * in the first part of this file segment.
2029 2030
     */

2031
    int infolen, nameoffset, reclength, i;
2032 2033
    int recoffset = offset + sizeof(INT);

2034
    char *recbuf = heap_alloc(0xffff);
2035
    MSFT_FuncRecord *pFuncRec = (MSFT_FuncRecord*)recbuf;
2036
    TLBFuncDesc *ptfd_prev = NULL, *ptfd;
2037

2038
    TRACE_(typelib)("\n");
2039

2040
    MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
2041

2042
    *pptfd = TLBFuncDesc_Constructor(cFuncs);
2043
    ptfd = *pptfd;
2044 2045
    for ( i = 0; i < cFuncs ; i++ )
    {
2046 2047
        int optional;

2048
        /* name, eventually add to a hash table */
2049 2050
        MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
                          offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
2051

2052 2053 2054
        /* nameoffset is sometimes -1 on the second half of a propget/propput
         * pair of functions */
        if ((nameoffset == -1) && (i > 0))
2055
            ptfd->Name = SysAllocString(ptfd_prev->Name);
2056
        else
2057
            ptfd->Name = MSFT_ReadName(pcx, nameoffset);
2058 2059

        /* read the function information record */
2060
        MSFT_ReadLEDWords(&reclength, sizeof(pFuncRec->Info), pcx, recoffset);
2061

2062
        reclength &= 0xffff;
2063

2064
        MSFT_ReadLEDWords(&pFuncRec->DataType, reclength - FIELD_OFFSET(MSFT_FuncRecord, DataType), pcx, DO_NOT_SEEK);
2065

2066 2067
        /* size without argument data */
        optional = reclength - pFuncRec->nrargs*sizeof(MSFT_ParameterInfo);
2068

2069
        if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpContext))
2070
            ptfd->helpcontext = pFuncRec->HelpContext;
2071

2072
        if (optional > FIELD_OFFSET(MSFT_FuncRecord, oHelpString))
2073
            ptfd->HelpString = MSFT_ReadString(pcx, pFuncRec->oHelpString);
2074

2075 2076 2077 2078 2079 2080
        if (optional > FIELD_OFFSET(MSFT_FuncRecord, oEntry))
        {
            if (pFuncRec->FKCCIC & 0x2000 )
            {
                if (!IS_INTRESOURCE(pFuncRec->oEntry))
                    ERR("ordinal 0x%08x invalid, IS_INTRESOURCE is false\n", pFuncRec->oEntry);
2081
                ptfd->Entry = (BSTR)(DWORD_PTR)LOWORD(pFuncRec->oEntry);
2082
            }
2083
            else
2084
                ptfd->Entry = MSFT_ReadString(pcx, pFuncRec->oEntry);
2085
        }
2086
        else
2087
            ptfd->Entry = (BSTR)-1;
2088 2089

        if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpStringContext))
2090
            ptfd->HelpStringContext = pFuncRec->HelpStringContext;
2091 2092

        if (optional > FIELD_OFFSET(MSFT_FuncRecord, oCustData) && pFuncRec->FKCCIC & 0x80)
2093
            MSFT_CustData(pcx, pFuncRec->oCustData, &ptfd->custdata_list);
2094 2095

        /* fill the FuncDesc Structure */
2096
        MSFT_ReadLEDWords( & ptfd->funcdesc.memid, sizeof(INT), pcx,
2097
                           offset + infolen + ( i + 1) * sizeof(INT));
2098

2099 2100 2101 2102 2103 2104 2105
        ptfd->funcdesc.funckind   =  (pFuncRec->FKCCIC)      & 0x7;
        ptfd->funcdesc.invkind    =  (pFuncRec->FKCCIC) >> 3 & 0xF;
        ptfd->funcdesc.callconv   =  (pFuncRec->FKCCIC) >> 8 & 0xF;
        ptfd->funcdesc.cParams    =   pFuncRec->nrargs  ;
        ptfd->funcdesc.cParamsOpt =   pFuncRec->nroargs ;
        ptfd->funcdesc.oVft       =   pFuncRec->VtableOffset & ~1;
        ptfd->funcdesc.wFuncFlags =   LOWORD(pFuncRec->Flags) ;
2106

2107 2108
        MSFT_GetTdesc(pcx,
		      pFuncRec->DataType,
2109
		      &ptfd->funcdesc.elemdescFunc.tdesc,
2110
		      pTI);
2111
        MSFT_ResolveReferencedTypes(pcx, pTI, &ptfd->funcdesc.elemdescFunc.tdesc);
2112

2113
        /* do the parameters/arguments */
2114 2115 2116
        if(pFuncRec->nrargs)
        {
            int j = 0;
2117
            MSFT_ParameterInfo paraminfo;
2118

2119
            ptfd->funcdesc.lprgelemdescParam =
2120
                heap_alloc_zero(pFuncRec->nrargs * sizeof(ELEMDESC));
2121

2122
            ptfd->pParamDesc = TLBParDesc_Constructor(pFuncRec->nrargs);
2123

2124 2125
            MSFT_ReadLEDWords(&paraminfo, sizeof(paraminfo), pcx,
                              recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
2126 2127 2128

            for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
            {
2129
                ELEMDESC *elemdesc = &ptfd->funcdesc.lprgelemdescParam[j];
2130

2131 2132
                MSFT_GetTdesc(pcx,
			      paraminfo.DataType,
2133
			      &elemdesc->tdesc,
2134
			      pTI);
2135

2136
                elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
2137

2138 2139 2140 2141 2142
                /* name */
                if (paraminfo.oName == -1)
                    /* this occurs for [propput] or [propget] methods, so
                     * we should just set the name of the parameter to the
                     * name of the method. */
2143
                    ptfd->pParamDesc[j].Name = SysAllocString(ptfd->Name);
2144
                else
2145
                    ptfd->pParamDesc[j].Name =
2146
                        MSFT_ReadName( pcx, paraminfo.oName );
2147
                TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w(ptfd->pParamDesc[j].Name));
2148

2149
                MSFT_ResolveReferencedTypes(pcx, pTI, &elemdesc->tdesc);
2150

2151 2152 2153 2154 2155 2156
                /* default value */
                if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
                     (pFuncRec->FKCCIC & 0x1000) )
                {
                    INT* pInt = (INT *)((char *)pFuncRec +
                                   reclength -
2157
                                   (pFuncRec->nrargs * 4) * sizeof(INT) );
2158 2159 2160

                    PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;

2161
                    pParamDesc->pparamdescex = heap_alloc_zero(sizeof(PARAMDESCEX));
2162 2163 2164 2165 2166
                    pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);

		    MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
                        pInt[j], pcx);
                }
2167 2168
                else
                    elemdesc->u.paramdesc.pparamdescex = NULL;
2169

2170
                /* custom info */
2171 2172 2173
                if (optional > (FIELD_OFFSET(MSFT_FuncRecord, oArgCustData) +
                                j*sizeof(pFuncRec->oArgCustData[0])) &&
                    pFuncRec->FKCCIC & 0x80 )
2174 2175
                {
                    MSFT_CustData(pcx,
2176
				  pFuncRec->oArgCustData[j],
2177
				  &ptfd->pParamDesc[j].custdata_list);
2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188
                }

                /* SEEK value = jump to offset,
                 * from there jump to the end of record,
                 * go back by (j-1) arguments
                 */
                MSFT_ReadLEDWords( &paraminfo ,
			   sizeof(MSFT_ParameterInfo), pcx,
			   recoffset + reclength - ((pFuncRec->nrargs - j - 1)
					       * sizeof(MSFT_ParameterInfo)));
            }
2189
        }
2190 2191

        /* scode is not used: archaic win16 stuff FIXME: right? */
2192 2193
        ptfd->funcdesc.cScodes   = 0 ;
        ptfd->funcdesc.lprgscode = NULL ;
2194

2195 2196
        ptfd_prev = ptfd;
        ++ptfd;
2197 2198
        recoffset += reclength;
    }
2199
    heap_free(recbuf);
2200
}
2201

2202 2203
static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
		       int cVars, int offset, TLBVarDesc ** pptvd)
2204 2205 2206
{
    int infolen, nameoffset, reclength;
    char recbuf[256];
2207
    MSFT_VarRecord *pVarRec = (MSFT_VarRecord*)recbuf;
2208
    TLBVarDesc *ptvd;
2209 2210
    int i;
    int recoffset;
2211

2212
    TRACE_(typelib)("\n");
2213

2214
    ptvd = *pptvd = TLBVarDesc_Constructor(cVars);
2215 2216 2217
    MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
    MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
                      ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
2218
    recoffset += offset+sizeof(INT);
2219
    for(i=0;i<cVars;i++, ++ptvd){
2220
    /* name, eventually add to a hash table */
2221
        MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
2222
                          offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
2223
        ptvd->Name=MSFT_ReadName(pcx, nameoffset);
2224
    /* read the variable information record */
2225 2226 2227 2228 2229 2230
        MSFT_ReadLEDWords(&reclength, sizeof(pVarRec->Info), pcx, recoffset);
        reclength &= 0xff;
        MSFT_ReadLEDWords(&pVarRec->DataType, reclength - FIELD_OFFSET(MSFT_VarRecord, DataType), pcx, DO_NOT_SEEK);

        /* optional data */
        if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpContext))
2231
            ptvd->HelpContext = pVarRec->HelpContext;
2232

2233
        if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpString))
2234
            ptvd->HelpString = MSFT_ReadString(pcx, pVarRec->HelpString);
2235 2236

        if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpStringContext))
2237
            ptvd->HelpStringContext = pVarRec->HelpStringContext;
2238

2239
    /* fill the VarDesc Structure */
2240
        MSFT_ReadLEDWords(&ptvd->vardesc.memid, sizeof(INT), pcx,
2241
                          offset + infolen + (cFuncs + i + 1) * sizeof(INT));
2242 2243
        ptvd->vardesc.varkind = pVarRec->VarKind;
        ptvd->vardesc.wVarFlags = pVarRec->Flags;
2244
        MSFT_GetTdesc(pcx, pVarRec->DataType,
2245 2246
            &ptvd->vardesc.elemdescVar.tdesc, pTI);
/*   ptvd->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
2247
        if(pVarRec->VarKind == VAR_CONST ){
2248 2249
            ptvd->vardesc.u.lpvarValue = heap_alloc_zero(sizeof(VARIANT));
            MSFT_ReadValue(ptvd->vardesc.u.lpvarValue,
2250
                pVarRec->OffsValue, pcx);
2251
        } else
2252 2253
            ptvd->vardesc.u.oInst=pVarRec->OffsValue;
        MSFT_ResolveReferencedTypes(pcx, pTI, &ptvd->vardesc.elemdescVar.tdesc);
2254 2255 2256
        recoffset += reclength;
    }
}
2257

2258
/* fill in data for a hreftype (offset). When the referenced type is contained
2259 2260
 * in the typelib, it's just an (file) offset in the type info base dir.
 * If comes from import, it's an offset+1 in the ImpInfo table
2261
 * */
2262
static void MSFT_DoRefType(TLBContext *pcx, ITypeLibImpl *pTL,
2263
                          int offset)
2264
{
2265
    TLBRefType *ref;
2266

2267
    TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset);
2268

2269 2270 2271
    LIST_FOR_EACH_ENTRY(ref, &pTL->ref_list, TLBRefType, entry)
    {
        if(ref->reference == offset) return;
2272 2273
    }

2274
    ref = heap_alloc_zero(sizeof(TLBRefType));
2275
    list_add_tail(&pTL->ref_list, &ref->entry);
2276 2277

    if(!MSFT_HREFTYPE_INTHISFILE( offset)) {
2278
        /* external typelib */
2279
        MSFT_ImpInfo impinfo;
2280
        TLBImpLib *pImpLib;
2281

2282 2283
        TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc));

2284 2285
        MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx,
                          pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc));
2286 2287 2288 2289 2290 2291

        LIST_FOR_EACH_ENTRY(pImpLib, &pcx->pLibInfo->implib_list, TLBImpLib, entry)
            if(pImpLib->offset==impinfo.oImpFile)
                break;

        if(&pImpLib->entry != &pcx->pLibInfo->implib_list){
2292 2293
            ref->reference = offset;
            ref->pImpTLInfo = pImpLib;
2294
            if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
2295 2296 2297
                MSFT_ReadGuid(&ref->guid, impinfo.oGuid, pcx);
                TRACE("importing by guid %s\n", debugstr_guid(&ref->guid));
                ref->index = TLB_REF_USE_GUID;
2298
            } else
2299
                ref->index = impinfo.oGuid;
2300
        }else{
2301
            ERR("Cannot find a reference\n");
2302 2303
            ref->reference = -1;
            ref->pImpTLInfo = TLB_REF_NOT_FOUND;
2304 2305 2306
        }
    }else{
        /* in this typelib */
2307 2308 2309
        ref->index = MSFT_HREFTYPE_INDEX(offset);
        ref->reference = offset;
        ref->pImpTLInfo = TLB_REF_INTERNAL;
2310 2311 2312 2313
    }
}

/* process Implemented Interfaces of a com class */
2314 2315
static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
			    int offset)
2316 2317
{
    int i;
2318
    MSFT_RefRecord refrec;
2319
    TLBImplType *pImpl;
2320

2321
    TRACE_(typelib)("\n");
2322

2323
    pTI->impltypes = TLBImplType_Constructor(count);
2324
    pImpl = pTI->impltypes;
2325 2326
    for(i=0;i<count;i++){
        if(offset<0) break; /* paranoia */
2327
        MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
2328
        MSFT_DoRefType(pcx, pTI->pTypeLib, refrec.reftype);
2329 2330
        pImpl->hRef = refrec.reftype;
        pImpl->implflags=refrec.flags;
2331
        MSFT_CustData(pcx, refrec.oCustData, &pImpl->custdata_list);
2332
        offset=refrec.onext;
2333
        ++pImpl;
2334 2335 2336 2337 2338
    }
}
/*
 * process a typeinfo record
 */
2339
static ITypeInfoImpl * MSFT_DoTypeInfo(
2340 2341 2342
    TLBContext *pcx,
    int count,
    ITypeLibImpl * pLibInfo)
2343
{
2344
    MSFT_TypeInfoBase tiBase;
2345 2346
    ITypeInfoImpl *ptiRet;

2347
    TRACE_(typelib)("count=%u\n", count);
2348

2349
    ptiRet = ITypeInfoImpl_Constructor();
2350 2351
    MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
                      pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
2352

2353
/* this is where we are coming from */
2354
    ptiRet->pTypeLib = pLibInfo;
2355 2356
    ptiRet->index=count;
/* fill in the typeattr fields */
2357

2358
    MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx);
2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369
    ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid;   /* FIXME: correct? */
    ptiRet->TypeAttr.lpstrSchema=NULL;              /* reserved */
    ptiRet->TypeAttr.cbSizeInstance=tiBase.size;
    ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF;
    ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement);
    ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement);
    ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */
    ptiRet->TypeAttr.wTypeFlags=tiBase.flags;
    ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version);
    ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version);
    ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes;
2370
    ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */
2371
    if(ptiRet->TypeAttr.typekind == TKIND_ALIAS)
2372
        MSFT_GetTdesc(pcx, tiBase.datatype1,
2373
            &ptiRet->TypeAttr.tdescAlias, ptiRet);
2374

2375 2376 2377 2378
/*  FIXME: */
/*    IDLDESC  idldescType; *//* never saw this one != zero  */

/* name, eventually add to a hash table */
2379
    ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
2380
    ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
2381
    TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name));
2382
    /* help info */
2383
    ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
2384 2385
    ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
    ptiRet->dwHelpContext=tiBase.helpcontext;
2386 2387 2388 2389

    if (ptiRet->TypeAttr.typekind == TKIND_MODULE)
        ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);

2390 2391 2392 2393 2394
/* note: InfoType's Help file and HelpStringDll come from the containing
 * library. Further HelpString and Docstring appear to be the same thing :(
 */
    /* functions */
    if(ptiRet->TypeAttr.cFuncs >0 )
2395
        MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2396
		    ptiRet->TypeAttr.cVars,
2397
		    tiBase.memoffset, &ptiRet->funcdescs);
2398 2399
    /* variables */
    if(ptiRet->TypeAttr.cVars >0 )
2400
        MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs,
2401
		   ptiRet->TypeAttr.cVars,
2402
		   tiBase.memoffset, &ptiRet->vardescs);
2403
    if(ptiRet->TypeAttr.cImplTypes >0 ) {
2404
        switch(ptiRet->TypeAttr.typekind)
2405 2406
        {
        case TKIND_COCLASS:
2407
            MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes ,
2408
                tiBase.datatype1);
2409 2410
            break;
        case TKIND_DISPATCH:
2411
            /* This is not -1 when the interface is a non-base dual interface or
Austin English's avatar
Austin English committed
2412
               when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
2413 2414 2415
               Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
               not this interface.
            */
2416

2417 2418
            if (tiBase.datatype1 != -1)
            {
2419
                ptiRet->impltypes = TLBImplType_Constructor(1);
2420
                ptiRet->impltypes[0].hRef = tiBase.datatype1;
2421
                MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2422
            }
2423
            break;
2424
        default:
2425
            ptiRet->impltypes = TLBImplType_Constructor(1);
2426
            MSFT_DoRefType(pcx, pLibInfo, tiBase.datatype1);
2427
            ptiRet->impltypes[0].hRef = tiBase.datatype1;
2428
            break;
2429
       }
2430
    }
2431
    MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->custdata_list);
2432

2433
    TRACE_(typelib)("%s guid: %s kind:%s\n",
2434
       debugstr_w(ptiRet->Name),
2435 2436
       debugstr_guid(&ptiRet->TypeAttr.guid),
       typekind_desc[ptiRet->TypeAttr.typekind]);
2437 2438
    if (TRACE_ON(typelib))
      dump_TypeInfo(ptiRet);
2439

2440
    return ptiRet;
2441 2442
}

2443 2444 2445 2446 2447
/* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
 * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
 * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
 * tradeoff here.
 */
2448
static struct list tlb_cache = LIST_INIT(tlb_cache);
2449 2450 2451 2452 2453
static CRITICAL_SECTION cache_section;
static CRITICAL_SECTION_DEBUG cache_section_debug =
{
    0, 0, &cache_section,
    { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
2454
      0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
2455 2456 2457 2458
};
static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };


2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
typedef struct TLB_PEFile
{
    const IUnknownVtbl *lpvtbl;
    LONG refs;
    HMODULE dll;
    HRSRC typelib_resource;
    HGLOBAL typelib_global;
    LPVOID typelib_base;
} TLB_PEFile;

static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, &IID_IUnknown))
    {
        *ppv = iface;
        IUnknown_AddRef(iface);
        return S_OK;
    }
    *ppv = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface)
{
    TLB_PEFile *This = (TLB_PEFile *)iface;
    return InterlockedIncrement(&This->refs);
}

static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
{
    TLB_PEFile *This = (TLB_PEFile *)iface;
    ULONG refs = InterlockedDecrement(&This->refs);
    if (!refs)
    {
        if (This->typelib_global)
            FreeResource(This->typelib_global);
        if (This->dll)
            FreeLibrary(This->dll);
2497
        heap_free(This);
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512
    }
    return refs;
}

static const IUnknownVtbl TLB_PEFile_Vtable =
{
    TLB_PEFile_QueryInterface,
    TLB_PEFile_AddRef,
    TLB_PEFile_Release
};

static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
{
    TLB_PEFile *This;

2513
    This = heap_alloc(sizeof(TLB_PEFile));
2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552
    if (!This)
        return E_OUTOFMEMORY;

    This->lpvtbl = &TLB_PEFile_Vtable;
    This->refs = 1;
    This->dll = NULL;
    This->typelib_resource = NULL;
    This->typelib_global = NULL;
    This->typelib_base = NULL;

    This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES |
                    LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);

    if (This->dll)
    {
        static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
        This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW);
        if (This->typelib_resource)
        {
            This->typelib_global = LoadResource(This->dll, This->typelib_resource);
            if (This->typelib_global)
            {
                This->typelib_base = LockResource(This->typelib_global);

                if (This->typelib_base)
                {
                    *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource);
                    *ppBase = This->typelib_base;
                    *ppFile = (IUnknown *)&This->lpvtbl;
                    return S_OK;
                }
            }
        }
    }

    TLB_PEFile_Release((IUnknown *)&This->lpvtbl);
    return TYPE_E_CANTLOADLIBRARY;
}

2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583
typedef struct TLB_NEFile
{
    const IUnknownVtbl *lpvtbl;
    LONG refs;
    LPVOID typelib_base;
} TLB_NEFile;

static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, &IID_IUnknown))
    {
        *ppv = iface;
        IUnknown_AddRef(iface);
        return S_OK;
    }
    *ppv = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
{
    TLB_NEFile *This = (TLB_NEFile *)iface;
    return InterlockedIncrement(&This->refs);
}

static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
{
    TLB_NEFile *This = (TLB_NEFile *)iface;
    ULONG refs = InterlockedDecrement(&This->refs);
    if (!refs)
    {
2584 2585
        heap_free(This->typelib_base);
        heap_free(This);
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653
    }
    return refs;
}

static const IUnknownVtbl TLB_NEFile_Vtable =
{
    TLB_NEFile_QueryInterface,
    TLB_NEFile_AddRef,
    TLB_NEFile_Release
};

/***********************************************************************
 *           read_xx_header         [internal]
 */
static int read_xx_header( HFILE lzfd )
{
    IMAGE_DOS_HEADER mzh;
    char magic[3];

    LZSeek( lzfd, 0, SEEK_SET );
    if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
        return 0;
    if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
        return 0;

    LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
    if ( 2 != LZRead( lzfd, magic, 2 ) )
        return 0;

    LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );

    if ( magic[0] == 'N' && magic[1] == 'E' )
        return IMAGE_OS2_SIGNATURE;
    if ( magic[0] == 'P' && magic[1] == 'E' )
        return IMAGE_NT_SIGNATURE;

    magic[2] = '\0';
    WARN("Can't handle %s files.\n", magic );
    return 0;
}


/***********************************************************************
 *           find_ne_resource         [internal]
 */
static BOOL find_ne_resource( HFILE lzfd, LPCSTR typeid, LPCSTR resid,
                                DWORD *resLen, DWORD *resOff )
{
    IMAGE_OS2_HEADER nehd;
    NE_TYPEINFO *typeInfo;
    NE_NAMEINFO *nameInfo;
    DWORD nehdoffset;
    LPBYTE resTab;
    DWORD resTabSize;
    int count;

    /* Read in NE header */
    nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
    if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;

    resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
    if ( !resTabSize )
    {
        TRACE("No resources in NE dll\n" );
        return FALSE;
    }

    /* Read in resource table */
2654
    resTab = heap_alloc( resTabSize );
2655 2656 2657 2658 2659
    if ( !resTab ) return FALSE;

    LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
    if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
    {
2660
        heap_free( resTab );
2661 2662 2663 2664 2665 2666
        return FALSE;
    }

    /* Find resource */
    typeInfo = (NE_TYPEINFO *)(resTab + 2);

2667
    if (!IS_INTRESOURCE(typeid))  /* named type */
2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691
    {
        BYTE len = strlen( typeid );
        while (typeInfo->type_id)
        {
            if (!(typeInfo->type_id & 0x8000))
            {
                BYTE *p = resTab + typeInfo->type_id;
                if ((*p == len) && !strncasecmp( (char*)p+1, typeid, len )) goto found_type;
            }
            typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
                                       typeInfo->count * sizeof(NE_NAMEINFO));
        }
    }
    else  /* numeric type id */
    {
        WORD id = LOWORD(typeid) | 0x8000;
        while (typeInfo->type_id)
        {
            if (typeInfo->type_id == id) goto found_type;
            typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
                                       typeInfo->count * sizeof(NE_NAMEINFO));
        }
    }
    TRACE("No typeid entry found for %p\n", typeid );
2692
    heap_free( resTab );
2693 2694 2695 2696 2697
    return FALSE;

 found_type:
    nameInfo = (NE_NAMEINFO *)(typeInfo + 1);

2698
    if (!IS_INTRESOURCE(resid))  /* named resource */
2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714
    {
        BYTE len = strlen( resid );
        for (count = typeInfo->count; count > 0; count--, nameInfo++)
        {
            BYTE *p = resTab + nameInfo->id;
            if (nameInfo->id & 0x8000) continue;
            if ((*p == len) && !strncasecmp( (char*)p+1, resid, len )) goto found_name;
        }
    }
    else  /* numeric resource id */
    {
        WORD id = LOWORD(resid) | 0x8000;
        for (count = typeInfo->count; count > 0; count--, nameInfo++)
            if (nameInfo->id == id) goto found_name;
    }
    TRACE("No resid entry found for %p\n", typeid );
2715
    heap_free( resTab );
2716 2717 2718 2719 2720 2721 2722
    return FALSE;

 found_name:
    /* Return resource data */
    if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
    if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;

2723
    heap_free( resTab );
2724 2725 2726 2727 2728 2729 2730 2731
    return TRUE;
}

static HRESULT TLB_NEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile){

    HFILE lzfd = -1;
    OFSTRUCT ofs;
    HRESULT hr = TYPE_E_CANTLOADLIBRARY;
2732
    TLB_NEFile *This;
2733

2734
    This = heap_alloc(sizeof(TLB_NEFile));
2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746
    if (!This) return E_OUTOFMEMORY;

    This->lpvtbl = &TLB_NEFile_Vtable;
    This->refs = 1;
    This->typelib_base = NULL;

    lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
    if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
    {
        DWORD reslen, offset;
        if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
        {
2747
            This->typelib_base = heap_alloc(reslen);
2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766
            if( !This->typelib_base )
                hr = E_OUTOFMEMORY;
            else
            {
                LZSeek( lzfd, offset, SEEK_SET );
                reslen = LZRead( lzfd, This->typelib_base, reslen );
                LZClose( lzfd );
                *ppBase = This->typelib_base;
                *pdwTLBLength = reslen;
                *ppFile = (IUnknown *)&This->lpvtbl;
                return S_OK;
            }
        }
    }

    if( lzfd >= 0) LZClose( lzfd );
    TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
    return hr;
}
2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806

typedef struct TLB_Mapping
{
    const IUnknownVtbl *lpvtbl;
    LONG refs;
    HANDLE file;
    HANDLE mapping;
    LPVOID typelib_base;
} TLB_Mapping;

static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, &IID_IUnknown))
    {
        *ppv = iface;
        IUnknown_AddRef(iface);
        return S_OK;
    }
    *ppv = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface)
{
    TLB_Mapping *This = (TLB_Mapping *)iface;
    return InterlockedIncrement(&This->refs);
}

static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
{
    TLB_Mapping *This = (TLB_Mapping *)iface;
    ULONG refs = InterlockedDecrement(&This->refs);
    if (!refs)
    {
        if (This->typelib_base)
            UnmapViewOfFile(This->typelib_base);
        if (This->mapping)
            CloseHandle(This->mapping);
        if (This->file != INVALID_HANDLE_VALUE)
            CloseHandle(This->file);
2807
        heap_free(This);
2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
    }
    return refs;
}

static const IUnknownVtbl TLB_Mapping_Vtable =
{
    TLB_Mapping_QueryInterface,
    TLB_Mapping_AddRef,
    TLB_Mapping_Release
};

static HRESULT TLB_Mapping_Open(LPCWSTR path, LPVOID *ppBase, DWORD *pdwTLBLength, IUnknown **ppFile)
{
    TLB_Mapping *This;

2823
    This = heap_alloc(sizeof(TLB_Mapping));
2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854
    if (!This)
        return E_OUTOFMEMORY;

    This->lpvtbl = &TLB_Mapping_Vtable;
    This->refs = 1;
    This->file = INVALID_HANDLE_VALUE;
    This->mapping = NULL;
    This->typelib_base = NULL;

    This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
    if (INVALID_HANDLE_VALUE != This->file)
    {
        This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
        if (This->mapping)
        {
            This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0);
            if(This->typelib_base)
            {
                /* retrieve file size */
                *pdwTLBLength = GetFileSize(This->file, NULL);
                *ppBase = This->typelib_base;
                *ppFile = (IUnknown *)&This->lpvtbl;
                return S_OK;
            }
        }
    }

    IUnknown_Release((IUnknown *)&This->lpvtbl);
    return TYPE_E_CANTLOADLIBRARY;
}

2855 2856 2857 2858 2859 2860
/****************************************************************************
 *	TLB_ReadTypeLib
 *
 * find the type of the typelib file and map the typelib resource into
 * the memory
 */
2861

2862
#define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
2863
static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
2864
{
2865
    ITypeLibImpl *entry;
2866
    HRESULT ret;
2867
    INT index = 1;
2868
    LPWSTR index_str, file = (LPWSTR)pszFileName;
2869 2870 2871
    LPVOID pBase = NULL;
    DWORD dwTLBLength = 0;
    IUnknown *pFile = NULL;
2872

2873
    *ppTypeLib = NULL;
2874

2875 2876
    index_str = strrchrW(pszFileName, '\\');
    if(index_str && *++index_str != '\0')
2877
    {
2878
        LPWSTR end_ptr;
2879
        LONG idx = strtolW(index_str, &end_ptr, 10);
2880
        if(*end_ptr == '\0')
2881
        {
2882 2883
            int str_len = index_str - pszFileName - 1;
            index = idx;
2884
            file = heap_alloc((str_len + 1) * sizeof(WCHAR));
2885 2886
            memcpy(file, pszFileName, str_len * sizeof(WCHAR));
            file[str_len] = 0;
2887 2888 2889
        }
    }

2890
    if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
2891
    {
2892 2893 2894 2895 2896 2897 2898 2899 2900 2901
        if(strchrW(file, '\\'))
        {
            lstrcpyW(pszPath, file);
        }
        else
        {
            int len = GetSystemDirectoryW(pszPath, cchPath);
            pszPath[len] = '\\';
            memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
        }
2902 2903
    }

2904
    if(file != pszFileName) heap_free(file);
2905

2906 2907
    TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);

2908 2909
    /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
    EnterCriticalSection(&cache_section);
2910
    LIST_FOR_EACH_ENTRY(entry, &tlb_cache, ITypeLibImpl, entry)
2911
    {
2912
        if (!strcmpiW(entry->path, pszPath) && entry->index == index)
2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
        {
            TRACE("cache hit\n");
            *ppTypeLib = (ITypeLib2*)entry;
            ITypeLib_AddRef(*ppTypeLib);
            LeaveCriticalSection(&cache_section);
            return S_OK;
        }
    }
    LeaveCriticalSection(&cache_section);

2923
    /* now actually load and parse the typelib */
2924

2925
    ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2926 2927
    if (ret == TYPE_E_CANTLOADLIBRARY)
        ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
2928 2929 2930
    if (ret == TYPE_E_CANTLOADLIBRARY)
        ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
    if (SUCCEEDED(ret))
2931
    {
2932
        if (dwTLBLength >= 4)
2933
        {
2934 2935 2936 2937 2938 2939
            DWORD dwSignature = FromLEDWord(*((DWORD*) pBase));
            if (dwSignature == MSFT_SIGNATURE)
                *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength);
            else if (dwSignature == SLTG_SIGNATURE)
                *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength);
            else
2940
            {
2941 2942
                FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
                ret = TYPE_E_CANTLOADLIBRARY;
2943 2944
            }
        }
2945 2946 2947
        else
            ret = TYPE_E_CANTLOADLIBRARY;
        IUnknown_Release(pFile);
2948 2949
    }

2950 2951
    if(*ppTypeLib) {
	ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
2952

2953
	TRACE("adding to cache\n");
2954
	impl->path = heap_alloc((strlenW(pszPath)+1) * sizeof(WCHAR));
2955
	lstrcpyW(impl->path, pszPath);
2956
	/* We should really canonicalise the path here. */
2957
        impl->index = index;
2958 2959 2960

        /* FIXME: check if it has added already in the meantime */
        EnterCriticalSection(&cache_section);
2961
        list_add_head(&tlb_cache, &impl->entry);
2962 2963 2964
        LeaveCriticalSection(&cache_section);
        ret = S_OK;
    } else
2965
	ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
2966

2967 2968 2969 2970 2971
    return ret;
}

/*================== ITypeLib(2) Methods ===================================*/

2972 2973 2974 2975
static ITypeLibImpl* TypeLibImpl_Constructor(void)
{
    ITypeLibImpl* pTypeLibImpl;

2976
    pTypeLibImpl = heap_alloc_zero(sizeof(ITypeLibImpl));
2977 2978 2979 2980 2981 2982
    if (!pTypeLibImpl) return NULL;

    pTypeLibImpl->lpVtbl = &tlbvt;
    pTypeLibImpl->lpVtblTypeComp = &tlbtcvt;
    pTypeLibImpl->ref = 1;

2983
    list_init(&pTypeLibImpl->implib_list);
2984
    list_init(&pTypeLibImpl->custdata_list);
2985
    list_init(&pTypeLibImpl->ref_list);
2986
    pTypeLibImpl->dispatch_href = -1;
2987

2988 2989 2990
    return pTypeLibImpl;
}

2991
/****************************************************************************
2992
 *	ITypeLib2_Constructor_MSFT
2993
 *
2994
 * loading an MSFT typelib from an in-memory image
2995
 */
2996
static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
2997 2998
{
    TLBContext cx;
2999
    LONG lPSegDir;
3000 3001
    MSFT_Header tlbHeader;
    MSFT_SegDir tlbSegDir;
3002 3003
    ITypeLibImpl * pTypeLibImpl;

3004
    TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
3005

3006
    pTypeLibImpl = TypeLibImpl_Constructor();
3007 3008
    if (!pTypeLibImpl) return NULL;

3009
    /* get pointer to beginning of typelib data */
3010
    cx.pos = 0;
3011
    cx.oStart=0;
3012
    cx.mapping = pLib;
3013
    cx.pLibInfo = pTypeLibImpl;
3014
    cx.length = dwTLBLength;
3015

3016
    /* read header */
3017
    MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0);
3018 3019
    TRACE_(typelib)("header:\n");
    TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
3020
    if (tlbHeader.magic1 != MSFT_SIGNATURE) {
3021 3022 3023
	FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
	return NULL;
    }
3024 3025
    TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);

3026
    /* there is a small amount of information here until the next important
3027 3028
     * part:
     * the segment directory . Try to calculate the amount of data */
3029
    lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
3030

3031
    /* now read the segment directory */
3032
    TRACE("read segment directory (at %d)\n",lPSegDir);
3033
    MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
3034 3035
    cx.pTblDir = &tlbSegDir;

3036
    /* just check two entries */
3037 3038
    if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
    {
3039
        ERR("cannot find the table directory, ptr=0x%x\n",lPSegDir);
3040
	heap_free(pTypeLibImpl);
3041
	return NULL;
3042
    }
3043

3044 3045
    /* now fill our internal data */
    /* TLIBATTR fields */
3046
    MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx);
3047

3048
    pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid2;
3049 3050 3051 3052
    pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */
    pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version);
    pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version);
    pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */
3053

3054 3055
    pTypeLibImpl->lcid = tlbHeader.lcid;

3056
    /* name, eventually add to a hash table */
3057
    pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
3058

3059
    /* help info */
3060 3061
    pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
    pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
3062 3063 3064

    if( tlbHeader.varflags & HELPDLLFLAG)
    {
3065
            int offset;
3066
            MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
3067
            pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
3068 3069
    }

3070
    pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
3071

3072
    /* custom data */
3073 3074
    if(tlbHeader.CustomDataOffset >= 0)
    {
3075
        MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->custdata_list);
3076
    }
3077

3078
    /* fill in type descriptions */
3079 3080 3081
    if(tlbSegDir.pTypdescTab.length > 0)
    {
        int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
3082
        INT16 td[4];
3083
        pTypeLibImpl->ctTypeDesc = cTD;
3084
        pTypeLibImpl->pTypeDesc = heap_alloc_zero( cTD * sizeof(TYPEDESC));
3085
        MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
3086 3087
        for(i=0; i<cTD; )
	{
3088
            /* FIXME: add several sanity checks here */
3089 3090 3091 3092 3093
            pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
            if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
	    {
	        /* FIXME: check safearray */
                if(td[3] < 0)
3094
                    pTypeLibImpl->pTypeDesc[i].u.lptdesc = &std_typedesc[td[2]];
3095
                else
3096
                    pTypeLibImpl->pTypeDesc[i].u.lptdesc = &pTypeLibImpl->pTypeDesc[td[2]/8];
3097 3098 3099 3100
            }
	    else if(td[0] == VT_CARRAY)
            {
	        /* array descr table here */
3101
	        pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)(INT_PTR)td[2];  /* temp store offset in*/
3102
            }
3103 3104
            else if(td[0] == VT_USERDEFINED)
	    {
3105
                pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
3106
            }
3107
	    if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
3108
        }
3109

3110
        /* second time around to fill the array subscript info */
3111 3112 3113 3114 3115
        for(i=0;i<cTD;i++)
	{
            if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
            if(tlbSegDir.pArrayDescriptions.offset>0)
	    {
3116
                MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (INT_PTR)pTypeLibImpl->pTypeDesc[i].u.lpadesc);
3117
                pTypeLibImpl->pTypeDesc[i].u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
3118

3119
                if(td[1]<0)
3120
                    pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
3121
                else
3122
                    pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
3123

3124
                pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
3125 3126 3127

                for(j = 0; j<td[2]; j++)
		{
3128 3129 3130 3131
                    MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements,
                                      sizeof(INT), &cx, DO_NOT_SEEK);
                    MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound,
                                      sizeof(INT), &cx, DO_NOT_SEEK);
3132
                }
3133 3134 3135
            }
	    else
	    {
3136
                pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
3137
                ERR("didn't find array description data\n");
3138 3139 3140
            }
        }
    }
3141

3142
    /* imported type libs */
3143 3144
    if(tlbSegDir.pImpFiles.offset>0)
    {
3145
        TLBImpLib *pImpLib;
3146
        int oGuid, offset = tlbSegDir.pImpFiles.offset;
3147
        UINT16 size;
3148 3149 3150

        while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
	{
3151 3152
            char *name;

3153 3154
            pImpLib = heap_alloc_zero(sizeof(TLBImpLib));
            pImpLib->offset = offset - tlbSegDir.pImpFiles.offset;
3155
            MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
3156

3157 3158 3159
            MSFT_ReadLEDWords(&pImpLib->lcid,         sizeof(LCID),   &cx, DO_NOT_SEEK);
            MSFT_ReadLEWords(&pImpLib->wVersionMajor, sizeof(WORD),   &cx, DO_NOT_SEEK);
            MSFT_ReadLEWords(&pImpLib->wVersionMinor, sizeof(WORD),   &cx, DO_NOT_SEEK);
3160
            MSFT_ReadLEWords(& size,                      sizeof(UINT16), &cx, DO_NOT_SEEK);
3161

3162
            size >>= 2;
3163
            name = heap_alloc_zero(size+1);
3164
            MSFT_Read(name, size, &cx, DO_NOT_SEEK);
3165
            pImpLib->name = TLB_MultiByteToBSTR(name);
3166
            heap_free(name);
3167

3168
            MSFT_ReadGuid(&pImpLib->guid, oGuid, &cx);
3169
            offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
3170

3171
            list_add_tail(&pTypeLibImpl->implib_list, &pImpLib->entry);
3172 3173
        }
    }
3174

3175 3176 3177 3178
    pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
    if(pTypeLibImpl->dispatch_href != -1)
        MSFT_DoRefType(&cx, pTypeLibImpl, pTypeLibImpl->dispatch_href);

3179
    /* type infos */
3180
    if(tlbHeader.nrtypeinfos >= 0 )
3181
    {
3182
        ITypeInfoImpl **ppTI;
3183
        int i;
3184

3185 3186
        ppTI = pTypeLibImpl->typeinfos = heap_alloc_zero(sizeof(ITypeInfoImpl*) * tlbHeader.nrtypeinfos);

3187
        for(i = 0; i < tlbHeader.nrtypeinfos; i++)
3188
        {
3189
            *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
3190

3191
            ++ppTI;
3192
            (pTypeLibImpl->TypeInfoCount)++;
3193 3194 3195
        }
    }

3196 3197 3198 3199
    TRACE("(%p)\n", pTypeLibImpl);
    return (ITypeLib2*) pTypeLibImpl;
}

3200

3201
static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
3202 3203 3204 3205 3206
{
  char b[3];
  int i;
  short s;

3207
  if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222
    FIXME("Can't parse guid %s\n", debugstr_guid(guid));
    return FALSE;
  }

  guid->Data4[0] = s >> 8;
  guid->Data4[1] = s & 0xff;

  b[2] = '\0';
  for(i = 0; i < 6; i++) {
    memcpy(b, str + 24 + 2 * i, 2);
    guid->Data4[i + 2] = strtol(b, NULL, 16);
  }
  return TRUE;
}

3223
static WORD SLTG_ReadString(const char *ptr, BSTR *pBstr)
3224 3225 3226 3227 3228
{
    WORD bytelen;
    DWORD len;

    *pBstr = NULL;
3229
    bytelen = *(const WORD*)ptr;
3230 3231
    if(bytelen == 0xffff) return 2;
    len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
3232
    *pBstr = SysAllocStringLen(NULL, len);
3233 3234
    if (*pBstr)
        len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, *pBstr, len);
3235 3236 3237
    return bytelen + 2;
}

3238
static WORD SLTG_ReadStringA(const char *ptr, char **str)
3239 3240 3241 3242
{
    WORD bytelen;

    *str = NULL;
3243
    bytelen = *(const WORD*)ptr;
3244
    if(bytelen == 0xffff) return 2;
3245
    *str = heap_alloc(bytelen + 1);
3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277
    memcpy(*str, ptr + 2, bytelen);
    (*str)[bytelen] = '\0';
    return bytelen + 2;
}

static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl)
{
    char *ptr = pLibBlk;
    WORD w;

    if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) {
        FIXME("libblk magic = %04x\n", w);
	return 0;
    }

    ptr += 6;
    if((w = *(WORD*)ptr) != 0xffff) {
        FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w);
        ptr += w;
    }
    ptr += 2;

    ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString);

    ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile);

    pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
    ptr += 4;

    pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr;
    ptr += 2;

3278
    if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
3279
        pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
3280
    else
3281
        pTypeLibImpl->lcid = pTypeLibImpl->LibAttr.lcid = 0;
3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300
    ptr += 2;

    ptr += 4; /* skip res12 */

    pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr;
    ptr += 2;

    pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr;
    ptr += 2;

    pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr;
    ptr += 2;

    memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID));
    ptr += sizeof(GUID);

    return ptr - (char*)pLibBlk;
}

3301 3302 3303 3304 3305 3306 3307
/* stores a mapping between the sltg typeinfo's references and the typelib's HREFTYPEs */
typedef struct
{
    unsigned int num;
    HREFTYPE refs[1];
} sltg_ref_lookup_t;

3308 3309
static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
				    HREFTYPE *typelib_ref)
3310
{
3311
    if(table && typeinfo_ref < table->num)
3312 3313 3314 3315 3316
    {
        *typelib_ref = table->refs[typeinfo_ref];
        return S_OK;
    }

3317
    ERR_(typelib)("Unable to find reference\n");
3318 3319 3320 3321
    *typelib_ref = -1;
    return E_FAIL;
}

3322
static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
3323 3324 3325 3326 3327 3328
{
    BOOL done = FALSE;

    while(!done) {
        if((*pType & 0xe00) == 0xe00) {
	    pTD->vt = VT_PTR;
3329
	    pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3330 3331
	    pTD = pTD->u.lptdesc;
	}
3332
	switch(*pType & 0x3f) {
3333 3334
	case VT_PTR:
	    pTD->vt = VT_PTR;
3335
	    pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3336 3337 3338 3339 3340
	    pTD = pTD->u.lptdesc;
	    break;

	case VT_USERDEFINED:
	    pTD->vt = VT_USERDEFINED;
3341
            sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352
	    done = TRUE;
	    break;

	case VT_CARRAY:
	  {
	    /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
	       array */

	    SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));

	    pTD->vt = VT_CARRAY;
3353
	    pTD->u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC) + (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368
	    pTD->u.lpadesc->cDims = pSA->cDims;
	    memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound,
		   pSA->cDims * sizeof(SAFEARRAYBOUND));

	    pTD = &pTD->u.lpadesc->tdescElem;
	    break;
	  }

	case VT_SAFEARRAY:
	  {
	    /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this
	       useful? */

	    pType++;
	    pTD->vt = VT_SAFEARRAY;
3369
	    pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
3370 3371 3372 3373
	    pTD = pTD->u.lptdesc;
	    break;
	  }
	default:
3374
	    pTD->vt = *pType & 0x3f;
3375 3376 3377 3378 3379 3380 3381 3382
	    done = TRUE;
	    break;
	}
	pType++;
    }
    return pType;
}

3383 3384
static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
			 ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401
{
    /* Handle [in/out] first */
    if((*pType & 0xc000) == 0xc000)
        pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE;
    else if(*pType & 0x8000)
        pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT;
    else if(*pType & 0x4000)
        pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT;
    else
        pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN;

    if(*pType & 0x2000)
        pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID;

    if(*pType & 0x80)
        pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL;

3402
    return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
3403 3404
}

3405

3406
static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
3407 3408
			char *pNameTable)
{
3409
    unsigned int ref;
3410
    char *name;
3411
    TLBRefType *ref_type;
3412 3413
    sltg_ref_lookup_t *table;
    HREFTYPE typelib_ref;
3414 3415 3416

    if(pRef->magic != SLTG_REF_MAGIC) {
        FIXME("Ref magic = %x\n", pRef->magic);
3417
	return NULL;
3418
    }
3419
    name = ( (char*)pRef->names + pRef->number);
3420

3421
    table = heap_alloc(sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
3422 3423 3424 3425 3426 3427 3428
    table->num = pRef->number >> 3;

    /* FIXME should scan the existing list and reuse matching refs added by previous typeinfos */

    /* We don't want the first href to be 0 */
    typelib_ref = (list_count(&pTL->ref_list) + 1) << 2;

3429 3430 3431 3432
    for(ref = 0; ref < pRef->number >> 3; ref++) {
        char *refname;
	unsigned int lib_offs, type_num;

3433
	ref_type = heap_alloc_zero(sizeof(TLBRefType));
3434 3435 3436

	name += SLTG_ReadStringA(name, &refname);
	if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
3437
	    FIXME_(typelib)("Can't sscanf ref\n");
3438
	if(lib_offs != 0xffff) {
3439
	    TLBImpLib *import;
3440

3441 3442 3443 3444 3445
            LIST_FOR_EACH_ENTRY(import, &pTL->implib_list, TLBImpLib, entry)
                if(import->offset == lib_offs)
                    break;

            if(&import->entry == &pTL->implib_list) {
3446 3447 3448
	        char fname[MAX_PATH+1];
		int len;

3449 3450
		import = heap_alloc_zero(sizeof(*import));
		import->offset = lib_offs;
3451
		TLB_GUIDFromString( pNameTable + lib_offs + 4,
3452
				    &import->guid);
3453
		if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
3454 3455 3456
			  &import->wVersionMajor,
			  &import->wVersionMinor,
			  &import->lcid, fname) != 4) {
3457
		  FIXME_(typelib)("can't sscanf ref %s\n",
3458 3459 3460 3461 3462 3463
			pNameTable + lib_offs + 40);
		}
		len = strlen(fname);
		if(fname[len-1] != '#')
		    FIXME("fname = %s\n", fname);
		fname[len-1] = '\0';
3464 3465
		import->name = TLB_MultiByteToBSTR(fname);
		list_add_tail(&pTL->implib_list, &import->entry);
3466
	    }
3467
	    ref_type->pImpTLInfo = import;
3468 3469

            /* Store a reference to IDispatch */
3470
            if(pTL->dispatch_href == -1 && IsEqualGUID(&import->guid, &IID_StdOle) && type_num == 4)
3471
                pTL->dispatch_href = typelib_ref;
3472

3473
	} else { /* internal ref */
3474
	  ref_type->pImpTLInfo = TLB_REF_INTERNAL;
3475
	}
3476
	ref_type->reference = typelib_ref;
3477
	ref_type->index = type_num;
3478

3479
	heap_free(refname);
3480
        list_add_tail(&pTL->ref_list, &ref_type->entry);
3481 3482 3483

        table->refs[ref] = typelib_ref;
        typelib_ref += 4;
3484 3485
    }
    if((BYTE)*name != SLTG_REF_MAGIC)
3486
      FIXME_(typelib)("End of ref block magic = %x\n", *name);
3487
    dump_TLBRefType(pTL);
3488
    return table;
3489 3490
}

3491
static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
3492
			  BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
3493
{
3494
    SLTG_ImplInfo *info;
3495
    TLBImplType *pImplType;
3496 3497 3498 3499 3500 3501 3502 3503
    /* I don't really get this structure, usually it's 0x16 bytes
       long, but iuser.tlb contains some that are 0x18 bytes long.
       That's ok because we can use the next ptr to jump to the next
       one. But how do we know the length of the last one?  The WORD
       at offs 0x8 might be the clue.  For now I'm just assuming that
       the last one is the regular 0x16 bytes. */

    info = (SLTG_ImplInfo*)pBlk;
3504 3505 3506 3507 3508 3509 3510 3511
    while(1){
        pTI->TypeAttr.cImplTypes++;
        if(info->next == 0xffff)
            break;
        info = (SLTG_ImplInfo*)(pBlk + info->next);
    }

    info = (SLTG_ImplInfo*)pBlk;
3512
    pTI->impltypes = TLBImplType_Constructor(pTI->TypeAttr.cImplTypes);
3513
    pImplType = pTI->impltypes;
3514
    while(1) {
3515 3516 3517
	sltg_get_typelib_ref(ref_lookup, info->ref, &pImplType->hRef);
	pImplType->implflags = info->impltypeflags;
	++pImplType;
3518

3519
	if(info->next == 0xffff)
3520 3521
	    break;
	if(OneOnly)
3522
	    FIXME_(typelib)("Interface inheriting more than one interface\n");
3523
	info = (SLTG_ImplInfo*)(pBlk + info->next);
3524
    }
3525
    info++; /* see comment at top of function */
3526 3527 3528
    return (char*)info;
}

3529 3530
static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
			const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3531
{
3532
  TLBVarDesc *pVarDesc;
3533
  BSTR bstrPrevName = NULL;
3534 3535 3536 3537
  SLTG_Variable *pItem;
  unsigned short i;
  WORD *pType;

3538
  pVarDesc = pTI->vardescs = TLBVarDesc_Constructor(cVars);
3539

3540
  for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
3541
      pItem = (SLTG_Variable *)(pBlk + pItem->next), i++, ++pVarDesc) {
3542

3543
      pVarDesc->vardesc.memid = pItem->memid;
3544

3545 3546
      if (pItem->magic != SLTG_VAR_MAGIC &&
          pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
3547 3548 3549 3550
	  FIXME_(typelib)("var magic = %02x\n", pItem->magic);
	  return;
      }

3551
      if (pItem->name == 0xfffe)
3552
        pVarDesc->Name = SysAllocString(bstrPrevName);
3553
      else
3554
        pVarDesc->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable);
3555

3556
      TRACE_(typelib)("name: %s\n", debugstr_w(pVarDesc->Name));
3557
      TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
3558
      TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
3559

3560 3561 3562 3563 3564 3565 3566 3567 3568
      if(pItem->flags & 0x02)
	  pType = &pItem->type;
      else
	  pType = (WORD*)(pBlk + pItem->type);

      if (pItem->flags & ~0xda)
        FIXME_(typelib)("unhandled flags = %02x\n", pItem->flags & ~0xda);

      SLTG_DoElem(pType, pBlk,
3569
		  &pVarDesc->vardesc.elemdescVar, ref_lookup);
3570

3571 3572
      if (TRACE_ON(typelib)) {
          char buf[300];
3573
          dump_TypeDesc(&pVarDesc->vardesc.elemdescVar.tdesc, buf);
3574 3575 3576
          TRACE_(typelib)("elemdescVar: %s\n", buf);
      }

3577 3578
      if (pItem->flags & 0x40) {
        TRACE_(typelib)("VAR_DISPATCH\n");
3579
        pVarDesc->vardesc.varkind = VAR_DISPATCH;
3580 3581 3582
      }
      else if (pItem->flags & 0x10) {
        TRACE_(typelib)("VAR_CONST\n");
3583 3584 3585
        pVarDesc->vardesc.varkind = VAR_CONST;
        pVarDesc->vardesc.u.lpvarValue = heap_alloc(sizeof(VARIANT));
        V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_INT;
3586
        if (pItem->flags & 0x08)
3587
          V_INT(pVarDesc->vardesc.u.lpvarValue) = pItem->byte_offs;
3588
        else {
3589
          switch (pVarDesc->vardesc.elemdescVar.tdesc.vt)
3590 3591 3592 3593 3594 3595
          {
            case VT_LPSTR:
            case VT_LPWSTR:
            case VT_BSTR:
            {
              WORD len = *(WORD *)(pBlk + pItem->byte_offs);
3596 3597 3598 3599 3600 3601 3602 3603 3604
              BSTR str;
              TRACE_(typelib)("len = %u\n", len);
              if (len == 0xffff) {
                str = NULL;
              } else {
                INT alloc_len = MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, NULL, 0);
                str = SysAllocStringLen(NULL, alloc_len);
                MultiByteToWideChar(CP_ACP, 0, pBlk + pItem->byte_offs + 2, len, str, alloc_len);
              }
3605 3606
              V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_BSTR;
              V_BSTR(pVarDesc->vardesc.u.lpvarValue) = str;
3607 3608 3609 3610 3611 3612
              break;
            }
            case VT_I2:
            case VT_UI2:
            case VT_I4:
            case VT_UI4:
3613 3614
            case VT_INT:
            case VT_UINT:
3615
              V_INT(pVarDesc->vardesc.u.lpvarValue) =
3616 3617 3618
                *(INT*)(pBlk + pItem->byte_offs);
              break;
            default:
3619
              FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", pVarDesc->vardesc.elemdescVar.tdesc.vt);
3620 3621
          }
        }
3622 3623 3624
      }
      else {
        TRACE_(typelib)("VAR_PERINSTANCE\n");
3625 3626
        pVarDesc->vardesc.u.oInst = pItem->byte_offs;
        pVarDesc->vardesc.varkind = VAR_PERINSTANCE;
3627 3628
      }

3629
      if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
3630
        pVarDesc->vardesc.wVarFlags = pItem->varflags;
3631

3632
      if (pItem->flags & 0x80)
3633
        pVarDesc->vardesc.wVarFlags |= VARFLAG_FREADONLY;
3634

3635
      bstrPrevName = pVarDesc->Name;
3636 3637 3638 3639
  }
  pTI->TypeAttr.cVars = cVars;
}

3640 3641
static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
			 unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
3642 3643
{
    SLTG_Function *pFunc;
3644
    unsigned short i;
3645 3646
    TLBFuncDesc *pFuncDesc;

3647
    pTI->funcdescs = TLBFuncDesc_Constructor(cFuncs);
3648

3649 3650 3651
    pFuncDesc = pTI->funcdescs;
    for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs && pFunc != (SLTG_Function*)0xFFFF;
	pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++, ++pFuncDesc) {
3652 3653 3654 3655

        int param;
	WORD *pType, *pArg;

3656 3657
        switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
        case SLTG_FUNCTION_MAGIC:
3658
            pFuncDesc->funcdesc.funckind = FUNC_PUREVIRTUAL;
3659 3660
            break;
        case SLTG_DISPATCH_FUNCTION_MAGIC:
3661
            pFuncDesc->funcdesc.funckind = FUNC_DISPATCH;
3662 3663
            break;
        case SLTG_STATIC_FUNCTION_MAGIC:
3664
            pFuncDesc->funcdesc.funckind = FUNC_STATIC;
3665 3666 3667
            break;
        default:
	    FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
3668
	    continue;
3669
	}
3670
	pFuncDesc->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable);
3671

3672 3673 3674 3675 3676 3677
	pFuncDesc->funcdesc.memid = pFunc->dispid;
	pFuncDesc->funcdesc.invkind = pFunc->inv >> 4;
	pFuncDesc->funcdesc.callconv = pFunc->nacc & 0x7;
	pFuncDesc->funcdesc.cParams = pFunc->nacc >> 3;
	pFuncDesc->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1;
	pFuncDesc->funcdesc.oVft = pFunc->vtblpos & ~1;
3678

3679
	if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
3680
	    pFuncDesc->funcdesc.wFuncFlags = pFunc->funcflags;
3681 3682 3683 3684

	if(pFunc->retnextopt & 0x80)
	    pType = &pFunc->rettype;
	else
3685
	    pType = (WORD*)(pBlk + pFunc->rettype);
3686

3687
	SLTG_DoElem(pType, pBlk, &pFuncDesc->funcdesc.elemdescFunc, ref_lookup);
3688

3689 3690
	pFuncDesc->funcdesc.lprgelemdescParam =
	  heap_alloc_zero(pFuncDesc->funcdesc.cParams * sizeof(ELEMDESC));
3691
	pFuncDesc->pParamDesc = TLBParDesc_Constructor(pFuncDesc->funcdesc.cParams);
3692

3693
	pArg = (WORD*)(pBlk + pFunc->arg_off);
3694

3695
	for(param = 0; param < pFuncDesc->funcdesc.cParams; param++) {
3696
	    char *paramName = pNameTable + *pArg;
3697 3698 3699 3700 3701 3702 3703 3704
	    BOOL HaveOffs;
	    /* If arg type follows then paramName points to the 2nd
	       letter of the name, else the next WORD is an offset to
	       the arg type and paramName points to the first letter.
	       So let's take one char off paramName and see if we're
	       pointing at an alpha-numeric char.  However if *pArg is
	       0xffff or 0xfffe then the param has no name, the former
	       meaning that the next WORD is the type, the latter
3705
	       meaning that the next WORD is an offset to the type. */
3706 3707 3708 3709 3710 3711 3712 3713

	    HaveOffs = FALSE;
	    if(*pArg == 0xffff)
	        paramName = NULL;
	    else if(*pArg == 0xfffe) {
	        paramName = NULL;
		HaveOffs = TRUE;
	    }
3714
	    else if(paramName[-1] && !isalnum(paramName[-1]))
3715
	        HaveOffs = TRUE;
3716 3717 3718

	    pArg++;

3719
	    if(HaveOffs) { /* the next word is an offset to type */
3720 3721
	        pType = (WORD*)(pBlk + *pArg);
		SLTG_DoElem(pType, pBlk,
3722
			    &pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
3723 3724 3725 3726
		pArg++;
	    } else {
		if(paramName)
		  paramName--;
3727
		pArg = SLTG_DoElem(pArg, pBlk,
3728
                                   &pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
3729 3730 3731
	    }

	    /* Are we an optional param ? */
3732 3733 3734
	    if(pFuncDesc->funcdesc.cParams - param <=
	       pFuncDesc->funcdesc.cParamsOpt)
	      pFuncDesc->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
3735 3736

	    if(paramName) {
3737
	        pFuncDesc->pParamDesc[param].Name =
3738
		  TLB_MultiByteToBSTR(paramName);
3739
	    } else {
3740 3741
	        pFuncDesc->pParamDesc[param].Name =
                  SysAllocString(pFuncDesc->Name);
3742 3743 3744
	    }
	}
    }
3745 3746 3747 3748 3749 3750 3751
    pTI->TypeAttr.cFuncs = cFuncs;
}

static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
				char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
				SLTG_TypeInfoTail *pTITail)
{
3752
    char *pFirstItem;
3753
    sltg_ref_lookup_t *ref_lookup = NULL;
3754 3755

    if(pTIHeader->href_table != 0xffffffff) {
3756
        ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3757 3758 3759
		    pNameTable);
    }

3760
    pFirstItem = pBlk;
3761 3762

    if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3763
        SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
3764
    }
3765
    heap_free(ref_lookup);
3766 3767 3768 3769 3770
}


static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
				  char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3771
				  const SLTG_TypeInfoTail *pTITail)
3772
{
3773
    char *pFirstItem;
3774
    sltg_ref_lookup_t *ref_lookup = NULL;
3775 3776

    if(pTIHeader->href_table != 0xffffffff) {
3777
        ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3778 3779 3780
		    pNameTable);
    }

3781
    pFirstItem = pBlk;
3782 3783

    if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
3784
        SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
3785 3786 3787
    }

    if (pTITail->funcs_off != 0xffff)
3788 3789
        SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);

3790
    heap_free(ref_lookup);
3791

3792
    if (TRACE_ON(typelib))
3793
        dump_TLBFuncDesc(pTI->funcdescs, pTI->TypeAttr.cFuncs);
3794 3795
}

3796
static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
3797 3798
			       const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
			       const SLTG_TypeInfoTail *pTITail)
3799
{
3800
  SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3801 3802
}

3803 3804
static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
			      char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3805
			      const SLTG_TypeInfoTail *pTITail)
3806
{
3807
  WORD *pType;
3808
  sltg_ref_lookup_t *ref_lookup = NULL;
3809

3810 3811 3812 3813 3814 3815
  if (pTITail->simple_alias) {
    /* if simple alias, no more processing required */
    pTI->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt;
    return;
  }

3816
  if(pTIHeader->href_table != 0xffffffff) {
3817
      ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3818 3819 3820
		  pNameTable);
  }

3821 3822 3823
  /* otherwise it is an offset to a type */
  pType = (WORD *)(pBlk + pTITail->tdescalias_vt);

3824 3825
  SLTG_DoType(pType, pBlk, &pTI->TypeAttr.tdescAlias, ref_lookup);

3826
  heap_free(ref_lookup);
3827 3828
}

3829 3830
static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
				 char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3831
				 const SLTG_TypeInfoTail *pTITail)
3832
{
3833
  sltg_ref_lookup_t *ref_lookup = NULL;
3834
  if (pTIHeader->href_table != 0xffffffff)
3835
      ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3836 3837
                                  pNameTable);

3838
  if (pTITail->vars_off != 0xffff)
3839
    SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3840

3841
  if (pTITail->funcs_off != 0xffff)
3842
    SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3843

3844 3845 3846
  if (pTITail->impls_off != 0xffff)
    SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);

3847
  /* this is necessary to cope with MSFT typelibs that set cFuncs to the number
3848
   * of dispinterface functions including the IDispatch ones, so
3849 3850 3851
   * ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
  pTI->TypeAttr.cbSizeVft = pTI->TypeAttr.cFuncs * sizeof(void *);

3852
  heap_free(ref_lookup);
3853
  if (TRACE_ON(typelib))
3854
      dump_TLBFuncDesc(pTI->funcdescs, pTI->TypeAttr.cFuncs);
3855 3856
}

3857
static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
3858 3859
			     const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
			     const SLTG_TypeInfoTail *pTITail)
3860
{
3861
  SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
3862 3863
}

3864 3865
static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
			       char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
3866
			       const SLTG_TypeInfoTail *pTITail)
3867
{
3868
  sltg_ref_lookup_t *ref_lookup = NULL;
3869
  if (pTIHeader->href_table != 0xffffffff)
3870
      ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
3871 3872 3873
                                  pNameTable);

  if (pTITail->vars_off != 0xffff)
3874
    SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
3875 3876

  if (pTITail->funcs_off != 0xffff)
3877
    SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
3878
  heap_free(ref_lookup);
3879 3880
  if (TRACE_ON(typelib))
    dump_TypeInfo(pTI);
3881 3882
}

3883
/* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
3884
   manageable copy of it into this */
3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920
typedef struct {
  WORD small_no;
  char *index_name;
  char *other_name;
  WORD res1a;
  WORD name_offs;
  WORD more_bytes;
  char *extra;
  WORD res20;
  DWORD helpcontext;
  WORD res26;
  GUID uuid;
} SLTG_InternalOtherTypeInfo;

/****************************************************************************
 *	ITypeLib2_Constructor_SLTG
 *
 * loading a SLTG typelib from an in-memory image
 */
static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
{
    ITypeLibImpl *pTypeLibImpl;
    SLTG_Header *pHeader;
    SLTG_BlkEntry *pBlkEntry;
    SLTG_Magic *pMagic;
    SLTG_Index *pIndex;
    SLTG_Pad9 *pPad9;
    LPVOID pBlk, pFirstBlk;
    SLTG_LibBlk *pLibBlk;
    SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks;
    char *pAfterOTIBlks = NULL;
    char *pNameTable, *ptr;
    int i;
    DWORD len, order;
    ITypeInfoImpl **ppTypeInfoImpl;

3921
    TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
3922 3923


3924 3925
    pTypeLibImpl = TypeLibImpl_Constructor();
    if (!pTypeLibImpl) return NULL;
3926 3927

    pHeader = pLib;
3928

3929
    TRACE_(typelib)("header:\n");
3930
    TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
3931
	  pHeader->nrOfFileBlks );
3932
    if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
3933
	FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
3934 3935 3936
	      pHeader->SLTG_magic);
	return NULL;
    }
3937

3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949
    /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */
    pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2;

    /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */
    pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1);

    /* Next we have a magic block */
    pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1);

    /* Let's see if we're still in sync */
    if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC,
	      sizeof(SLTG_COMPOBJ_MAGIC))) {
3950
        FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
3951 3952 3953 3954
	return NULL;
    }
    if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
	      sizeof(SLTG_DIR_MAGIC))) {
3955
        FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
3956 3957 3958 3959 3960 3961 3962
	return NULL;
    }

    pIndex = (SLTG_Index*)(pMagic+1);

    pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);

3963
    pFirstBlk = pPad9 + 1;
3964 3965 3966 3967 3968 3969

    /* We'll set up a ptr to the main library block, which is the last one. */

    for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
	  pBlkEntry[order].next != 0;
	  order = pBlkEntry[order].next - 1, i++) {
3970
       pBlk = (char*)pBlk + pBlkEntry[order].len;
3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982
    }
    pLibBlk = pBlk;

    len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);

    /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
       interspersed */

    len += 0x40;

    /* And now TypeInfoCount of SLTG_OtherTypeInfo */

3983
    pOtherTypeInfoBlks = heap_alloc_zero(sizeof(*pOtherTypeInfoBlks) * pTypeLibImpl->TypeInfoCount);
3984 3985 3986


    ptr = (char*)pLibBlk + len;
3987

3988 3989 3990 3991 3992 3993 3994 3995 3996
    for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) {
	WORD w, extra;
	len = 0;

	pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr;

	w = *(WORD*)(ptr + 2);
	if(w != 0xffff) {
	    len += w;
3997
	    pOtherTypeInfoBlks[i].index_name = heap_alloc(w+1);
3998 3999 4000 4001 4002
	    memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
	    pOtherTypeInfoBlks[i].index_name[w] = '\0';
	}
	w = *(WORD*)(ptr + 4 + len);
	if(w != 0xffff) {
4003
	    TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
4004
	    len += w;
4005
	    pOtherTypeInfoBlks[i].other_name = heap_alloc(w+1);
4006 4007 4008 4009 4010 4011 4012
	    memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w);
	    pOtherTypeInfoBlks[i].other_name[w] = '\0';
	}
	pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6);
	pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8);
	extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len);
	if(extra) {
4013
	    pOtherTypeInfoBlks[i].extra = heap_alloc(extra);
4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029
	    memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra);
	    len += extra;
	}
	pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len);
	pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len);
	pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len);
	memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID));
	len += sizeof(SLTG_OtherTypeInfo);
	ptr += len;
    }

    pAfterOTIBlks = ptr;

    /* Skip this WORD and get the next DWORD */
    len = *(DWORD*)(pAfterOTIBlks + 2);

4030 4031 4032
    /* Now add this to pLibBLk look at what we're pointing at and
       possibly add 0x20, then add 0x216, sprinkle a bit a magic
       dust and we should be pointing at the beginning of the name
4033
       table */
4034

4035 4036 4037 4038 4039 4040 4041 4042 4043
    pNameTable = (char*)pLibBlk + len;

   switch(*(WORD*)pNameTable) {
   case 0xffff:
       break;
   case 0x0200:
       pNameTable += 0x20;
       break;
   default:
4044
       FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
4045 4046 4047 4048
       break;
   }

    pNameTable += 0x216;
4049

4050 4051
    pNameTable += 2;

4052
    TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
4053 4054 4055 4056 4057 4058 4059

    pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name);


    /* Hopefully we now have enough ptrs set up to actually read in
       some TypeInfos.  It's not clear which order to do them in, so
       I'll just follow the links along the BlkEntry chain and read
4060
       them in the order in which they are in the file */
4061

4062 4063
    pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
    ppTypeInfoImpl = pTypeLibImpl->typeinfos;
4064 4065 4066 4067 4068 4069

    for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
	pBlkEntry[order].next != 0;
	order = pBlkEntry[order].next - 1, i++) {

      SLTG_TypeInfoHeader *pTIHeader;
4070
      SLTG_TypeInfoTail *pTITail;
4071
      SLTG_MemberHeader *pMemHeader;
4072 4073 4074

      if(strcmp(pBlkEntry[order].index_string + (char*)pMagic,
		pOtherTypeInfoBlks[i].index_name)) {
4075
	FIXME_(typelib)("Index strings don't match\n");
4076 4077 4078 4079 4080
	return NULL;
      }

      pTIHeader = pBlk;
      if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
4081
	FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
4082 4083
	return NULL;
      }
4084 4085
      TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
        "pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
4086 4087
        pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);

4088
      *ppTypeInfoImpl = ITypeInfoImpl_Constructor();
4089 4090 4091 4092 4093 4094
      (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
      (*ppTypeInfoImpl)->index = i;
      (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR(
					     pOtherTypeInfoBlks[i].name_offs +
					     pNameTable);
      (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
4095
      (*ppTypeInfoImpl)->TypeAttr.guid = pOtherTypeInfoBlks[i].uuid;
4096 4097 4098 4099 4100
      (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind;
      (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version;
      (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version;
      (*ppTypeInfoImpl)->TypeAttr.wTypeFlags =
	(pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
4101

4102 4103 4104
      if((*ppTypeInfoImpl)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
	(*ppTypeInfoImpl)->TypeAttr.typekind = TKIND_DISPATCH;

4105
      if((pTIHeader->typeflags1 & 7) != 2)
4106
	FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
4107
      if(pTIHeader->typeflags3 != 2)
4108
	FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
4109

4110
      TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
4111 4112 4113 4114 4115
	    debugstr_w((*ppTypeInfoImpl)->Name),
	    typekind_desc[pTIHeader->typekind],
	    debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid),
	    (*ppTypeInfoImpl)->TypeAttr.wTypeFlags);

4116 4117 4118 4119
      pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);

      pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);

4120 4121
      (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment;
      (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance;
4122
      (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft;
4123

4124 4125
      switch(pTIHeader->typekind) {
      case TKIND_ENUM:
4126 4127
	SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
                         pTIHeader, pTITail);
4128 4129 4130
	break;

      case TKIND_RECORD:
4131 4132
	SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
                           pTIHeader, pTITail);
4133 4134 4135
	break;

      case TKIND_INTERFACE:
4136 4137
	SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
                              pTIHeader, pTITail);
4138 4139 4140
	break;

      case TKIND_COCLASS:
4141 4142
	SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
                            pTIHeader, pTITail);
4143 4144
	break;

4145
      case TKIND_ALIAS:
4146 4147
	SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
                          pTIHeader, pTITail);
4148 4149 4150
	break;

      case TKIND_DISPATCH:
4151 4152
	SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
                             pTIHeader, pTITail);
4153 4154
	break;

4155 4156 4157 4158 4159
      case TKIND_MODULE:
	SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
                           pTIHeader, pTITail);
	break;

4160 4161 4162 4163 4164 4165
      default:
	FIXME("Not processing typekind %d\n", pTIHeader->typekind);
	break;

      }

4166
      /* could get cFuncs, cVars and cImplTypes from here
4167
		       but we've already set those */
4168
#define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182
      X(06);
      X(16);
      X(18);
      X(1a);
      X(1e);
      X(24);
      X(26);
      X(2a);
      X(2c);
      X(2e);
      X(30);
      X(32);
      X(34);
#undef X
4183
      ++ppTypeInfoImpl;
4184
      pBlk = (char*)pBlk + pBlkEntry[order].len;
4185 4186 4187 4188 4189 4190 4191
    }

    if(i != pTypeLibImpl->TypeInfoCount) {
      FIXME("Somehow processed %d TypeInfos\n", i);
      return NULL;
    }

4192
    heap_free(pOtherTypeInfoBlks);
4193 4194 4195
    return (ITypeLib2*)pTypeLibImpl;
}

4196 4197
/* ITypeLib::QueryInterface
 */
4198 4199 4200 4201
static HRESULT WINAPI ITypeLib2_fnQueryInterface(
	ITypeLib2 * iface,
	REFIID riid,
	VOID **ppvObject)
4202
{
4203
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4204

4205
    TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
4206

4207
    *ppvObject=NULL;
4208
    if(IsEqualIID(riid, &IID_IUnknown) ||
4209 4210 4211
       IsEqualIID(riid,&IID_ITypeLib)||
       IsEqualIID(riid,&IID_ITypeLib2))
    {
4212
        *ppvObject = This;
4213
    }
4214

4215 4216 4217
    if(*ppvObject)
    {
        ITypeLib2_AddRef(iface);
4218
        TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
4219 4220
        return S_OK;
    }
4221
    TRACE("-- Interface: E_NOINTERFACE\n");
4222 4223 4224 4225 4226
    return E_NOINTERFACE;
}

/* ITypeLib::AddRef
 */
4227
static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
4228
{
4229
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4230
    ULONG ref = InterlockedIncrement(&This->ref);
4231

4232
    TRACE("(%p)->ref was %u\n",This, ref - 1);
4233

4234
    return ref;
4235 4236 4237 4238
}

/* ITypeLib::Release
 */
4239
static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
4240
{
4241
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4242
    ULONG ref = InterlockedDecrement(&This->ref);
4243

4244
    TRACE("(%p)->(%u)\n",This, ref);
4245

4246
    if (!ref)
4247
    {
4248
      TLBImpLib *pImpLib, *pImpLibNext;
4249 4250
      TLBRefType *ref_type;
      void *cursor2;
4251
      int i;
4252

4253
      /* remove cache entry */
4254 4255 4256 4257
      if(This->path)
      {
          TRACE("removing from cache list\n");
          EnterCriticalSection(&cache_section);
4258 4259
          if(This->entry.next)
              list_remove(&This->entry);
4260
          LeaveCriticalSection(&cache_section);
4261
          heap_free(This->path);
4262
      }
4263
      TRACE(" destroying ITypeLib(%p)\n",This);
4264

4265 4266
      SysFreeString(This->Name);
      This->Name = NULL;
4267

4268 4269
      SysFreeString(This->DocString);
      This->DocString = NULL;
4270

4271 4272
      SysFreeString(This->HelpFile);
      This->HelpFile = NULL;
4273

4274 4275
      SysFreeString(This->HelpStringDll);
      This->HelpStringDll = NULL;
4276

4277
      TLB_FreeCustData(&This->custdata_list);
4278

4279 4280
      for (i = 0; i < This->ctTypeDesc; i++)
          if (This->pTypeDesc[i].vt == VT_CARRAY)
4281
              heap_free(This->pTypeDesc[i].u.lpadesc);
4282

4283
      heap_free(This->pTypeDesc);
4284

4285
      LIST_FOR_EACH_ENTRY_SAFE(pImpLib, pImpLibNext, &This->implib_list, TLBImpLib, entry)
4286
      {
4287 4288
          if (pImpLib->pImpTypeLib)
              ITypeLib_Release((ITypeLib *)pImpLib->pImpTypeLib);
4289
          SysFreeString(pImpLib->name);
4290

4291
          list_remove(&pImpLib->entry);
4292
          heap_free(pImpLib);
4293 4294
      }

4295 4296 4297
      LIST_FOR_EACH_ENTRY_SAFE(ref_type, cursor2, &This->ref_list, TLBRefType, entry)
      {
          list_remove(&ref_type->entry);
4298
          heap_free(ref_type);
4299 4300
      }

4301 4302 4303
      for (i = 0; i < This->TypeInfoCount; ++i)
          ITypeInfoImpl_Destroy(This->typeinfos[i]);
      heap_free(This->typeinfos);
4304
      heap_free(This);
4305 4306
      return 0;
    }
4307

4308
    return ref;
4309 4310 4311
}

/* ITypeLib::GetTypeInfoCount
4312
 *
4313 4314
 * Returns the number of type descriptions in the type library
 */
4315
static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
4316
{
4317
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4318
    TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
4319 4320 4321 4322 4323
    return This->TypeInfoCount;
}

/* ITypeLib::GetTypeInfo
 *
4324
 * retrieves the specified type description in the library.
4325
 */
4326
static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
4327
    ITypeLib2 *iface,
4328
    UINT index,
4329
    ITypeInfo **ppTInfo)
4330
{
4331
    ITypeLibImpl *This = (ITypeLibImpl*)iface;
4332

4333
    TRACE("%p %u %p\n", This, index, ppTInfo);
4334

4335 4336
    if(!ppTInfo)
        return E_INVALIDARG;
4337

4338
    if(index >= This->TypeInfoCount)
4339
        return TYPE_E_ELEMENTNOTFOUND;
4340

4341
    *ppTInfo = (ITypeInfo*)This->typeinfos[index];
4342
    ITypeInfo_AddRef(*ppTInfo);
4343

4344
    return S_OK;
4345 4346
}

4347

4348 4349 4350 4351
/* ITypeLibs::GetTypeInfoType
 *
 * Retrieves the type of a type description.
 */
4352
static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
4353 4354 4355
    ITypeLib2 *iface,
    UINT index,
    TYPEKIND *pTKind)
4356
{
4357
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4358

4359
    TRACE("(%p, %d, %p)\n", This, index, pTKind);
4360

4361 4362
    if(!pTKind)
        return E_INVALIDARG;
4363

4364
    if(index >= This->TypeInfoCount)
4365 4366
        return TYPE_E_ELEMENTNOTFOUND;

4367
    *pTKind = This->typeinfos[index]->TypeAttr.typekind;
4368 4369

    return S_OK;
4370 4371 4372 4373 4374 4375 4376
}

/* ITypeLib::GetTypeInfoOfGuid
 *
 * Retrieves the type description that corresponds to the specified GUID.
 *
 */
4377
static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
4378 4379 4380
    ITypeLib2 *iface,
    REFGUID guid,
    ITypeInfo **ppTInfo)
4381
{
4382
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4383
    UINT i;
4384

4385
    TRACE("%p %s %p\n", This, debugstr_guid(guid), ppTInfo);
4386

4387 4388 4389 4390 4391 4392
    for(i = 0; i < This->TypeInfoCount; ++i){
        if(IsEqualIID(&This->typeinfos[i]->TypeAttr.guid, guid)){
            *ppTInfo = (ITypeInfo*)This->typeinfos[i];
            ITypeInfo_AddRef(*ppTInfo);
            return S_OK;
        }
4393
    }
4394

4395
    return TYPE_E_ELEMENTNOTFOUND;
4396 4397 4398 4399 4400 4401 4402
}

/* ITypeLib::GetLibAttr
 *
 * Retrieves the structure that contains the library's attributes.
 *
 */
4403
static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
4404
	ITypeLib2 *iface,
4405
	LPTLIBATTR *attr)
4406
{
4407
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4408 4409 4410 4411 4412

    TRACE("(%p, %p)\n", This, attr);

    if (!attr) return E_INVALIDARG;

4413
    *attr = heap_alloc(sizeof(**attr));
4414 4415 4416
    if (!*attr) return E_OUTOFMEMORY;

    **attr = This->LibAttr;
4417 4418 4419 4420 4421 4422 4423 4424 4425
    return S_OK;
}

/* ITypeLib::GetTypeComp
 *
 * Enables a client compiler to bind to a library's types, variables,
 * constants, and global functions.
 *
 */
4426 4427 4428
static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
	ITypeLib2 *iface,
	ITypeComp **ppTComp)
4429
{
4430
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4431 4432 4433 4434 4435 4436

    TRACE("(%p)->(%p)\n",This,ppTComp);
    *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
    ITypeComp_AddRef(*ppTComp);

    return S_OK;
4437 4438 4439 4440 4441 4442 4443 4444
}

/* ITypeLib::GetDocumentation
 *
 * Retrieves the library's documentation string, the complete Help file name
 * and path, and the context identifier for the library Help topic in the Help
 * file.
 *
4445 4446
 * On a successful return all non-null BSTR pointers will have been set,
 * possibly to NULL.
4447
 */
4448
static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
4449 4450 4451 4452
    ITypeLib2 *iface,
    INT index,
    BSTR *pBstrName,
    BSTR *pBstrDocString,
4453
    DWORD *pdwHelpContext,
4454
    BSTR *pBstrHelpFile)
4455
{
4456
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4457

4458
    HRESULT result = E_INVALIDARG;
4459

4460
    ITypeInfo *pTInfo;
4461

4462

4463 4464
    TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
        This, index,
4465
        pBstrName, pBstrDocString,
4466
        pdwHelpContext, pBstrHelpFile);
4467

4468
    if(index<0)
4469
    {
4470 4471 4472 4473
        /* documentation for the typelib */
        if(pBstrName)
        {
            if (This->Name)
4474 4475 4476 4477
            {
                if(!(*pBstrName = SysAllocString(This->Name)))
                    goto memerr1;
            }
4478 4479 4480 4481 4482 4483
            else
                *pBstrName = NULL;
        }
        if(pBstrDocString)
        {
            if (This->DocString)
4484 4485 4486 4487
            {
                if(!(*pBstrDocString = SysAllocString(This->DocString)))
                    goto memerr2;
            }
4488
            else if (This->Name)
4489 4490 4491 4492
            {
                if(!(*pBstrDocString = SysAllocString(This->Name)))
                    goto memerr2;
            }
4493 4494 4495 4496 4497
            else
                *pBstrDocString = NULL;
        }
        if(pdwHelpContext)
        {
4498
            *pdwHelpContext = This->dwHelpContext;
4499 4500 4501 4502
        }
        if(pBstrHelpFile)
        {
            if (This->HelpFile)
4503 4504 4505 4506
            {
                if(!(*pBstrHelpFile = SysAllocString(This->HelpFile)))
                    goto memerr3;
            }
4507 4508 4509
            else
                *pBstrHelpFile = NULL;
        }
4510

4511
        result = S_OK;
4512
    }
4513
    else
4514 4515 4516 4517 4518 4519
    {
        /* for a typeinfo */
        result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);

        if(SUCCEEDED(result))
        {
4520 4521
            result = ITypeInfo_GetDocumentation(pTInfo,
                                          MEMBERID_NIL,
4522
                                          pBstrName,
4523
                                          pBstrDocString,
4524
                                          pdwHelpContext, pBstrHelpFile);
4525

4526 4527 4528
            ITypeInfo_Release(pTInfo);
        }
    }
4529
    return result;
4530 4531 4532 4533 4534 4535
memerr3:
    if (pBstrDocString) SysFreeString (*pBstrDocString);
memerr2:
    if (pBstrName) SysFreeString (*pBstrName);
memerr1:
    return STG_E_INSUFFICIENTMEMORY;
4536 4537 4538 4539 4540 4541 4542 4543
}

/* ITypeLib::IsName
 *
 * Indicates whether a passed-in string contains the name of a type or member
 * described in the library.
 *
 */
4544 4545 4546 4547 4548
static HRESULT WINAPI ITypeLib2_fnIsName(
	ITypeLib2 *iface,
	LPOLESTR szNameBuf,
	ULONG lHashVal,
	BOOL *pfName)
4549
{
4550
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4551
    UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR), tic, fdc, vrc, pc;
4552

4553
    TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
4554
	  pfName);
4555

4556
    *pfName=TRUE;
4557 4558
    for(tic = 0; tic < This->TypeInfoCount; ++tic){
        ITypeInfoImpl *pTInfo = This->typeinfos[tic];
4559
        if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4560 4561
        for(fdc = 0; fdc < pTInfo->TypeAttr.cFuncs; ++fdc) {
            TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc];
4562
            if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4563 4564
            for(pc=0; pc < pFInfo->funcdesc.cParams; pc++)
                if(!memcmp(szNameBuf,pFInfo->pParamDesc[pc].Name, nNameBufLen))
4565
                    goto ITypeLib2_fnIsName_exit;
4566
        }
4567 4568
        for(vrc = 0; vrc < pTInfo->TypeAttr.cVars; ++vrc){
            TLBVarDesc *pVInfo = &pTInfo->vardescs[vrc];
4569
            if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
4570
        }
4571

4572 4573 4574
    }
    *pfName=FALSE;

4575
ITypeLib2_fnIsName_exit:
4576
    TRACE("(%p)slow! search for %s: %s found!\n", This,
4577
          debugstr_w(szNameBuf), *pfName?"NOT":"");
4578

4579 4580 4581 4582 4583 4584 4585 4586 4587
    return S_OK;
}

/* ITypeLib::FindName
 *
 * Finds occurrences of a type description in a type library. This may be used
 * to quickly verify that a name exists in a type library.
 *
 */
4588 4589
static HRESULT WINAPI ITypeLib2_fnFindName(
	ITypeLib2 *iface,
4590 4591
	LPOLESTR name,
	ULONG hash,
4592
	ITypeInfo **ppTInfo,
4593 4594
	MEMBERID *memid,
	UINT16 *found)
4595
{
4596
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4597 4598
    UINT tic, count = 0;
    UINT len;
4599

4600 4601 4602 4603 4604 4605 4606
    TRACE("(%p)->(%s %u %p %p %p)\n", This, debugstr_w(name), hash, ppTInfo, memid, found);

    if ((!name && hash == 0) || !ppTInfo || !memid || !found)
        return E_INVALIDARG;

    len = (lstrlenW(name) + 1)*sizeof(WCHAR);
    for(tic = 0; tic < This->TypeInfoCount; ++tic) {
4607
        ITypeInfoImpl *pTInfo = This->typeinfos[tic];
4608 4609 4610 4611
        TLBVarDesc *var;
        UINT fdc;

        if(!memcmp(name, pTInfo->Name, len)) goto ITypeLib2_fnFindName_exit;
4612
        for(fdc = 0; fdc < pTInfo->TypeAttr.cFuncs; ++fdc) {
4613 4614 4615 4616 4617 4618
            TLBFuncDesc *func = &pTInfo->funcdescs[fdc];
            UINT pc;

            if(!memcmp(name, func->Name, len)) goto ITypeLib2_fnFindName_exit;
            for(pc = 0; pc < func->funcdesc.cParams; pc++) {
                if(!memcmp(name, func->pParamDesc[pc].Name, len))
4619
                    goto ITypeLib2_fnFindName_exit;
4620
            }
4621
        }
4622

4623 4624
        var = TLB_get_vardesc_by_name(pTInfo->vardescs, pTInfo->TypeAttr.cVars, name);
        if (var)
4625 4626
            goto ITypeLib2_fnFindName_exit;

4627
        continue;
4628 4629
ITypeLib2_fnFindName_exit:
        ITypeInfo_AddRef((ITypeInfo*)pTInfo);
4630 4631
        ppTInfo[count]=(LPTYPEINFO)pTInfo;
        count++;
4632
    }
4633
    TRACE("found %d typeinfos\n", count);
4634

4635
    *found = count;
4636

4637 4638 4639 4640 4641 4642 4643 4644
    return S_OK;
}

/* ITypeLib::ReleaseTLibAttr
 *
 * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
 *
 */
4645 4646 4647
static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
	ITypeLib2 *iface,
	TLIBATTR *pTLibAttr)
4648
{
4649
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4650
    TRACE("freeing (%p)\n",This);
4651
    heap_free(pTLibAttr);
4652

4653 4654 4655 4656 4657 4658
}

/* ITypeLib2::GetCustData
 *
 * gets the custom data
 */
4659 4660
static HRESULT WINAPI ITypeLib2_fnGetCustData(
	ITypeLib2 * iface,
4661
	REFGUID guid,
4662 4663
        VARIANT *pVarVal)
{
4664
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4665
    TLBCustData *pCData;
4666

4667
    TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
4668

4669
    pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
4670 4671
    if(!pCData)
        return TYPE_E_ELEMENTNOTFOUND;
4672

4673 4674 4675 4676
    VariantInit(pVarVal);
    VariantCopy(pVarVal, &pCData->data);

    return S_OK;
4677 4678 4679 4680 4681 4682 4683 4684
}

/* ITypeLib2::GetLibStatistics
 *
 * Returns statistics about a type library that are required for efficient
 * sizing of hash tables.
 *
 */
4685
static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
4686
	ITypeLib2 * iface,
4687 4688
        ULONG *pcUniqueNames,
	ULONG *pcchUniqueNames)
4689
{
4690
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4691

4692
    FIXME("(%p): stub!\n", This);
4693

4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705
    if(pcUniqueNames) *pcUniqueNames=1;
    if(pcchUniqueNames) *pcchUniqueNames=1;
    return S_OK;
}

/* ITypeLib2::GetDocumentation2
 *
 * Retrieves the library's documentation string, the complete Help file name
 * and path, the localization context to use, and the context ID for the
 * library Help topic in the Help file.
 *
 */
4706
static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
4707
	ITypeLib2 * iface,
4708 4709 4710 4711 4712
        INT index,
	LCID lcid,
	BSTR *pbstrHelpString,
        DWORD *pdwHelpStringContext,
	BSTR *pbstrHelpStringDll)
4713
{
4714
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4715 4716
    HRESULT result;
    ITypeInfo *pTInfo;
4717

4718
    FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
4719

4720 4721 4722 4723
    /* the help string should be obtained from the helpstringdll,
     * using the _DLLGetDocumentation function, based on the supplied
     * lcid. Nice to do sometime...
     */
4724 4725 4726 4727
    if(index<0)
    {
      /* documentation for the typelib */
      if(pbstrHelpString)
4728
        *pbstrHelpString=SysAllocString(This->DocString);
4729 4730 4731
      if(pdwHelpStringContext)
        *pdwHelpStringContext=This->dwHelpContext;
      if(pbstrHelpStringDll)
4732
        *pbstrHelpStringDll=SysAllocString(This->HelpStringDll);
4733 4734

      result = S_OK;
4735 4736 4737 4738 4739
    }
    else
    {
      /* for a typeinfo */
      result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
4740

4741
      if(SUCCEEDED(result))
4742
      {
4743
        ITypeInfo2 * pTInfo2;
4744 4745
        result = ITypeInfo_QueryInterface(pTInfo,
                                          &IID_ITypeInfo2,
4746 4747 4748 4749
                                          (LPVOID*) &pTInfo2);

        if(SUCCEEDED(result))
        {
4750 4751
          result = ITypeInfo2_GetDocumentation2(pTInfo2,
                                           MEMBERID_NIL,
4752
                                           lcid,
4753 4754
                                           pbstrHelpString,
                                           pdwHelpStringContext,
4755
                                           pbstrHelpStringDll);
4756

4757
          ITypeInfo2_Release(pTInfo2);
4758
        }
4759

4760 4761
        ITypeInfo_Release(pTInfo);
      }
4762
    }
4763
    return result;
4764 4765
}

4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790
static HRESULT TLB_copy_all_custdata(struct list *custdata_list, CUSTDATA *pCustData)
{
    TLBCustData *pCData;
    unsigned int ct;
    CUSTDATAITEM *cdi;

    ct = list_count(custdata_list);

    pCustData->prgCustData = heap_alloc_zero(ct * sizeof(CUSTDATAITEM));
    if(!pCustData->prgCustData)
        return E_OUTOFMEMORY;

    pCustData->cCustData = ct;

    cdi = pCustData->prgCustData;
    LIST_FOR_EACH_ENTRY(pCData, custdata_list, TLBCustData, entry){
        cdi->guid = pCData->guid;
        VariantCopy(&cdi->varValue, &pCData->data);
        ++cdi;
    }

    return S_OK;
}


4791 4792
/* ITypeLib2::GetAllCustData
 *
4793
 * Gets all custom data items for the library.
4794 4795
 *
 */
4796 4797
static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
	ITypeLib2 * iface,
4798 4799
        CUSTDATA *pCustData)
{
4800
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
4801 4802
    TRACE("%p %p\n", iface, pCustData);
    return TLB_copy_all_custdata(&This->custdata_list, pCustData);
4803 4804
}

4805
static const ITypeLib2Vtbl tlbvt = {
4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824
    ITypeLib2_fnQueryInterface,
    ITypeLib2_fnAddRef,
    ITypeLib2_fnRelease,
    ITypeLib2_fnGetTypeInfoCount,
    ITypeLib2_fnGetTypeInfo,
    ITypeLib2_fnGetTypeInfoType,
    ITypeLib2_fnGetTypeInfoOfGuid,
    ITypeLib2_fnGetLibAttr,
    ITypeLib2_fnGetTypeComp,
    ITypeLib2_fnGetDocumentation,
    ITypeLib2_fnIsName,
    ITypeLib2_fnFindName,
    ITypeLib2_fnReleaseTLibAttr,

    ITypeLib2_fnGetCustData,
    ITypeLib2_fnGetLibStatistics,
    ITypeLib2_fnGetDocumentation2,
    ITypeLib2_fnGetAllCustData
 };
4825

4826 4827 4828

static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
{
4829
    ITypeLibImpl *This = impl_from_ITypeComp(iface);
4830

4831
    return ITypeLib2_QueryInterface((ITypeLib *)This, riid, ppv);
4832 4833 4834 4835
}

static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
{
4836
    ITypeLibImpl *This = impl_from_ITypeComp(iface);
4837

4838
    return ITypeLib2_AddRef((ITypeLib2 *)This);
4839 4840 4841 4842
}

static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
{
4843
    ITypeLibImpl *This = impl_from_ITypeComp(iface);
4844

4845
    return ITypeLib2_Release((ITypeLib2 *)This);
4846 4847 4848 4849 4850
}

static HRESULT WINAPI ITypeLibComp_fnBind(
    ITypeComp * iface,
    OLECHAR * szName,
4851 4852
    ULONG lHash,
    WORD wFlags,
4853 4854 4855 4856
    ITypeInfo ** ppTInfo,
    DESCKIND * pDescKind,
    BINDPTR * pBindPtr)
{
4857
    ITypeLibImpl *This = impl_from_ITypeComp(iface);
4858
    int typemismatch=0, i;
4859

4860
    TRACE("(%s, 0x%x, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
4861 4862 4863 4864 4865

    *pDescKind = DESCKIND_NONE;
    pBindPtr->lptcomp = NULL;
    *ppTInfo = NULL;

4866 4867
    for(i = 0; i < This->TypeInfoCount; ++i){
        ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897
        TRACE("testing %s\n", debugstr_w(pTypeInfo->Name));

        /* FIXME: check wFlags here? */
        /* FIXME: we should use a hash table to look this info up using lHash
         * instead of an O(n) search */
        if ((pTypeInfo->TypeAttr.typekind == TKIND_ENUM) ||
            (pTypeInfo->TypeAttr.typekind == TKIND_MODULE))
        {
            if (pTypeInfo->Name && !strcmpW(pTypeInfo->Name, szName))
            {
                *pDescKind = DESCKIND_TYPECOMP;
                pBindPtr->lptcomp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
                ITypeComp_AddRef(pBindPtr->lptcomp);
                TRACE("module or enum: %s\n", debugstr_w(szName));
                return S_OK;
            }
        }

        if ((pTypeInfo->TypeAttr.typekind == TKIND_MODULE) ||
            (pTypeInfo->TypeAttr.typekind == TKIND_ENUM))
        {
            ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
            HRESULT hr;

            hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
            if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE))
            {
                TRACE("found in module or in enum: %s\n", debugstr_w(szName));
                return S_OK;
            }
4898 4899
            else if (hr == TYPE_E_TYPEMISMATCH)
                typemismatch = 1;
4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914
        }

        if ((pTypeInfo->TypeAttr.typekind == TKIND_COCLASS) &&
            (pTypeInfo->TypeAttr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
        {
            ITypeComp *pSubTypeComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
            HRESULT hr;
            ITypeInfo *subtypeinfo;
            BINDPTR subbindptr;
            DESCKIND subdesckind;

            hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
                &subtypeinfo, &subdesckind, &subbindptr);
            if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
            {
4915
                TYPEDESC tdesc_appobject;
4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936
                const VARDESC vardesc_appobject =
                {
                    -2,         /* memid */
                    NULL,       /* lpstrSchema */
                    {
                        0       /* oInst */
                    },
                    {
                                /* ELEMDESC */
                        {
                                /* TYPEDESC */
                                {
                                    &tdesc_appobject
                                },
                                VT_PTR
                        },
                    },
                    0,          /* wVarFlags */
                    VAR_STATIC  /* varkind */
                };

4937 4938 4939
                tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
                tdesc_appobject.vt = VT_USERDEFINED;

4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956
                TRACE("found in implicit app object: %s\n", debugstr_w(szName));

                /* cleanup things filled in by Bind call so we can put our
                 * application object data in there instead */
                switch (subdesckind)
                {
                case DESCKIND_FUNCDESC:
                    ITypeInfo_ReleaseFuncDesc(subtypeinfo, subbindptr.lpfuncdesc);
                    break;
                case DESCKIND_VARDESC:
                    ITypeInfo_ReleaseVarDesc(subtypeinfo, subbindptr.lpvardesc);
                    break;
                default:
                    break;
                }
                if (subtypeinfo) ITypeInfo_Release(subtypeinfo);

4957 4958 4959
                if (pTypeInfo->hreftype == -1)
                    FIXME("no hreftype for interface %p\n", pTypeInfo);

4960 4961 4962 4963 4964 4965 4966 4967 4968
                hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
                if (FAILED(hr))
                    return hr;

                *pDescKind = DESCKIND_IMPLICITAPPOBJ;
                *ppTInfo = (ITypeInfo *)pTypeInfo;
                ITypeInfo_AddRef(*ppTInfo);
                return S_OK;
            }
4969 4970
            else if (hr == TYPE_E_TYPEMISMATCH)
                typemismatch = 1;
4971 4972 4973
        }
    }

4974 4975 4976 4977 4978 4979 4980 4981 4982 4983
    if (typemismatch)
    {
        TRACE("type mismatch %s\n", debugstr_w(szName));
        return TYPE_E_TYPEMISMATCH;
    }
    else
    {
        TRACE("name not found %s\n", debugstr_w(szName));
        return S_OK;
    }
4984 4985 4986 4987 4988
}

static HRESULT WINAPI ITypeLibComp_fnBindType(
    ITypeComp * iface,
    OLECHAR * szName,
4989
    ULONG lHash,
4990 4991 4992
    ITypeInfo ** ppTInfo,
    ITypeComp ** ppTComp)
{
4993
    ITypeLibImpl *This = impl_from_ITypeComp(iface);
4994
    UINT i;
4995 4996 4997

    TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);

4998 4999 5000
    if(!szName || !ppTInfo || !ppTComp)
        return E_INVALIDARG;

5001
    for(i = 0; i < This->TypeInfoCount; ++i)
5002
    {
5003
        ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
5004
        /* FIXME: should use lHash to do the search */
5005
        if (pTypeInfo->Name && !strcmpiW(pTypeInfo->Name, szName))
5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019
        {
            TRACE("returning %p\n", pTypeInfo);
            *ppTInfo = (ITypeInfo *)&pTypeInfo->lpVtbl;
            ITypeInfo_AddRef(*ppTInfo);
            *ppTComp = (ITypeComp *)&pTypeInfo->lpVtblTypeComp;
            ITypeComp_AddRef(*ppTComp);
            return S_OK;
        }
    }

    TRACE("not found\n");
    *ppTInfo = NULL;
    *ppTComp = NULL;
    return S_OK;
5020 5021
}

5022
static const ITypeCompVtbl tlbtcvt =
5023 5024 5025 5026 5027 5028 5029 5030 5031 5032
{

    ITypeLibComp_fnQueryInterface,
    ITypeLibComp_fnAddRef,
    ITypeLibComp_fnRelease,

    ITypeLibComp_fnBind,
    ITypeLibComp_fnBindType
};

5033
/*================== ITypeInfo(2) Methods ===================================*/
5034
static ITypeInfoImpl* ITypeInfoImpl_Constructor(void)
5035
{
5036
    ITypeInfoImpl *pTypeInfoImpl;
5037

5038
    pTypeInfoImpl = heap_alloc_zero(sizeof(ITypeInfoImpl));
5039 5040
    if (pTypeInfoImpl)
    {
5041
      pTypeInfoImpl->lpVtbl = &tinfvt;
5042
      pTypeInfoImpl->lpVtblTypeComp = &tcompvt;
5043
      pTypeInfoImpl->ref = 0;
5044
      pTypeInfoImpl->hreftype = -1;
5045 5046
      pTypeInfoImpl->TypeAttr.memidConstructor = MEMBERID_NIL;
      pTypeInfoImpl->TypeAttr.memidDestructor = MEMBERID_NIL;
5047
      list_init(&pTypeInfoImpl->custdata_list);
5048 5049
    }
    TRACE("(%p)\n", pTypeInfoImpl);
5050
    return pTypeInfoImpl;
5051
}
5052 5053 5054

/* ITypeInfo::QueryInterface
 */
5055 5056 5057 5058
static HRESULT WINAPI ITypeInfo_fnQueryInterface(
	ITypeInfo2 *iface,
	REFIID riid,
	VOID **ppvObject)
5059
{
5060
    ITypeLibImpl *This = (ITypeLibImpl *)iface;
5061

5062
    TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
5063

5064
    *ppvObject=NULL;
5065
    if(IsEqualIID(riid, &IID_IUnknown) ||
5066 5067 5068
            IsEqualIID(riid,&IID_ITypeInfo)||
            IsEqualIID(riid,&IID_ITypeInfo2))
        *ppvObject = This;
5069

5070
    if(*ppvObject){
5071
        ITypeInfo_AddRef(iface);
5072
        TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
5073 5074
        return S_OK;
    }
5075
    TRACE("-- Interface: E_NOINTERFACE\n");
5076 5077 5078 5079 5080
    return E_NOINTERFACE;
}

/* ITypeInfo::AddRef
 */
5081
static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
5082
{
5083
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5084
    ULONG ref = InterlockedIncrement(&This->ref);
5085

5086
    TRACE("(%p)->ref is %u\n",This, ref);
5087 5088 5089 5090

    if (ref == 1 /* incremented from 0 */)
        ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib);

5091
    return ref;
5092 5093
}

5094
static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This)
5095
{
5096
    UINT i, j;
5097

5098
    TRACE("destroying ITypeInfo(%p)\n",This);
5099

5100 5101
    SysFreeString(This->Name);
    This->Name = NULL;
5102

5103 5104
    SysFreeString(This->DocString);
    This->DocString = NULL;
5105

5106 5107
    SysFreeString(This->DllName);
    This->DllName = NULL;
5108

5109
    for (i = 0; i < This->TypeAttr.cFuncs; ++i)
5110
    {
5111 5112
        TLBFuncDesc *pFInfo = &This->funcdescs[i];
        for(j = 0; j < pFInfo->funcdesc.cParams; j++)
5113
        {
5114
            ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[j];
5115 5116 5117
            if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
            {
                VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
5118
                heap_free(elemdesc->u.paramdesc.pparamdescex);
5119
            }
5120
            TLB_FreeCustData(&pFInfo->pParamDesc[j].custdata_list);
5121
            SysFreeString(pFInfo->pParamDesc[j].Name);
5122
        }
5123 5124
        heap_free(pFInfo->funcdesc.lprgelemdescParam);
        heap_free(pFInfo->pParamDesc);
5125
        TLB_FreeCustData(&pFInfo->custdata_list);
5126
        if (!IS_INTRESOURCE(pFInfo->Entry) && pFInfo->Entry != (BSTR)-1)
5127 5128 5129 5130
            SysFreeString(pFInfo->Entry);
        SysFreeString(pFInfo->HelpString);
        SysFreeString(pFInfo->Name);
    }
5131 5132
    heap_free(This->funcdescs);

5133
    for(i = 0; i < This->TypeAttr.cVars; ++i)
5134
    {
5135
        TLBVarDesc *pVInfo = &This->vardescs[i];
5136 5137 5138
        if (pVInfo->vardesc.varkind == VAR_CONST)
        {
            VariantClear(pVInfo->vardesc.u.lpvarValue);
5139
            heap_free(pVInfo->vardesc.u.lpvarValue);
5140
        }
5141
        TLB_FreeCustData(&pVInfo->custdata_list);
5142
        SysFreeString(pVInfo->Name);
5143
        SysFreeString(pVInfo->HelpString);
5144
    }
5145
    heap_free(This->vardescs);
5146 5147

    if(This->impltypes){
5148 5149
        for (i = 0; i < This->TypeAttr.cImplTypes; ++i){
            TLBImplType *pImpl = &This->impltypes[i];
5150
            TLB_FreeCustData(&pImpl->custdata_list);
5151 5152
        }
        heap_free(This->impltypes);
5153
    }
5154

5155
    TLB_FreeCustData(&This->custdata_list);
5156

5157
    heap_free(This);
5158
}
5159

5160 5161 5162 5163 5164 5165
/* ITypeInfo::Release
 */
static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
{
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
    ULONG ref = InterlockedDecrement(&This->ref);
5166

5167
    TRACE("(%p)->(%u)\n",This, ref);
5168

5169 5170 5171 5172 5173
    if (!ref)
    {
        BOOL not_attached_to_typelib = This->not_attached_to_typelib;
        ITypeLib2_Release((ITypeLib2*)This->pTypeLib);
        if (not_attached_to_typelib)
5174
            heap_free(This);
5175
        /* otherwise This will be freed when typelib is freed */
5176
    }
5177

5178
    return ref;
5179 5180 5181 5182 5183 5184 5185 5186
}

/* ITypeInfo::GetTypeAttr
 *
 * Retrieves a TYPEATTR structure that contains the attributes of the type
 * description.
 *
 */
5187
static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
5188 5189
        LPTYPEATTR  *ppTypeAttr)
{
5190
    const ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5191 5192
    SIZE_T size;

5193
    TRACE("(%p)\n",This);
5194 5195 5196 5197 5198

    size = sizeof(**ppTypeAttr);
    if (This->TypeAttr.typekind == TKIND_ALIAS)
        size += TLB_SizeTypeDesc(&This->TypeAttr.tdescAlias, FALSE);

5199
    *ppTypeAttr = heap_alloc(size);
5200 5201 5202
    if (!*ppTypeAttr)
        return E_OUTOFMEMORY;

5203
    **ppTypeAttr = This->TypeAttr;
5204

5205 5206
    if (This->TypeAttr.typekind == TKIND_ALIAS)
        TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias,
5207
            &This->TypeAttr.tdescAlias, *ppTypeAttr + 1);
5208

5209
    if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
5210 5211
        /* This should include all the inherited funcs */
        (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / sizeof(void *);
5212 5213
        /* This is always the size of IDispatch's vtbl */
        (*ppTypeAttr)->cbSizeVft = sizeof(IDispatchVtbl);
5214 5215
        (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
    }
5216 5217 5218 5219 5220 5221 5222 5223 5224
    return S_OK;
}

/* ITypeInfo::GetTypeComp
 *
 * Retrieves the ITypeComp interface for the type description, which enables a
 * client compiler to bind to the type description's members.
 *
 */
5225
static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
5226 5227
        ITypeComp  * *ppTComp)
{
5228
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5229

5230
    TRACE("(%p)->(%p)\n", This, ppTComp);
5231 5232 5233

    *ppTComp = (ITypeComp *)&This->lpVtblTypeComp;
    ITypeComp_AddRef(*ppTComp);
5234 5235 5236
    return S_OK;
}

5237 5238 5239
static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
{
    SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
5240
    if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5241 5242 5243 5244 5245 5246
        size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
    return size;
}

static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
{
5247
    *dest = *src;
5248
    *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
5249
    if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5250 5251 5252 5253
    {
        const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
        PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
        *buffer += sizeof(PARAMDESCEX);
5254
        *pparamdescex_dest = *pparamdescex_src;
5255
        VariantInit(&pparamdescex_dest->varDefaultValue);
5256 5257
        return VariantCopy(&pparamdescex_dest->varDefaultValue, 
                           (VARIANTARG *)&pparamdescex_src->varDefaultValue);
5258
    }
5259 5260
    else
        dest->u.paramdesc.pparamdescex = NULL;
5261 5262 5263 5264 5265
    return S_OK;
}

static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
{
5266
    if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
5267 5268 5269
        VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
}

5270
static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288
{
    FUNCDESC *dest;
    char *buffer;
    SIZE_T size = sizeof(*src);
    SHORT i;
    HRESULT hr;

    size += sizeof(*src->lprgscode) * src->cScodes;
    size += TLB_SizeElemDesc(&src->elemdescFunc);
    for (i = 0; i < src->cParams; i++)
    {
        size += sizeof(ELEMDESC);
        size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
    }

    dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
    if (!dest) return E_OUTOFMEMORY;

5289
    *dest = *src;
5290 5291
    if (dispinterface)    /* overwrite funckind */
        dest->funckind = FUNC_DISPATCH;
5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322
    buffer = (char *)(dest + 1);

    dest->lprgscode = (SCODE *)buffer;
    memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
    buffer += sizeof(*src->lprgscode) * src->cScodes;

    hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
    if (FAILED(hr))
    {
        SysFreeString((BSTR)dest);
        return hr;
    }

    dest->lprgelemdescParam = (ELEMDESC *)buffer;
    buffer += sizeof(ELEMDESC) * src->cParams;
    for (i = 0; i < src->cParams; i++)
    {
        hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
        if (FAILED(hr))
            break;
    }
    if (FAILED(hr))
    {
        /* undo the above actions */
        for (i = i - 1; i >= 0; i--)
            TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
        TLB_FreeElemDesc(&dest->elemdescFunc);
        SysFreeString((BSTR)dest);
        return hr;
    }

5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354
    /* special treatment for dispinterfaces: this makes functions appear
     * to return their [retval] value when it is really returning an
     * HRESULT */
    if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
    {
        if (dest->cParams &&
            (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
        {
            ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
            if (elemdesc->tdesc.vt != VT_PTR)
            {
                ERR("elemdesc should have started with VT_PTR instead of:\n");
                if (ERR_ON(ole))
                    dump_ELEMDESC(elemdesc);
                return E_UNEXPECTED;
            }

            /* copy last parameter to the return value. we are using a flat
             * buffer so there is no danger of leaking memory in
             * elemdescFunc */
            dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;

            /* remove the last parameter */
            dest->cParams--;
        }
        else
            /* otherwise this function is made to appear to have no return
             * value */
            dest->elemdescFunc.tdesc.vt = VT_VOID;

    }

5355 5356 5357 5358
    *dest_ptr = dest;
    return S_OK;
}

5359 5360 5361 5362
HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
{
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;

5363 5364
    if (index >= This->TypeAttr.cFuncs)
        return TYPE_E_ELEMENTNOTFOUND;
5365

5366 5367
    *ppFuncDesc = &This->funcdescs[index].funcdesc;
    return S_OK;
5368 5369
}

5370 5371 5372
/* internal function to make the inherited interfaces' methods appear
 * part of the interface */
static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
5373
    UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
5374 5375 5376 5377 5378 5379 5380
{
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
    HRESULT hr;
    UINT implemented_funcs = 0;

    if (funcs)
        *funcs = 0;
5381 5382
    else
        *hrefoffset = DISPATCH_HREF_OFFSET;
5383

5384
    if(This->impltypes)
5385 5386 5387 5388
    {
        ITypeInfo *pSubTypeInfo;
        UINT sub_funcs;

5389
        hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
5390 5391 5392 5393 5394 5395
        if (FAILED(hr))
            return hr;

        hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
                                                       index,
                                                       ppFuncDesc,
5396
                                                       &sub_funcs, hrefoffset);
5397 5398 5399 5400
        implemented_funcs += sub_funcs;
        ITypeInfo_Release(pSubTypeInfo);
        if (SUCCEEDED(hr))
            return hr;
5401
        *hrefoffset += DISPATCH_HREF_OFFSET;
5402 5403 5404 5405
    }

    if (funcs)
        *funcs = implemented_funcs + This->TypeAttr.cFuncs;
5406 5407
    else
        *hrefoffset = 0;
5408 5409 5410 5411 5412 5413 5414
    
    if (index < implemented_funcs)
        return E_INVALIDARG;
    return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
                                             ppFuncDesc);
}

5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445
static inline void ITypeInfoImpl_ElemDescAddHrefOffset( LPELEMDESC pElemDesc, UINT hrefoffset)
{
    TYPEDESC *pTypeDesc = &pElemDesc->tdesc;
    while (TRUE)
    {
        switch (pTypeDesc->vt)
        {
        case VT_USERDEFINED:
            pTypeDesc->u.hreftype += hrefoffset;
            return;
        case VT_PTR:
        case VT_SAFEARRAY:
            pTypeDesc = pTypeDesc->u.lptdesc;
            break;
        case VT_CARRAY:
            pTypeDesc = &pTypeDesc->u.lpadesc->tdescElem;
            break;
        default:
            return;
        }
    }
}

static inline void ITypeInfoImpl_FuncDescAddHrefOffset( LPFUNCDESC pFuncDesc, UINT hrefoffset)
{
    SHORT i;
    for (i = 0; i < pFuncDesc->cParams; i++)
        ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->lprgelemdescParam[i], hrefoffset);
    ITypeInfoImpl_ElemDescAddHrefOffset(&pFuncDesc->elemdescFunc, hrefoffset);
}

5446 5447 5448 5449 5450 5451
/* ITypeInfo::GetFuncDesc
 *
 * Retrieves the FUNCDESC structure that contains information about a
 * specified function.
 *
 */
5452
static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
5453 5454
        LPFUNCDESC  *ppFuncDesc)
{
5455
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5456 5457
    const FUNCDESC *internal_funcdesc;
    HRESULT hr;
5458
    UINT hrefoffset = 0;
5459

5460
    TRACE("(%p) index %d\n", This, index);
5461

5462
    if (This->TypeAttr.typekind == TKIND_DISPATCH)
5463
        hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
5464 5465
                                                       &internal_funcdesc, NULL,
                                                       &hrefoffset);
5466 5467 5468
    else
        hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
                                               &internal_funcdesc);
5469
    if (FAILED(hr))
5470 5471
    {
        WARN("description for function %d not found\n", index);
5472
        return hr;
5473
    }
5474

5475
    hr = TLB_AllocAndInitFuncDesc(
5476 5477 5478
        internal_funcdesc,
        ppFuncDesc,
        This->TypeAttr.typekind == TKIND_DISPATCH);
5479 5480 5481 5482 5483 5484

    if ((This->TypeAttr.typekind == TKIND_DISPATCH) && hrefoffset)
        ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);

    TRACE("-- 0x%08x\n", hr);
    return hr;
5485 5486
}

5487 5488 5489 5490 5491
static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
{
    VARDESC *dest;
    char *buffer;
    SIZE_T size = sizeof(*src);
5492
    HRESULT hr;
5493 5494 5495 5496

    if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
    if (src->varkind == VAR_CONST)
        size += sizeof(VARIANT);
5497
    size += TLB_SizeElemDesc(&src->elemdescVar);
5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519

    dest = (VARDESC *)SysAllocStringByteLen(NULL, size);
    if (!dest) return E_OUTOFMEMORY;

    *dest = *src;
    buffer = (char *)(dest + 1);
    if (src->lpstrSchema)
    {
        int len;
        dest->lpstrSchema = (LPOLESTR)buffer;
        len = strlenW(src->lpstrSchema);
        memcpy(dest->lpstrSchema, src->lpstrSchema, (len + 1) * sizeof(WCHAR));
        buffer += (len + 1) * sizeof(WCHAR);
    }

    if (src->varkind == VAR_CONST)
    {
        HRESULT hr;

        dest->u.lpvarValue = (VARIANT *)buffer;
        *dest->u.lpvarValue = *src->u.lpvarValue;
        buffer += sizeof(VARIANT);
5520
        VariantInit(dest->u.lpvarValue);
5521 5522 5523
        hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
        if (FAILED(hr))
        {
5524
            SysFreeString((BSTR)dest);
5525 5526 5527
            return hr;
        }
    }
5528 5529
    hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
    if (FAILED(hr))
5530
    {
5531 5532 5533 5534
        if (src->varkind == VAR_CONST)
            VariantClear(dest->u.lpvarValue);
        SysFreeString((BSTR)dest);
        return hr;
5535 5536 5537 5538 5539
    }
    *dest_ptr = dest;
    return S_OK;
}

5540 5541
/* ITypeInfo::GetVarDesc
 *
5542
 * Retrieves a VARDESC structure that describes the specified variable.
5543 5544
 *
 */
5545
static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
5546 5547
        LPVARDESC  *ppVarDesc)
{
5548
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5549
    const TLBVarDesc *pVDesc = &This->vardescs[index];
5550

5551
    TRACE("(%p) index %d\n", This, index);
5552

5553 5554
    if(index >= This->TypeAttr.cVars)
        return TYPE_E_ELEMENTNOTFOUND;
5555

5556
    return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
5557 5558 5559 5560 5561 5562 5563 5564
}

/* ITypeInfo_GetNames
 *
 * Retrieves the variable with the specified member ID (or the name of the
 * property or method and its parameters) that correspond to the specified
 * function ID.
 */
5565
static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
5566 5567
        BSTR  *rgBstrNames, UINT cMaxNames, UINT  *pcNames)
{
5568
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5569 5570
    const TLBFuncDesc *pFDesc;
    const TLBVarDesc *pVDesc;
5571
    int i;
5572
    TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
5573
    pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
5574 5575 5576 5577 5578 5579
    if(pFDesc)
    {
      /* function found, now return function and parameter names */
      for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++)
      {
        if(!i)
5580
	  *rgBstrNames=SysAllocString(pFDesc->Name);
5581
        else
5582
          rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name);
5583 5584 5585 5586 5587
      }
      *pcNames=i;
    }
    else
    {
5588
      pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
5589 5590
      if(pVDesc)
      {
5591
        *rgBstrNames=SysAllocString(pVDesc->Name);
5592 5593 5594 5595
        *pcNames=1;
      }
      else
      {
5596
        if(This->impltypes &&
5597
	   (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
5598 5599 5600
          /* recursive search */
          ITypeInfo *pTInfo;
          HRESULT result;
5601
          result=ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef,
5602
					  &pTInfo);
5603 5604 5605 5606 5607 5608 5609
          if(SUCCEEDED(result))
	  {
            result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
            ITypeInfo_Release(pTInfo);
            return result;
          }
          WARN("Could not search inherited interface!\n");
5610
        }
5611 5612 5613 5614 5615 5616 5617
        else
	{
          WARN("no names found\n");
	}
        *pcNames=0;
        return TYPE_E_ELEMENTNOTFOUND;
      }
5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630
    }
    return S_OK;
}


/* ITypeInfo::GetRefTypeOfImplType
 *
 * If a type description describes a COM class, it retrieves the type
 * description of the implemented interface types. For an interface,
 * GetRefTypeOfImplType returns the type information for inherited interfaces,
 * if any exist.
 *
 */
5631 5632 5633 5634
static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
	ITypeInfo2 *iface,
        UINT index,
	HREFTYPE  *pRefType)
5635
{
5636
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5637
    HRESULT hr = S_OK;
5638

5639
    TRACE("(%p) index %d\n", This, index);
5640
    if (TRACE_ON(ole)) dump_TypeInfo(This);
5641

5642 5643
    if(index==(UINT)-1)
    {
5644 5645 5646
      /* only valid on dual interfaces;
         retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
      */
5647
      if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG;
5648

5649
      if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)
5650 5651 5652 5653 5654
      {
        *pRefType = -1;
      }
      else
      {
5655
        hr = TYPE_E_ELEMENTNOTFOUND;
5656
      }
5657
    }
5658 5659 5660 5661 5662
    else if(index == 0 && This->TypeAttr.typekind == TKIND_DISPATCH)
    {
      /* All TKIND_DISPATCHs are made to look like they inherit from IDispatch */
      *pRefType = This->pTypeLib->dispatch_href;
    }
5663
    else
5664
    {
5665 5666 5667 5668
        if(index >= This->TypeAttr.cImplTypes)
            hr = TYPE_E_ELEMENTNOTFOUND;
        else
            *pRefType = This->impltypes[index].hRef;
5669
    }
5670

5671 5672 5673
    if(TRACE_ON(ole))
    {
        if(SUCCEEDED(hr))
5674
            TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
5675
        else
5676
            TRACE("FAILURE -- hresult = 0x%08x\n", hr);
5677
    }
5678

5679
    return hr;
5680 5681 5682
}

/* ITypeInfo::GetImplTypeFlags
5683 5684
 *
 * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
5685 5686
 * or base interface in a type description.
 */
5687
static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
5688 5689
        UINT index, INT  *pImplTypeFlags)
{
5690
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5691

5692
    TRACE("(%p) index %d\n", This, index);
5693 5694 5695

    if(This->TypeAttr.typekind == TKIND_DISPATCH && index == 0){
        *pImplTypeFlags = 0;
5696 5697
        return S_OK;
    }
5698

5699 5700
    if(index >= This->TypeAttr.cImplTypes)
        return TYPE_E_ELEMENTNOTFOUND;
5701

5702 5703 5704
    *pImplTypeFlags = This->impltypes[index].implflags;

    return S_OK;
5705 5706 5707 5708 5709 5710
}

/* GetIDsOfNames
 * Maps between member names and member IDs, and parameter names and
 * parameter IDs.
 */
5711
static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
5712 5713
        LPOLESTR  *rgszNames, UINT cNames, MEMBERID  *pMemId)
{
5714
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
5715
    const TLBVarDesc *pVDesc;
5716
    HRESULT ret=S_OK;
5717
    UINT i, fdc;
5718

5719
    TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
5720
            cNames);
5721 5722 5723 5724 5725

    /* init out parameters in case of failure */
    for (i = 0; i < cNames; i++)
        pMemId[i] = MEMBERID_NIL;

5726
    for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc) {
5727
        int j;
5728
        const TLBFuncDesc *pFDesc = &This->funcdescs[fdc];
5729
        if(!lstrcmpiW(*rgszNames, pFDesc->Name)) {
5730 5731 5732
            if(cNames) *pMemId=pFDesc->funcdesc.memid;
            for(i=1; i < cNames; i++){
                for(j=0; j<pFDesc->funcdesc.cParams; j++)
5733
                    if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name))
5734 5735 5736 5737 5738 5739
                            break;
                if( j<pFDesc->funcdesc.cParams)
                    pMemId[i]=j;
                else
                   ret=DISP_E_UNKNOWNNAME;
            };
5740
            TRACE("-- 0x%08x\n", ret);
5741 5742
            return ret;
        }
5743
    }
5744 5745 5746 5747 5748
    pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->TypeAttr.cVars, *rgszNames);
    if(pVDesc){
        if(cNames)
            *pMemId = pVDesc->vardesc.memid;
        return ret;
5749
    }
5750
    /* not found, see if it can be found in an inherited interface */
5751
    if(This->impltypes) {
5752 5753
        /* recursive search */
        ITypeInfo *pTInfo;
5754
        ret=ITypeInfo_GetRefTypeInfo(iface,
5755
                This->impltypes[0].hRef, &pTInfo);
5756
        if(SUCCEEDED(ret)){
5757 5758
            ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
            ITypeInfo_Release(pTInfo);
5759 5760
            return ret;
        }
5761
        WARN("Could not search inherited interface!\n");
5762
    } else
5763
        WARN("no names found\n");
5764 5765 5766
    return DISP_E_UNKNOWNNAME;
}

5767 5768 5769

#ifdef __i386__

5770
extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781
__ASM_GLOBAL_FUNC( call_method,
                   "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")
                   "pushl %esi\n\t"
                  __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
                   "pushl %edi\n\t"
                  __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
                   "movl 12(%ebp),%edx\n\t"
5782
                   "movl %esp,%edi\n\t"
5783 5784
                   "shll $2,%edx\n\t"
                   "jz 1f\n\t"
5785 5786 5787
                   "subl %edx,%edi\n\t"
                   "andl $~15,%edi\n\t"
                   "movl %edi,%esp\n\t"
5788 5789 5790 5791 5792
                   "movl 12(%ebp),%ecx\n\t"
                   "movl 16(%ebp),%esi\n\t"
                   "cld\n\t"
                   "rep; movsl\n"
                   "1:\tcall *8(%ebp)\n\t"
5793 5794 5795
                   "subl %esp,%edi\n\t"
                   "movl 20(%ebp),%ecx\n\t"
                   "movl %edi,(%ecx)\n\t"
5796 5797 5798 5799 5800 5801 5802 5803 5804 5805
                   "leal -8(%ebp),%esp\n\t"
                   "popl %edi\n\t"
                   __ASM_CFI(".cfi_same_value %edi\n\t")
                   "popl %esi\n\t"
                   __ASM_CFI(".cfi_same_value %esi\n\t")
                   "popl %ebp\n\t"
                   __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
                   __ASM_CFI(".cfi_same_value %ebp\n\t")
                   "ret" )

5806
/* same function but returning floating point */
5807
static double (* const call_double_method)(void*,int,const DWORD*,int*) = (void *)call_method;
5808

5809
/* ITypeInfo::Invoke
5810
 *
5811 5812 5813
 * Invokes a method, or accesses a property of an object, that implements the
 * interface described by the type description.
 */
5814
DWORD
5815
_invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) {
5816
    DWORD res;
5817
    int stack_offset;
5818 5819 5820

    if (TRACE_ON(ole)) {
	int i;
5821
	TRACE("Calling %p(",func);
5822 5823
	for (i=0;i<min(nrargs,30);i++) TRACE("%08x,",args[i]);
	if (nrargs > 30) TRACE("...");
5824
	TRACE(")\n");
5825 5826 5827 5828
    }

    switch (callconv) {
    case CC_STDCALL:
5829
    case CC_CDECL:
5830
        res = call_method( func, nrargs, args, &stack_offset );
5831 5832 5833 5834 5835 5836
	break;
    default:
	FIXME("unsupported calling convention %d\n",callconv);
	res = -1;
	break;
    }
5837
    TRACE("returns %08x\n",res);
5838 5839
    return res;
}
5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867

#elif defined(__x86_64__)

extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
__ASM_GLOBAL_FUNC( call_method,
                   "pushq %rbp\n\t"
                   __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
                   __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
                   "movq %rsp,%rbp\n\t"
                   __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
                   "pushq %rsi\n\t"
                   __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
                   "pushq %rdi\n\t"
                   __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
                   "movq %rcx,%rax\n\t"
                   "movq $4,%rcx\n\t"
                   "cmp %rcx,%rdx\n\t"
                   "cmovgq %rdx,%rcx\n\t"
                   "leaq 0(,%rcx,8),%rdx\n\t"
                   "subq %rdx,%rsp\n\t"
                   "andq $~15,%rsp\n\t"
                   "movq %rsp,%rdi\n\t"
                   "movq %r8,%rsi\n\t"
                   "rep; movsq\n\t"
                   "movq 0(%rsp),%rcx\n\t"
                   "movq 8(%rsp),%rdx\n\t"
                   "movq 16(%rsp),%r8\n\t"
                   "movq 24(%rsp),%r9\n\t"
5868 5869 5870 5871
                   "movq %rcx,%xmm0\n\t"
                   "movq %rdx,%xmm1\n\t"
                   "movq %r8,%xmm2\n\t"
                   "movq %r9,%xmm3\n\t"
5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883
                   "callq *%rax\n\t"
                   "leaq -16(%rbp),%rsp\n\t"
                   "popq %rdi\n\t"
                   __ASM_CFI(".cfi_same_value %rdi\n\t")
                   "popq %rsi\n\t"
                   __ASM_CFI(".cfi_same_value %rsi\n\t")
                   __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
                   "popq %rbp\n\t"
                   __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
                   __ASM_CFI(".cfi_same_value %rbp\n\t")
                   "ret")

5884
/* same function but returning floating point */
5885
static double (CDECL * const call_double_method)(void*,int,const DWORD_PTR*) = (void *)call_method;
5886

5887
#endif  /* __x86_64__ */
5888

5889
static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5890 5891 5892 5893 5894 5895 5896 5897
{
    HRESULT hr = S_OK;
    ITypeInfo *tinfo2 = NULL;
    TYPEATTR *tattr = NULL;

    hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
    if (hr)
    {
5898 5899
        ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
            "hr = 0x%08x\n",
5900 5901 5902 5903 5904 5905
              tdesc->u.hreftype, hr);
        return hr;
    }
    hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
    if (hr)
    {
5906
        ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
5907 5908 5909 5910 5911 5912 5913
        ITypeInfo_Release(tinfo2);
        return hr;
    }

    switch (tattr->typekind)
    {
    case TKIND_ENUM:
5914
        *vt |= VT_I4;
5915 5916 5917 5918 5919 5920 5921 5922
        break;

    case TKIND_ALIAS:
        tdesc = &tattr->tdescAlias;
        hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
        break;

    case TKIND_INTERFACE:
5923
        if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
5924 5925 5926 5927
           *vt |= VT_DISPATCH;
        else
           *vt |= VT_UNKNOWN;
        break;
5928 5929 5930 5931 5932

    case TKIND_DISPATCH:
        *vt |= VT_DISPATCH;
        break;

5933
    case TKIND_COCLASS:
5934
        *vt |= VT_DISPATCH;
5935 5936
        break;

5937 5938 5939
    case TKIND_RECORD:
        FIXME("TKIND_RECORD unhandled.\n");
        hr = E_NOTIMPL;
5940
        break;
5941 5942

    case TKIND_UNION:
5943
        FIXME("TKIND_UNION unhandled.\n");
5944
        hr = E_NOTIMPL;
5945
        break;
5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956

    default:
        FIXME("TKIND %d unhandled.\n",tattr->typekind);
        hr = E_NOTIMPL;
        break;
    }
    ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
    ITypeInfo_Release(tinfo2);
    return hr;
}

5957
static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
5958 5959 5960 5961
{
    HRESULT hr = S_OK;

    /* enforce only one level of pointer indirection */
5962
    if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
5963 5964 5965 5966 5967 5968 5969 5970 5971 5972
    {
        tdesc = tdesc->u.lptdesc;

        /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
         * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into 
         * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
        if ((tdesc->vt == VT_USERDEFINED) ||
            ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
        {
            VARTYPE vt_userdefined = 0;
5973
            const TYPEDESC *tdesc_userdefined = tdesc;
5974 5975 5976 5977 5978 5979
            if (tdesc->vt == VT_PTR)
            {
                vt_userdefined = VT_BYREF;
                tdesc_userdefined = tdesc->u.lptdesc;
            }
            hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
5980 5981 5982
            if ((hr == S_OK) && 
                (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
                 ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998
            {
                *vt |= vt_userdefined;
                return S_OK;
            }
        }
        *vt = VT_BYREF;
    }

    switch (tdesc->vt)
    {
    case VT_HRESULT:
        *vt |= VT_ERROR;
        break;
    case VT_USERDEFINED:
        hr = userdefined_to_variantvt(tinfo, tdesc, vt);
        break;
5999 6000
    case VT_VOID:
    case VT_CARRAY:
6001
    case VT_PTR:
6002 6003 6004 6005 6006 6007 6008 6009
    case VT_LPSTR:
    case VT_LPWSTR:
        ERR("cannot convert type %d into variant VT\n", tdesc->vt);
        hr = DISP_E_BADVARTYPE;
        break;
    case VT_SAFEARRAY:
        *vt |= VT_ARRAY;
        hr = typedescvt_to_variantvt(tinfo, tdesc->u.lptdesc, vt);
6010
        break;
6011 6012 6013 6014 6015 6016
    case VT_INT:
        *vt |= VT_I4;
        break;
    case VT_UINT:
        *vt |= VT_UI4;
        break;
6017 6018 6019 6020 6021 6022 6023
    default:
        *vt |= tdesc->vt;
        break;
    }
    return hr;
}

6024 6025
/***********************************************************************
 *		DispCallFunc (OLEAUT32.@)
6026
 *
6027
 * Invokes a function of the specified calling convention, passing the
6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060
 * specified arguments and returns the result.
 *
 * PARAMS
 *  pvInstance  [I] Optional pointer to the instance whose function to invoke.
 *  oVft        [I] The offset in the vtable. See notes.
 *  cc          [I] Calling convention of the function to call.
 *  vtReturn    [I] The return type of the function.
 *  cActuals    [I] Number of parameters.
 *  prgvt       [I] The types of the parameters to pass. This is used for sizing only.
 *  prgpvarg    [I] The arguments to pass.
 *  pvargResult [O] The return value of the function. Can be NULL.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * NOTES
 *  The HRESULT return value of this function is not affected by the return
 *  value of the user supplied function, which is returned in pvargResult.
 *
 *  If pvInstance is NULL then a non-object function is to be called and oVft
 *  is the address of the function to call.
 *
 * The cc parameter can be one of the following values:
 *|CC_FASTCALL
 *|CC_CDECL
 *|CC_PASCAL
 *|CC_STDCALL
 *|CC_FPFASTCALL
 *|CC_SYSCALL
 *|CC_MPWCDECL
 *|CC_MPWPASCAL
 *
6061
 */
6062 6063
HRESULT WINAPI
DispCallFunc(
6064
    void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
6065 6066
    VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
{
6067
#ifdef __i386__
6068 6069
    int argspos, stack_offset;
    void *func;
6070
    UINT i;
6071 6072
    DWORD *args;

6073
    TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
6074 6075 6076
        pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
        pvargResult, V_VT(pvargResult));

6077
    if (cc != CC_STDCALL && cc != CC_CDECL)
6078
    {
6079 6080
        FIXME("unsupported calling convention %d\n",cc);
        return E_INVALIDARG;
6081
    }
6082 6083

    /* maximum size for an argument is sizeof(VARIANT) */
6084
    args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
6085

6086 6087
    /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
    argspos = 1;
6088 6089
    if (pvInstance)
    {
6090 6091 6092
        const FARPROC *vtable = *(FARPROC **)pvInstance;
        func = vtable[oVft/sizeof(void *)];
        args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
6093
    }
6094
    else func = (void *)oVft;
6095

6096
    for (i = 0; i < cActuals; i++)
6097
    {
6098
        VARIANT *arg = prgpvarg[i];
6099 6100 6101

        switch (prgvt[i])
        {
6102 6103
        case VT_EMPTY:
            break;
6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116
        case VT_I8:
        case VT_UI8:
        case VT_R8:
        case VT_DATE:
        case VT_CY:
            memcpy( &args[argspos], &V_I8(arg), sizeof(V_I8(arg)) );
            argspos += sizeof(V_I8(arg)) / sizeof(DWORD);
            break;
        case VT_DECIMAL:
        case VT_VARIANT:
            memcpy( &args[argspos], arg, sizeof(*arg) );
            argspos += sizeof(*arg) / sizeof(DWORD);
            break;
6117 6118 6119
        case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
            args[argspos++] = V_BOOL(arg);
            break;
6120 6121 6122 6123 6124 6125
        default:
            args[argspos++] = V_UI4(arg);
            break;
        }
        TRACE("arg %u: type %d\n",i,prgvt[i]);
        dump_Variant(arg);
6126
    }
6127

6128
    switch (vtReturn)
6129
    {
6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152
    case VT_EMPTY:
        call_method( func, argspos - 1, args + 1, &stack_offset );
        break;
    case VT_R4:
        V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
        break;
    case VT_R8:
    case VT_DATE:
        V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1, &stack_offset );
        break;
    case VT_DECIMAL:
    case VT_VARIANT:
        args[0] = (DWORD)pvargResult;  /* arg 0 is a pointer to the result */
        call_method( func, argspos, args, &stack_offset );
        break;
    case VT_I8:
    case VT_UI8:
    case VT_CY:
        V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
        break;
    default:
        V_UI4(pvargResult) = call_method( func, argspos - 1, args + 1, &stack_offset );
        break;
6153
    }
6154
    heap_free( args );
6155
    if (stack_offset && cc == CC_STDCALL)
6156
    {
6157 6158
        WARN( "stack pointer off by %d\n", stack_offset );
        return DISP_E_BADCALLEE;
6159
    }
6160 6161
    if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
    TRACE("retval: "); dump_Variant(pvargResult);
6162
    return S_OK;
6163 6164 6165 6166

#elif defined(__x86_64__)
    int argspos;
    UINT i;
6167 6168
    DWORD_PTR *args;
    void *func;
6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179

    TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n",
          pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg,
          pvargResult, V_VT(pvargResult));

    if (cc != CC_STDCALL && cc != CC_CDECL)
    {
	FIXME("unsupported calling convention %d\n",cc);
        return E_INVALIDARG;
    }

6180
    /* maximum size for an argument is sizeof(DWORD_PTR) */
6181
    args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
6182

6183 6184
    /* start at 1 in case we need to pass a pointer to the return value as arg 0 */
    argspos = 1;
6185 6186
    if (pvInstance)
    {
6187 6188 6189
        const FARPROC *vtable = *(FARPROC **)pvInstance;
        func = vtable[oVft/sizeof(void *)];
        args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
6190
    }
6191
    else func = (void *)oVft;
6192 6193 6194 6195 6196 6197 6198 6199 6200

    for (i = 0; i < cActuals; i++)
    {
        VARIANT *arg = prgpvarg[i];

        switch (prgvt[i])
        {
        case VT_DECIMAL:
        case VT_VARIANT:
6201 6202 6203 6204
            args[argspos++] = (ULONG_PTR)arg;
            break;
        case VT_BOOL:  /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
            args[argspos++] = V_BOOL(arg);
6205 6206 6207 6208 6209 6210 6211 6212 6213
            break;
        default:
            args[argspos++] = V_UI8(arg);
            break;
        }
        TRACE("arg %u: type %d\n",i,prgvt[i]);
        dump_Variant(arg);
    }

6214
    switch (vtReturn)
6215
    {
6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230
    case VT_R4:
        V_R4(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
        break;
    case VT_R8:
    case VT_DATE:
        V_R8(pvargResult) = call_double_method( func, argspos - 1, args + 1 );
        break;
    case VT_DECIMAL:
    case VT_VARIANT:
        args[0] = (DWORD_PTR)pvargResult;  /* arg 0 is a pointer to the result */
        call_method( func, argspos, args );
        break;
    default:
        V_UI8(pvargResult) = call_method( func, argspos - 1, args + 1 );
        break;
6231
    }
6232
    heap_free( args );
6233 6234
    if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
    TRACE("retval: "); dump_Variant(pvargResult);
6235 6236
    return S_OK;

6237 6238 6239 6240 6241
#else
    FIXME( "(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d)): not implemented for this CPU\n",
           pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult));
    return E_NOTIMPL;
#endif
6242 6243
}

6244 6245 6246 6247 6248
static inline BOOL func_restricted( const FUNCDESC *desc )
{
    return (desc->wFuncFlags & FUNCFLAG_FRESTRICTED) && (desc->memid >= 0);
}

6249 6250
#define INVBUF_ELEMENT_SIZE \
    (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
6251
#define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
6252 6253 6254 6255 6256 6257 6258
#define INVBUF_GET_MISSING_ARG_ARRAY(buffer, params) \
    ((VARIANTARG *)((char *)(buffer) + sizeof(VARIANTARG) * (params)))
#define INVBUF_GET_ARG_PTR_ARRAY(buffer, params) \
    ((VARIANTARG **)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG)) * (params)))
#define INVBUF_GET_ARG_TYPE_ARRAY(buffer, params) \
    ((VARTYPE *)((char *)(buffer) + (sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *)) * (params)))

6259
static HRESULT WINAPI ITypeInfo_fnInvoke(
6260 6261 6262
    ITypeInfo2 *iface,
    VOID  *pIUnk,
    MEMBERID memid,
6263
    UINT16 wFlags,
6264 6265 6266 6267
    DISPPARAMS  *pDispParams,
    VARIANT  *pVarResult,
    EXCEPINFO  *pExcepInfo,
    UINT  *pArgErr)
6268
{
6269
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6270
    int i;
6271
    unsigned int var_index;
6272
    TYPEKIND type_kind;
6273
    HRESULT hres;
6274
    const TLBFuncDesc *pFuncInfo;
6275
    UINT fdc;
6276

6277
    TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
6278
      This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
6279
    );
6280

6281
    if( This->TypeAttr.wTypeFlags & TYPEFLAG_FRESTRICTED )
6282 6283
        return DISP_E_MEMBERNOTFOUND;

6284 6285 6286 6287 6288 6289
    if (!pDispParams)
    {
        ERR("NULL pDispParams not allowed\n");
        return E_INVALIDARG;
    }

6290
    dump_DispParms(pDispParams);
6291

6292 6293 6294 6295 6296 6297 6298
    if (pDispParams->cNamedArgs > pDispParams->cArgs)
    {
        ERR("named argument array cannot be bigger than argument array (%d/%d)\n",
            pDispParams->cNamedArgs, pDispParams->cArgs);
        return E_INVALIDARG;
    }

6299 6300
    /* we do this instead of using GetFuncDesc since it will return a fake
     * FUNCDESC for dispinterfaces and we want the real function description */
6301 6302
    for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
        pFuncInfo = &This->funcdescs[fdc];
6303
        if ((memid == pFuncInfo->funcdesc.memid) &&
6304
            (wFlags & pFuncInfo->funcdesc.invkind) &&
6305
            !func_restricted( &pFuncInfo->funcdesc ))
6306
            break;
6307
    }
6308

6309
    if (fdc < This->TypeAttr.cFuncs) {
6310
        const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
6311

6312 6313 6314
        if (TRACE_ON(ole))
        {
            TRACE("invoking:\n");
6315
            dump_TLBFuncDescOne(pFuncInfo);
6316
        }
6317 6318
        
	switch (func_desc->funckind) {
6319 6320
	case FUNC_PUREVIRTUAL:
	case FUNC_VIRTUAL: {
6321
            void *buffer = heap_alloc_zero(INVBUF_ELEMENT_SIZE * func_desc->cParams);
6322
            VARIANT varresult;
6323
            VARIANT retval; /* pointer for storing byref retvals in */
6324 6325 6326
            VARIANTARG **prgpvarg = INVBUF_GET_ARG_PTR_ARRAY(buffer, func_desc->cParams);
            VARIANTARG *rgvarg = INVBUF_GET_ARG_ARRAY(buffer, func_desc->cParams);
            VARTYPE *rgvt = INVBUF_GET_ARG_TYPE_ARRAY(buffer, func_desc->cParams);
6327 6328
            UINT cNamedArgs = pDispParams->cNamedArgs;
            DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
6329
            UINT vargs_converted=0;
6330

6331
            hres = S_OK;
6332 6333 6334 6335 6336 6337

            if (func_desc->invkind & (INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF))
            {
                if (!cNamedArgs || (rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
                {
                    ERR("first named arg for property put invocation must be DISPID_PROPERTYPUT\n");
6338
                    hres = DISP_E_PARAMNOTFOUND;
6339 6340 6341 6342
                    goto func_fail;
                }
            }

6343 6344 6345 6346 6347 6348 6349
            if (func_desc->cParamsOpt < 0 && cNamedArgs)
            {
                ERR("functions with the vararg attribute do not support named arguments\n");
                hres = DISP_E_NONAMEDARGS;
                goto func_fail;
            }

6350 6351
            for (i = 0; i < func_desc->cParams; i++)
            {
6352
                TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
6353
                hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
6354 6355
                if (FAILED(hres))
                    goto func_fail;
6356
            }
6357

6358
            TRACE("changing args\n");
6359 6360
            for (i = 0; i < func_desc->cParams; i++)
            {
6361
                USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6362 6363
                VARIANTARG *src_arg;

6364 6365 6366 6367 6368 6369 6370 6371 6372
                if (wParamFlags & PARAMFLAG_FLCID)
                {
                    VARIANTARG *arg;
                    arg = prgpvarg[i] = &rgvarg[i];
                    V_VT(arg) = VT_I4;
                    V_I4(arg) = This->pTypeLib->lcid;
                    continue;
                }

6373 6374
                src_arg = NULL;

6375
                if (cNamedArgs)
6376 6377
                {
                    USHORT j;
6378
                    for (j = 0; j < cNamedArgs; j++)
6379
                        if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
6380 6381 6382 6383 6384
                        {
                            src_arg = &pDispParams->rgvarg[j];
                            break;
                        }
                }
6385 6386

                if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
6387
                {
6388
                    src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6389 6390
                    vargs_converted++;
                }
6391

6392
                if (wParamFlags & PARAMFLAG_FRETVAL)
6393
                {
6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406
                    /* under most conditions the caller is not allowed to
                     * pass in a dispparam arg in the index of what would be
                     * the retval parameter. however, there is an exception
                     * where the extra parameter is used in an extra
                     * IDispatch::Invoke below */
                    if ((i < pDispParams->cArgs) &&
                        ((func_desc->cParams != 1) || !pVarResult ||
                         !(func_desc->invkind & INVOKE_PROPERTYGET)))
                    {
                        hres = DISP_E_BADPARAMCOUNT;
                        break;
                    }

6407 6408 6409 6410 6411 6412
                    /* note: this check is placed so that if the caller passes
                     * in a VARIANTARG for the retval we just ignore it, like
                     * native does */
                    if (i == func_desc->cParams - 1)
                    {
                        VARIANTARG *arg;
6413
                        arg = prgpvarg[i] = &rgvarg[i];
6414
                        memset(arg, 0, sizeof(*arg));
6415
                        V_VT(arg) = rgvt[i];
6416
                        memset(&retval, 0, sizeof(retval));
6417 6418 6419 6420 6421 6422 6423
                        V_BYREF(arg) = &retval;
                    }
                    else
                    {
                        ERR("[retval] parameter must be the last parameter of the method (%d/%d)\n", i, func_desc->cParams);
                        hres = E_UNEXPECTED;
                        break;
6424
                    }
6425
                }
6426
                else if (src_arg)
6427
                {
6428 6429
                    dump_Variant(src_arg);

6430
                    if(rgvt[i]!=V_VT(src_arg))
6431
                    {
6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477
                        if (rgvt[i] == VT_VARIANT)
                            hres = VariantCopy(&rgvarg[i], src_arg);
                        else if (rgvt[i] == (VT_VARIANT | VT_BYREF))
                        {
                            if (rgvt[i] == V_VT(src_arg))
                                V_VARIANTREF(&rgvarg[i]) = V_VARIANTREF(src_arg);
                            else
                            {
                                VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
                                if (wParamFlags & PARAMFLAG_FIN)
                                    hres = VariantCopy(&missing_arg[i], src_arg);
                                V_VARIANTREF(&rgvarg[i]) = &missing_arg[i];
                            }
                            V_VT(&rgvarg[i]) = rgvt[i];
                        }
                        else if (rgvt[i] == (VT_VARIANT | VT_ARRAY) && func_desc->cParamsOpt < 0 && i == func_desc->cParams-1)
                        {
                            SAFEARRAY *a;
                            SAFEARRAYBOUND bound;
                            VARIANT *v;
                            LONG j;
                            bound.lLbound = 0;
                            bound.cElements = pDispParams->cArgs-i;
                            if (!(a = SafeArrayCreate(VT_VARIANT, 1, &bound)))
                            {
                                ERR("SafeArrayCreate failed\n");
                                break;
                            }
                            hres = SafeArrayAccessData(a, (LPVOID)&v);
                            if (hres != S_OK)
                            {
                                ERR("SafeArrayAccessData failed with %x\n", hres);
                                break;
                            }
                            for (j = 0; j < bound.cElements; j++)
                                VariantCopy(&v[j], &pDispParams->rgvarg[pDispParams->cArgs - 1 - i - j]);
                            hres = SafeArrayUnaccessData(a);
                            if (hres != S_OK)
                            {
                                ERR("SafeArrayUnaccessData failed with %x\n", hres);
                                break;
                            }
                            V_ARRAY(&rgvarg[i]) = a;
                            V_VT(&rgvarg[i]) = rgvt[i];
                        }
                        else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
6478 6479
                        {
                            VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6480
                            if (wParamFlags & PARAMFLAG_FIN)
6481 6482 6483 6484 6485
                                hres = VariantChangeType(&missing_arg[i], src_arg, 0, rgvt[i] & ~VT_BYREF);
                            else
                                V_VT(&missing_arg[i]) = rgvt[i] & ~VT_BYREF;
                            V_BYREF(&rgvarg[i]) = &V_NONE(&missing_arg[i]);
                            V_VT(&rgvarg[i]) = rgvt[i];
6486
                        }
6487
                        else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
6488
                        {
6489 6490
                            V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
                            V_VT(&rgvarg[i]) = rgvt[i];
6491
                        }
6492
                        else
6493
                        {
6494 6495 6496 6497 6498
                            /* FIXME: this doesn't work for VT_BYREF arguments if
                             * they are not the same type as in the paramdesc */
                            V_VT(&rgvarg[i]) = V_VT(src_arg);
                            hres = VariantChangeType(&rgvarg[i], src_arg, 0, rgvt[i]);
                            V_VT(&rgvarg[i]) = rgvt[i];
6499
                        }
6500 6501

                        if (FAILED(hres))
6502
                        {
6503 6504 6505
                            ERR("failed to convert param %d to %s%s from %s%s\n", i,
                                debugstr_vt(rgvt[i]), debugstr_vf(rgvt[i]),
                                debugstr_VT(src_arg), debugstr_VF(src_arg));
6506 6507
                            break;
                        }
6508
                        prgpvarg[i] = &rgvarg[i];
6509
                    }
6510
                    else
6511
                    {
6512
                        prgpvarg[i] = src_arg;
6513
                    }
6514
                }
6515
                else if (wParamFlags & PARAMFLAG_FOPT)
6516
                {
6517
                    VARIANTARG *arg;
6518
                    arg = prgpvarg[i] = &rgvarg[i];
6519 6520 6521 6522 6523 6524
                    if (wParamFlags & PARAMFLAG_FHASDEFAULT)
                    {
                        hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
                        if (FAILED(hres))
                            break;
                    }
6525
                    else
6526
                    {
6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540
                        VARIANTARG *missing_arg;
                        /* if the function wants a pointer to a variant then
                         * set that up, otherwise just pass the VT_ERROR in
                         * the argument by value */
                        if (rgvt[i] & VT_BYREF)
                        {
                            missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams) + i;
                            V_VT(arg) = VT_VARIANT | VT_BYREF;
                            V_VARIANTREF(arg) = missing_arg;
                        }
                        else
                            missing_arg = arg;
                        V_VT(missing_arg) = VT_ERROR;
                        V_ERROR(missing_arg) = DISP_E_PARAMNOTFOUND;
6541 6542 6543 6544 6545 6546
                    }
                }
                else
                {
                    hres = DISP_E_BADPARAMCOUNT;
                    break;
6547 6548
                }
            }
6549
            if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
6550

6551 6552 6553 6554 6555 6556 6557 6558 6559 6560
            /* VT_VOID is a special case for return types, so it is not
             * handled in the general function */
            if (func_desc->elemdescFunc.tdesc.vt == VT_VOID)
                V_VT(&varresult) = VT_EMPTY;
            else
            {
                V_VT(&varresult) = 0;
                hres = typedescvt_to_variantvt((ITypeInfo *)iface, &func_desc->elemdescFunc.tdesc, &V_VT(&varresult));
                if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
            }
6561

6562 6563 6564
            hres = DispCallFunc(pIUnk, func_desc->oVft, func_desc->callconv,
                                V_VT(&varresult), func_desc->cParams, rgvt,
                                prgpvarg, &varresult);
6565

6566 6567
            vargs_converted = 0;

6568 6569 6570
            for (i = 0; i < func_desc->cParams; i++)
            {
                USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
6571
                VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
6572 6573 6574 6575

                if (wParamFlags & PARAMFLAG_FLCID)
                    continue;
                else if (wParamFlags & PARAMFLAG_FRETVAL)
6576 6577 6578
                {
                    if (TRACE_ON(ole))
                    {
6579
                        TRACE("[retval] value: ");
6580
                        dump_Variant(prgpvarg[i]);
6581 6582 6583
                    }

                    if (pVarResult)
6584 6585
                    {
                        VariantInit(pVarResult);
6586
                        /* deref return value */
6587
                        hres = VariantCopyInd(pVarResult, prgpvarg[i]);
6588
                    }
6589

6590
                    VARIANT_ClearInd(prgpvarg[i]);
6591
                }
6592
                else if (vargs_converted < pDispParams->cArgs)
6593
                {
6594
                    VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
6595 6596
                    if (wParamFlags & PARAMFLAG_FOUT)
                    {
6597 6598
                        if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
                        {
6599 6600
                            hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));

6601 6602 6603 6604 6605 6606
                            if (FAILED(hres))
                            {
                                ERR("failed to convert param %d to vt %d\n", i,
                                    V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
                                break;
                            }
6607 6608
                        }
                    }
6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636
                    else if (V_VT(prgpvarg[i]) == (VT_VARIANT | VT_ARRAY) &&
                             func_desc->cParamsOpt < 0 &&
                             i == func_desc->cParams-1)
                    {
                        SAFEARRAY *a = V_ARRAY(prgpvarg[i]);
                        LONG j, ubound;
                        VARIANT *v;
                        hres = SafeArrayGetUBound(a, 1, &ubound);
                        if (hres != S_OK)
                        {
                            ERR("SafeArrayGetUBound failed with %x\n", hres);
                            break;
                        }
                        hres = SafeArrayAccessData(a, (LPVOID)&v);
                        if (hres != S_OK)
                        {
                            ERR("SafeArrayAccessData failed with %x\n", hres);
                            break;
                        }
                        for (j = 0; j <= ubound; j++)
                            VariantClear(&v[j]);
                        hres = SafeArrayUnaccessData(a);
                        if (hres != S_OK)
                        {
                            ERR("SafeArrayUnaccessData failed with %x\n", hres);
                            break;
                        }
                    }
6637
                    VariantClear(&rgvarg[i]);
6638
                    vargs_converted++;
6639 6640 6641 6642
                }
                else if (wParamFlags & PARAMFLAG_FOPT)
                {
                    if (wParamFlags & PARAMFLAG_FHASDEFAULT)
6643
                        VariantClear(&rgvarg[i]);
6644
                }
6645 6646

                VariantClear(&missing_arg[i]);
6647 6648
            }

6649
            if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
6650
            {
6651
                WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
6652
                hres = DISP_E_EXCEPTION;
6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666
                if (pExcepInfo)
                {
                    IErrorInfo *pErrorInfo;
                    pExcepInfo->scode = V_ERROR(&varresult);
                    if (GetErrorInfo(0, &pErrorInfo) == S_OK)
                    {
                        IErrorInfo_GetDescription(pErrorInfo, &pExcepInfo->bstrDescription);
                        IErrorInfo_GetHelpFile(pErrorInfo, &pExcepInfo->bstrHelpFile);
                        IErrorInfo_GetSource(pErrorInfo, &pExcepInfo->bstrSource);
                        IErrorInfo_GetHelpContext(pErrorInfo, &pExcepInfo->dwHelpContext);

                        IErrorInfo_Release(pErrorInfo);
                    }
                }
6667
            }
6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680
            if (V_VT(&varresult) != VT_ERROR)
            {
                TRACE("varresult value: ");
                dump_Variant(&varresult);

                if (pVarResult)
                {
                    VariantClear(pVarResult);
                    *pVarResult = varresult;
                }
                else
                    VariantClear(&varresult);
            }
6681

6682
            if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
6683
                (func_desc->invkind & INVOKE_PROPERTYGET) &&
6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704
                (func_desc->lprgelemdescParam[0].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL) &&
                (pDispParams->cArgs != 0))
            {
                if (V_VT(pVarResult) == VT_DISPATCH)
                {
                    IDispatch *pDispatch = V_DISPATCH(pVarResult);
                    /* Note: not VariantClear; we still need the dispatch
                     * pointer to be valid */
                    VariantInit(pVarResult);
                    hres = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL,
                        GetSystemDefaultLCID(), INVOKE_PROPERTYGET,
                        pDispParams, pVarResult, pExcepInfo, pArgErr);
                    IDispatch_Release(pDispatch);
                }
                else
                {
                    VariantClear(pVarResult);
                    hres = DISP_E_NOTACOLLECTION;
                }
            }

6705
func_fail:
6706
            heap_free(buffer);
6707
            break;
6708
        }
6709 6710 6711
	case FUNC_DISPATCH:  {
	   IDispatch *disp;

6712 6713 6714 6715
	   hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
	   if (SUCCEEDED(hres)) {
               FIXME("Calling Invoke in IDispatch iface. untested!\n");
               hres = IDispatch_Invoke(
6716
                                     disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
6717 6718 6719
                                     pVarResult,pExcepInfo,pArgErr
                                     );
               if (FAILED(hres))
6720
                   FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
6721 6722
               IDispatch_Release(disp);
           } else
6723
	       FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
6724
           break;
6725 6726
	}
	default:
6727 6728 6729 6730 6731
            FIXME("Unknown function invocation type %d\n", func_desc->funckind);
            hres = E_FAIL;
            break;
        }

6732
        TRACE("-- 0x%08x\n", hres);
6733 6734
        return hres;

6735 6736 6737 6738 6739 6740 6741 6742 6743 6744
    } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) {
        VARDESC *var_desc;

        hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc);
        if(FAILED(hres)) return hres;
        
        FIXME("varseek: Found memid, but variable-based invoking not supported\n");
        dump_VARDESC(var_desc);
        ITypeInfo2_ReleaseVarDesc(iface, var_desc);
        return E_NOTIMPL;
6745
    }
6746

6747
    /* not found, look for it in inherited interfaces */
6748 6749
    ITypeInfo2_GetTypeKind(iface, &type_kind);
    if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
6750
        if(This->impltypes) {
6751 6752
            /* recursive search */
            ITypeInfo *pTInfo;
6753
            hres = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
6754
            if(SUCCEEDED(hres)){
6755
                hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
6756 6757 6758 6759
                ITypeInfo_Release(pTInfo);
                return hres;
            }
            WARN("Could not search inherited interface!\n");
6760 6761
        }
    }
6762
    WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
6763
    return DISP_E_MEMBERNOTFOUND;
6764 6765 6766
}

/* ITypeInfo::GetDocumentation
6767
 *
6768 6769
 * Retrieves the documentation string, the complete Help file name and path,
 * and the context ID for the Help topic for a specified type description.
6770 6771
 *
 * (Can be tested by the Visual Basic Editor in Word for instance.)
6772
 */
6773
static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
6774 6775 6776
        MEMBERID memid, BSTR  *pBstrName, BSTR  *pBstrDocString,
        DWORD  *pdwHelpContext, BSTR  *pBstrHelpFile)
{
6777
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6778 6779
    const TLBFuncDesc *pFDesc;
    const TLBVarDesc *pVDesc;
6780
    TRACE("(%p) memid %d Name(%p) DocString(%p)"
6781
          " HelpContext(%p) HelpFile(%p)\n",
6782 6783 6784
        This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
    if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
        if(pBstrName)
6785
            *pBstrName=SysAllocString(This->Name);
6786
        if(pBstrDocString)
6787
            *pBstrDocString=SysAllocString(This->DocString);
6788 6789 6790
        if(pdwHelpContext)
            *pdwHelpContext=This->dwHelpContext;
        if(pBstrHelpFile)
6791
            *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */
6792 6793
        return S_OK;
    }else {/* for a member */
6794 6795 6796 6797 6798 6799 6800 6801 6802
        pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
        if(pFDesc){
            if(pBstrName)
              *pBstrName = SysAllocString(pFDesc->Name);
            if(pBstrDocString)
              *pBstrDocString=SysAllocString(pFDesc->HelpString);
            if(pdwHelpContext)
              *pdwHelpContext=pFDesc->helpcontext;
            return S_OK;
6803
        }
6804 6805 6806 6807 6808 6809 6810 6811 6812
        pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
        if(pVDesc){
            if(pBstrName)
              *pBstrName = SysAllocString(pVDesc->Name);
            if(pBstrDocString)
              *pBstrDocString=SysAllocString(pVDesc->HelpString);
            if(pdwHelpContext)
              *pdwHelpContext=pVDesc->HelpContext;
            return S_OK;
6813 6814
        }
    }
6815

6816
    if(This->impltypes &&
6817 6818 6819 6820
       (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) {
        /* recursive search */
        ITypeInfo *pTInfo;
        HRESULT result;
6821
        result = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef,
6822 6823 6824 6825 6826 6827 6828 6829 6830 6831
                                        &pTInfo);
        if(SUCCEEDED(result)) {
            result = ITypeInfo_GetDocumentation(pTInfo, memid, pBstrName,
                pBstrDocString, pdwHelpContext, pBstrHelpFile);
            ITypeInfo_Release(pTInfo);
            return result;
        }
        WARN("Could not search inherited interface!\n");
    }

6832
    WARN("member %d not found\n", memid);
6833 6834 6835 6836
    return TYPE_E_ELEMENTNOTFOUND;
}

/*  ITypeInfo::GetDllEntry
6837
 *
6838 6839 6840
 * Retrieves a description or specification of an entry point for a function
 * in a DLL.
 */
6841
static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
6842 6843 6844
        INVOKEKIND invKind, BSTR  *pBstrDllName, BSTR  *pBstrName,
        WORD  *pwOrdinal)
{
6845
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6846
    const TLBFuncDesc *pFDesc;
6847

6848
    TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
6849 6850 6851 6852 6853 6854 6855

    if (pBstrDllName) *pBstrDllName = NULL;
    if (pBstrName) *pBstrName = NULL;
    if (pwOrdinal) *pwOrdinal = 0;

    if (This->TypeAttr.typekind != TKIND_MODULE)
        return TYPE_E_BADMODULEKIND;
6856

6857 6858
    pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
    if(pFDesc){
6859
	    dump_TypeInfo(This);
6860 6861
	    if (TRACE_ON(ole))
		dump_TLBFuncDescOne(pFDesc);
6862

6863 6864
	    if (pBstrDllName)
		*pBstrDllName = SysAllocString(This->DllName);
6865

6866
            if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
6867 6868 6869 6870 6871 6872 6873 6874 6875
		if (pBstrName)
		    *pBstrName = SysAllocString(pFDesc->Entry);
		if (pwOrdinal)
		    *pwOrdinal = -1;
		return S_OK;
	    }
	    if (pBstrName)
		*pBstrName = NULL;
	    if (pwOrdinal)
6876
		*pwOrdinal = LOWORD(pFDesc->Entry);
6877 6878
	    return S_OK;
        }
6879
    return TYPE_E_ELEMENTNOTFOUND;
6880 6881
}

6882 6883 6884 6885 6886 6887 6888 6889 6890 6891
/* internal function to make the inherited interfaces' methods appear
 * part of the interface */
static HRESULT ITypeInfoImpl_GetDispatchRefTypeInfo( ITypeInfo *iface,
    HREFTYPE *hRefType, ITypeInfo  **ppTInfo)
{
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
    HRESULT hr;

    TRACE("%p, 0x%x\n", iface, *hRefType);

6892
    if (This->impltypes && (*hRefType & DISPATCH_HREF_MASK))
6893 6894 6895
    {
        ITypeInfo *pSubTypeInfo;

6896
        hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913
        if (FAILED(hr))
            return hr;

        hr = ITypeInfoImpl_GetDispatchRefTypeInfo(pSubTypeInfo,
                                                  hRefType, ppTInfo);
        ITypeInfo_Release(pSubTypeInfo);
        if (SUCCEEDED(hr))
            return hr;
    }
    *hRefType -= DISPATCH_HREF_OFFSET;

    if (!(*hRefType & DISPATCH_HREF_MASK))
        return ITypeInfo_GetRefTypeInfo(iface, *hRefType, ppTInfo);
    else
        return E_FAIL;
}

6914
/* ITypeInfo::GetRefTypeInfo
6915
 *
6916 6917 6918
 * If a type description references other type descriptions, it retrieves
 * the referenced type descriptions.
 */
6919 6920 6921 6922
static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
	ITypeInfo2 *iface,
        HREFTYPE hRefType,
	ITypeInfo  **ppTInfo)
6923
{
6924
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
6925
    HRESULT result = E_FAIL;
6926

6927 6928 6929 6930 6931 6932 6933
    if ((This->hreftype != -1) && (This->hreftype == hRefType))
    {
        *ppTInfo = (ITypeInfo *)&This->lpVtbl;
        ITypeInfo_AddRef(*ppTInfo);
        result = S_OK;
    }
    else if (hRefType == -1 &&
6934 6935
	(This->TypeAttr.typekind   == TKIND_DISPATCH) &&
	(This->TypeAttr.wTypeFlags &  TYPEFLAG_FDUAL))
6936
    {
6937
	  /* when we meet a DUAL dispinterface, we must create the interface
6938 6939
	  * version of it.
	  */
6940
	  ITypeInfoImpl *pTypeInfoImpl = ITypeInfoImpl_Constructor();
6941

6942

6943 6944 6945 6946
	  /* the interface version contains the same information as the dispinterface
	   * copy the contents of the structs.
	   */
	  *pTypeInfoImpl = *This;
6947
	  pTypeInfoImpl->ref = 0;
6948

6949 6950
	  /* change the type to interface */
	  pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE;
6951

6952
	  *ppTInfo = (ITypeInfo*) pTypeInfoImpl;
6953

6954 6955 6956
	  /* the AddRef implicitly adds a reference to the parent typelib, which
	   * stops the copied data from being destroyed until the new typeinfo's
	   * refcount goes to zero, but we need to signal to the new instance to
6957
	   * not free its data structures when it is destroyed */
6958
	  pTypeInfoImpl->not_attached_to_typelib = TRUE;
6959 6960

	  ITypeInfo_AddRef(*ppTInfo);
6961

6962 6963
	  result = S_OK;

6964
    } else if ((hRefType != -1) && (hRefType & DISPATCH_HREF_MASK) &&
6965
        (This->TypeAttr.typekind   == TKIND_DISPATCH))
6966 6967 6968
    {
        HREFTYPE href_dispatch = hRefType;
        result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
6969
    } else {
6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981
        TLBRefType *ref_type;
        LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
        {
            if(ref_type->reference == hRefType)
                break;
        }
        if(&ref_type->entry == &This->pTypeLib->ref_list)
        {
            FIXME("Can't find pRefType for ref %x\n", hRefType);
            goto end;
        }
        if(hRefType != -1) {
6982
            ITypeLib *pTLib = NULL;
6983

6984
            if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
Mike McCormack's avatar
Mike McCormack committed
6985
	        UINT Index;
6986 6987
		result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index);
	    } else {
6988
                if(ref_type->pImpTLInfo->pImpTypeLib) {
6989
		    TRACE("typeinfo in imported typelib that is already loaded\n");
6990
                    pTLib = (ITypeLib*)ref_type->pImpTLInfo->pImpTypeLib;
6991
		    ITypeLib2_AddRef(pTLib);
6992 6993 6994
		    result = S_OK;
		} else {
		    TRACE("typeinfo in imported typelib that isn't already loaded\n");
6995 6996 6997 6998
                    result = LoadRegTypeLib( &ref_type->pImpTLInfo->guid,
                                             ref_type->pImpTLInfo->wVersionMajor,
                                             ref_type->pImpTLInfo->wVersionMinor,
                                             ref_type->pImpTLInfo->lcid,
6999 7000
					     &pTLib);

7001
                    if(FAILED(result)) {
7002
                        BSTR libnam=SysAllocString(ref_type->pImpTLInfo->name);
7003 7004 7005 7006
			result=LoadTypeLib(libnam, &pTLib);
			SysFreeString(libnam);
		    }
		    if(SUCCEEDED(result)) {
7007
                        ref_type->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib;
7008 7009 7010 7011 7012
			ITypeLib2_AddRef(pTLib);
		    }
		}
	    }
	    if(SUCCEEDED(result)) {
7013
                if(ref_type->index == TLB_REF_USE_GUID)
7014
		    result = ITypeLib2_GetTypeInfoOfGuid(pTLib,
7015
                                                         &ref_type->guid,
7016 7017
							 ppTInfo);
		else
7018
                    result = ITypeLib2_GetTypeInfo(pTLib, ref_type->index,
7019 7020
						   ppTInfo);
	    }
7021 7022
	    if (pTLib != NULL)
		ITypeLib2_Release(pTLib);
7023
	}
7024
    }
7025

7026
end:
7027
    TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
7028
          SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
7029 7030 7031 7032
    return result;
}

/* ITypeInfo::AddressOfMember
7033
 *
7034 7035 7036
 * Retrieves the addresses of static functions or variables, such as those
 * defined in a DLL.
 */
7037
static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
7038 7039
        MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
{
7040
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7041 7042 7043 7044 7045
    HRESULT hr;
    BSTR dll, entry;
    WORD ordinal;
    HMODULE module;

7046
    TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
7047 7048 7049 7050 7051 7052 7053 7054 7055 7056

    hr = ITypeInfo_GetDllEntry(iface, memid, invKind, &dll, &entry, &ordinal);
    if (FAILED(hr))
        return hr;

    module = LoadLibraryW(dll);
    if (!module)
    {
        ERR("couldn't load %s\n", debugstr_w(dll));
        SysFreeString(dll);
7057
        SysFreeString(entry);
7058 7059 7060 7061 7062 7063 7064 7065
        return STG_E_FILENOTFOUND;
    }
    /* FIXME: store library somewhere where we can free it */

    if (entry)
    {
        LPSTR entryA;
        INT len = WideCharToMultiByte(CP_ACP, 0, entry, -1, NULL, 0, NULL, NULL);
7066
        entryA = heap_alloc(len);
7067 7068 7069 7070 7071 7072
        WideCharToMultiByte(CP_ACP, 0, entry, -1, entryA, len, NULL, NULL);

        *ppv = GetProcAddress(module, entryA);
        if (!*ppv)
            ERR("function not found %s\n", debugstr_a(entryA));

7073
        heap_free(entryA);
7074 7075 7076 7077 7078 7079 7080 7081 7082
    }
    else
    {
        *ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
        if (!*ppv)
            ERR("function not found %d\n", ordinal);
    }

    SysFreeString(dll);
7083
    SysFreeString(entry);
7084 7085 7086 7087

    if (!*ppv)
        return TYPE_E_DLLFUNCTIONNOTFOUND;

7088 7089 7090 7091
    return S_OK;
}

/* ITypeInfo::CreateInstance
7092 7093
 *
 * Creates a new instance of a type that describes a component object class
7094 7095
 * (coclass).
 */
7096
static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
7097
        IUnknown *pOuterUnk, REFIID riid, VOID  **ppvObj)
7098
{
7099
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127
    HRESULT hr;
    TYPEATTR *pTA;

    TRACE("(%p)->(%p, %s, %p)\n", This, pOuterUnk, debugstr_guid(riid), ppvObj);

    *ppvObj = NULL;

    if(pOuterUnk)
    {
        WARN("Not able to aggregate\n");
        return CLASS_E_NOAGGREGATION;
    }

    hr = ITypeInfo_GetTypeAttr(iface, &pTA);
    if(FAILED(hr)) return hr;

    if(pTA->typekind != TKIND_COCLASS)
    {
        WARN("CreateInstance on typeinfo of type %x\n", pTA->typekind);
        hr = E_INVALIDARG;
        goto end;
    }

    hr = S_FALSE;
    if(pTA->wTypeFlags & TYPEFLAG_FAPPOBJECT)
    {
        IUnknown *pUnk;
        hr = GetActiveObject(&pTA->guid, NULL, &pUnk);
7128
        TRACE("GetActiveObject rets %08x\n", hr);
7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143
        if(hr == S_OK)
        {
            hr = IUnknown_QueryInterface(pUnk, riid, ppvObj);
            IUnknown_Release(pUnk);
        }
    }

    if(hr != S_OK)
        hr = CoCreateInstance(&pTA->guid, NULL,
                              CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
                              riid, ppvObj);

end:
    ITypeInfo_ReleaseTypeAttr(iface, pTA);
    return hr;
7144 7145 7146 7147
}

/* ITypeInfo::GetMops
 *
7148
 * Retrieves marshalling information.
7149
 */
7150
static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
7151 7152
				BSTR  *pBstrMops)
{
7153
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7154 7155
    FIXME("(%p %d) stub!\n", This, memid);
    *pBstrMops = NULL;
7156 7157 7158 7159
    return S_OK;
}

/* ITypeInfo::GetContainingTypeLib
7160
 *
7161 7162 7163
 * Retrieves the containing type library and the index of the type description
 * within that type library.
 */
7164
static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
7165 7166
        ITypeLib  * *ppTLib, UINT  *pIndex)
{
7167
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7168 7169 7170 7171
    
    /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
    if (pIndex) {
      *pIndex=This->index;
7172
      TRACE("returning pIndex=%d\n", *pIndex);
7173 7174 7175 7176 7177
    }
    
    if (ppTLib) {
      *ppTLib=(LPTYPELIB )(This->pTypeLib);
      ITypeLib2_AddRef(*ppTLib);
7178
      TRACE("returning ppTLib=%p\n", *ppTLib);
7179 7180
    }
    
7181 7182 7183 7184 7185 7186 7187 7188
    return S_OK;
}

/* ITypeInfo::ReleaseTypeAttr
 *
 * Releases a TYPEATTR previously returned by GetTypeAttr.
 *
 */
7189
static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
7190 7191
        TYPEATTR* pTypeAttr)
{
7192
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7193
    TRACE("(%p)->(%p)\n", This, pTypeAttr);
7194
    heap_free(pTypeAttr);
7195 7196 7197 7198 7199 7200
}

/* ITypeInfo::ReleaseFuncDesc
 *
 * Releases a FUNCDESC previously returned by GetFuncDesc. *
 */
7201
static void WINAPI ITypeInfo_fnReleaseFuncDesc(
7202
	ITypeInfo2 *iface,
7203 7204
        FUNCDESC *pFuncDesc)
{
7205
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7206 7207
    SHORT i;

7208
    TRACE("(%p)->(%p)\n", This, pFuncDesc);
7209 7210 7211 7212 7213 7214

    for (i = 0; i < pFuncDesc->cParams; i++)
        TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
    TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);

    SysFreeString((BSTR)pFuncDesc);
7215 7216 7217 7218 7219 7220
}

/* ITypeInfo::ReleaseVarDesc
 *
 * Releases a VARDESC previously returned by GetVarDesc.
 */
7221
static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
7222 7223
        VARDESC *pVarDesc)
{
7224
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7225
    TRACE("(%p)->(%p)\n", This, pVarDesc);
7226

7227
    TLB_FreeElemDesc(&pVarDesc->elemdescVar);
7228 7229 7230
    if (pVarDesc->varkind == VAR_CONST)
        VariantClear(pVarDesc->u.lpvarValue);
    SysFreeString((BSTR)pVarDesc);
7231 7232 7233 7234 7235 7236 7237
}

/* ITypeInfo2::GetTypeKind
 *
 * Returns the TYPEKIND enumeration quickly, without doing any allocations.
 *
 */
7238
static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
7239 7240
    TYPEKIND *pTypeKind)
{
7241
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7242
    *pTypeKind=This->TypeAttr.typekind;
7243
    TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
7244 7245 7246 7247 7248 7249 7250
    return S_OK;
}

/* ITypeInfo2::GetTypeFlags
 *
 * Returns the type flags without any allocations. This returns a DWORD type
 * flag, which expands the type flags without growing the TYPEATTR (type
7251
 * attribute).
7252 7253
 *
 */
7254
static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
7255
{
7256
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7257
    *pTypeFlags=This->TypeAttr.wTypeFlags;
7258
    TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
7259
    return S_OK;
7260 7261 7262 7263 7264 7265 7266
}

/* ITypeInfo2::GetFuncIndexOfMemId
 * Binds to a specific member based on a known DISPID, where the member name
 * is not known (for example, when binding to a default member).
 *
 */
7267
static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
7268 7269
    MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
{
7270
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7271
    UINT fdc;
7272
    HRESULT result;
7273

7274 7275
    for (fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
        const TLBFuncDesc *pFuncInfo = &This->funcdescs[fdc];
7276 7277
        if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
            break;
7278 7279 7280
    }
    if(fdc < This->TypeAttr.cFuncs) {
        *pFuncIndex = fdc;
7281 7282 7283 7284
        result = S_OK;
    } else
        result = TYPE_E_ELEMENTNOTFOUND;

7285
    TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
7286
          memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
7287 7288 7289 7290 7291 7292
    return result;
}

/* TypeInfo2::GetVarIndexOfMemId
 *
 * Binds to a specific member based on a known DISPID, where the member name
7293
 * is not known (for example, when binding to a default member).
7294 7295
 *
 */
7296
static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
7297 7298
    MEMBERID memid, UINT *pVarIndex)
{
7299
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7300
    TLBVarDesc *pVarInfo;
7301

7302 7303 7304 7305 7306 7307 7308 7309 7310
    TRACE("%p %d %p\n", iface, memid, pVarIndex);

    pVarInfo = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
    if(!pVarInfo)
        return TYPE_E_ELEMENTNOTFOUND;

    *pVarIndex = (pVarInfo - This->vardescs);

    return S_OK;
7311 7312 7313 7314 7315 7316
}

/* ITypeInfo2::GetCustData
 *
 * Gets the custom data
 */
7317 7318 7319 7320
static HRESULT WINAPI ITypeInfo2_fnGetCustData(
	ITypeInfo2 * iface,
	REFGUID guid,
	VARIANT *pVarVal)
7321
{
7322
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7323
    TLBCustData *pCData;
7324

7325
    TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
7326

7327
    pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
7328

7329 7330
    VariantInit( pVarVal);
    if (pCData)
7331
        VariantCopy( pVarVal, &pCData->data);
7332 7333 7334
    else
        VariantClear( pVarVal );
    return S_OK;
7335 7336 7337 7338 7339 7340
}

/* ITypeInfo2::GetFuncCustData
 *
 * Gets the custom data
 */
7341 7342 7343 7344 7345
static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
	ITypeInfo2 * iface,
	UINT index,
	REFGUID guid,
	VARIANT *pVarVal)
7346
{
7347
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7348
    TLBCustData *pCData;
7349
    TLBFuncDesc *pFDesc = &This->funcdescs[index];
7350

7351 7352
    TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);

7353 7354 7355
    if(index >= This->TypeAttr.cFuncs)
        return TYPE_E_ELEMENTNOTFOUND;

7356
    pCData = TLB_get_custdata_by_guid(&pFDesc->custdata_list, guid);
7357 7358
    if(!pCData)
        return TYPE_E_ELEMENTNOTFOUND;
7359

7360 7361
    VariantInit(pVarVal);
    VariantCopy(pVarVal, &pCData->data);
7362

7363
    return S_OK;
7364 7365 7366 7367 7368 7369
}

/* ITypeInfo2::GetParamCustData
 *
 * Gets the custom data
 */
7370 7371 7372 7373 7374 7375
static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
	ITypeInfo2 * iface,
	UINT indexFunc,
	UINT indexParam,
	REFGUID guid,
	VARIANT *pVarVal)
7376
{
7377
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7378 7379
    TLBCustData *pCData;
    TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
7380

7381 7382 7383
    TRACE("%p %u %u %s %p\n", This, indexFunc, indexParam,
            debugstr_guid(guid), pVarVal);

7384 7385
    if(indexFunc >= This->TypeAttr.cFuncs)
        return TYPE_E_ELEMENTNOTFOUND;
7386

7387 7388 7389
    if(indexParam >= pFDesc->funcdesc.cParams)
        return TYPE_E_ELEMENTNOTFOUND;

7390
    pCData = TLB_get_custdata_by_guid(&pFDesc->pParamDesc[indexParam].custdata_list, guid);
7391 7392
    if(!pCData)
        return TYPE_E_ELEMENTNOTFOUND;
7393

7394 7395
    VariantInit(pVarVal);
    VariantCopy(pVarVal, &pCData->data);
7396

7397
    return S_OK;
7398 7399
}

7400
/* ITypeInfo2::GetVarCustData
7401 7402 7403
 *
 * Gets the custom data
 */
7404 7405 7406 7407 7408
static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
	ITypeInfo2 * iface,
	UINT index,
	REFGUID guid,
	VARIANT *pVarVal)
7409
{
7410
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7411
    TLBCustData *pCData;
7412
    TLBVarDesc *pVDesc = &This->vardescs[index];
7413

7414
    TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
7415

7416 7417
    if(index >= This->TypeAttr.cVars)
        return TYPE_E_ELEMENTNOTFOUND;
7418

7419
    pCData = TLB_get_custdata_by_guid(&pVDesc->custdata_list, guid);
7420 7421
    if(!pCData)
        return TYPE_E_ELEMENTNOTFOUND;
7422

7423 7424 7425
    VariantInit(pVarVal);
    VariantCopy(pVarVal, &pCData->data);

7426
    return S_OK;
7427 7428
}

7429
/* ITypeInfo2::GetImplCustData
7430 7431 7432
 *
 * Gets the custom data
 */
7433 7434 7435 7436 7437
static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
	ITypeInfo2 * iface,
	UINT index,
	REFGUID guid,
	VARIANT *pVarVal)
7438
{
7439
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7440
    TLBCustData *pCData;
7441
    TLBImplType *pRDesc = &This->impltypes[index];
7442

7443 7444
    TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);

7445 7446
    if(index >= This->TypeAttr.cImplTypes)
        return TYPE_E_ELEMENTNOTFOUND;
7447

7448
    pCData = TLB_get_custdata_by_guid(&pRDesc->custdata_list, guid);
7449 7450
    if(!pCData)
        return TYPE_E_ELEMENTNOTFOUND;
7451

7452 7453
    VariantInit(pVarVal);
    VariantCopy(pVarVal, &pCData->data);
7454

7455
    return S_OK;
7456 7457 7458
}

/* ITypeInfo2::GetDocumentation2
7459
 *
7460 7461 7462 7463 7464
 * Retrieves the documentation string, the complete Help file name and path,
 * the localization context to use, and the context ID for the library Help
 * topic in the Help file.
 *
 */
7465 7466 7467 7468 7469 7470 7471
static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
	ITypeInfo2 * iface,
	MEMBERID memid,
	LCID lcid,
	BSTR *pbstrHelpString,
	DWORD *pdwHelpStringContext,
	BSTR *pbstrHelpStringDll)
7472
{
7473
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7474 7475
    const TLBFuncDesc *pFDesc;
    const TLBVarDesc *pVDesc;
7476
    TRACE("(%p) memid %d lcid(0x%x)  HelpString(%p) "
7477 7478 7479
          "HelpStringContext(%p) HelpStringDll(%p)\n",
          This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
          pbstrHelpStringDll );
7480 7481 7482 7483 7484 7485
    /* the help string should be obtained from the helpstringdll,
     * using the _DLLGetDocumentation function, based on the supplied
     * lcid. Nice to do sometime...
     */
    if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
        if(pbstrHelpString)
7486
            *pbstrHelpString=SysAllocString(This->Name);
7487 7488 7489 7490
        if(pdwHelpStringContext)
            *pdwHelpStringContext=This->dwHelpStringContext;
        if(pbstrHelpStringDll)
            *pbstrHelpStringDll=
7491
                SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7492 7493
        return S_OK;
    }else {/* for a member */
7494 7495 7496
        pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->TypeAttr.cFuncs, memid);
        if(pFDesc){
            if(pbstrHelpString)
7497
                *pbstrHelpString=SysAllocString(pFDesc->HelpString);
7498 7499 7500 7501
            if(pdwHelpStringContext)
                *pdwHelpStringContext=pFDesc->HelpStringContext;
            if(pbstrHelpStringDll)
                *pbstrHelpStringDll=
7502
                    SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7503 7504
            return S_OK;
        }
7505 7506 7507
        pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->TypeAttr.cVars, memid);
        if(pVDesc){
            if(pbstrHelpString)
7508
                *pbstrHelpString=SysAllocString(pVDesc->HelpString);
7509 7510 7511 7512
            if(pdwHelpStringContext)
                *pdwHelpStringContext=pVDesc->HelpStringContext;
            if(pbstrHelpStringDll)
                *pbstrHelpStringDll=
7513
                    SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */
7514 7515 7516 7517 7518 7519 7520 7521
            return S_OK;
        }
    }
    return TYPE_E_ELEMENTNOTFOUND;
}

/* ITypeInfo2::GetAllCustData
 *
7522
 * Gets all custom data items for the Type info.
7523 7524
 *
 */
7525 7526 7527
static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
	ITypeInfo2 * iface,
	CUSTDATA *pCustData)
7528
{
7529
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7530

7531
    TRACE("%p %p\n", This, pCustData);
7532

7533
    return TLB_copy_all_custdata(&This->custdata_list, pCustData);
7534 7535 7536 7537 7538 7539 7540
}

/* ITypeInfo2::GetAllFuncCustData
 *
 * Gets all custom data items for the specified Function
 *
 */
7541 7542 7543 7544
static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
	ITypeInfo2 * iface,
	UINT index,
	CUSTDATA *pCustData)
7545
{
7546
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7547
    TLBFuncDesc *pFDesc = &This->funcdescs[index];
7548 7549

    TRACE("%p %u %p\n", This, index, pCustData);
7550 7551 7552 7553

    if(index >= This->TypeAttr.cFuncs)
        return TYPE_E_ELEMENTNOTFOUND;

7554
    return TLB_copy_all_custdata(&pFDesc->custdata_list, pCustData);
7555 7556 7557 7558 7559 7560 7561
}

/* ITypeInfo2::GetAllParamCustData
 *
 * Gets all custom data items for the Functions
 *
 */
7562
static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
7563 7564
    UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
{
7565
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7566
    TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
7567 7568

    TRACE("%p %u %u %p\n", This, indexFunc, indexParam, pCustData);
7569 7570 7571 7572 7573 7574 7575

    if(indexFunc >= This->TypeAttr.cFuncs)
        return TYPE_E_ELEMENTNOTFOUND;

    if(indexParam >= pFDesc->funcdesc.cParams)
        return TYPE_E_ELEMENTNOTFOUND;

7576
    return TLB_copy_all_custdata(&pFDesc->pParamDesc[indexParam].custdata_list, pCustData);
7577 7578 7579 7580 7581 7582 7583
}

/* ITypeInfo2::GetAllVarCustData
 *
 * Gets all custom data items for the specified Variable
 *
 */
7584
static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
7585 7586
    UINT index, CUSTDATA *pCustData)
{
7587
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7588
    TLBVarDesc * pVDesc = &This->vardescs[index];
7589 7590

    TRACE("%p %u %p\n", This, index, pCustData);
7591 7592 7593 7594

    if(index >= This->TypeAttr.cVars)
        return TYPE_E_ELEMENTNOTFOUND;

7595
    return TLB_copy_all_custdata(&pVDesc->custdata_list, pCustData);
7596 7597 7598 7599 7600 7601 7602
}

/* ITypeInfo2::GetAllImplCustData
 *
 * Gets all custom data items for the specified implementation type
 *
 */
7603 7604 7605 7606
static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
	ITypeInfo2 * iface,
	UINT index,
	CUSTDATA *pCustData)
7607
{
7608
    ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
7609 7610
    TLBImplType *pRDesc = &This->impltypes[index];

7611
    TRACE("%p %u %p\n", This, index, pCustData);
7612 7613 7614 7615

    if(index >= This->TypeAttr.cImplTypes)
        return TYPE_E_ELEMENTNOTFOUND;

7616
    return TLB_copy_all_custdata(&pRDesc->custdata_list, pCustData);
7617 7618
}

7619
static const ITypeInfo2Vtbl tinfvt =
7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661
{

    ITypeInfo_fnQueryInterface,
    ITypeInfo_fnAddRef,
    ITypeInfo_fnRelease,

    ITypeInfo_fnGetTypeAttr,
    ITypeInfo_fnGetTypeComp,
    ITypeInfo_fnGetFuncDesc,
    ITypeInfo_fnGetVarDesc,
    ITypeInfo_fnGetNames,
    ITypeInfo_fnGetRefTypeOfImplType,
    ITypeInfo_fnGetImplTypeFlags,
    ITypeInfo_fnGetIDsOfNames,
    ITypeInfo_fnInvoke,
    ITypeInfo_fnGetDocumentation,
    ITypeInfo_fnGetDllEntry,
    ITypeInfo_fnGetRefTypeInfo,
    ITypeInfo_fnAddressOfMember,
    ITypeInfo_fnCreateInstance,
    ITypeInfo_fnGetMops,
    ITypeInfo_fnGetContainingTypeLib,
    ITypeInfo_fnReleaseTypeAttr,
    ITypeInfo_fnReleaseFuncDesc,
    ITypeInfo_fnReleaseVarDesc,

    ITypeInfo2_fnGetTypeKind,
    ITypeInfo2_fnGetTypeFlags,
    ITypeInfo2_fnGetFuncIndexOfMemId,
    ITypeInfo2_fnGetVarIndexOfMemId,
    ITypeInfo2_fnGetCustData,
    ITypeInfo2_fnGetFuncCustData,
    ITypeInfo2_fnGetParamCustData,
    ITypeInfo2_fnGetVarCustData,
    ITypeInfo2_fnGetImplTypeCustData,
    ITypeInfo2_fnGetDocumentation2,
    ITypeInfo2_fnGetAllCustData,
    ITypeInfo2_fnGetAllFuncCustData,
    ITypeInfo2_fnGetAllParamCustData,
    ITypeInfo2_fnGetAllVarCustData,
    ITypeInfo2_fnGetAllImplTypeCustData,
};
7662

7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681
/******************************************************************************
 * CreateDispTypeInfo [OLEAUT32.31]
 *
 * Build type information for an object so it can be called through an
 * IDispatch interface.
 *
 * RETURNS
 *  Success: S_OK. pptinfo contains the created ITypeInfo object.
 *  Failure: E_INVALIDARG, if one or more arguments is invalid.
 *
 * NOTES
 *  This call allows an objects methods to be accessed through IDispatch, by
 *  building an ITypeInfo object that IDispatch can use to call through.
 */
HRESULT WINAPI CreateDispTypeInfo(
	INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */
	LCID lcid, /* [I] Locale Id */
	ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */
{
7682 7683
    ITypeInfoImpl *pTIClass, *pTIIface;
    ITypeLibImpl *pTypeLibImpl;
7684
    unsigned int param, func;
7685
    TLBFuncDesc *pFuncDesc;
7686
    TLBRefType *ref;
7687

7688
    TRACE("\n");
7689 7690 7691
    pTypeLibImpl = TypeLibImpl_Constructor();
    if (!pTypeLibImpl) return E_FAIL;

7692 7693 7694 7695
    pTypeLibImpl->TypeInfoCount = 2;
    pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));

    pTIIface = pTypeLibImpl->typeinfos[0] = ITypeInfoImpl_Constructor();
7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712
    pTIIface->pTypeLib = pTypeLibImpl;
    pTIIface->index = 0;
    pTIIface->Name = NULL;
    pTIIface->dwHelpContext = -1;
    memset(&pTIIface->TypeAttr.guid, 0, sizeof(GUID));
    pTIIface->TypeAttr.lcid = lcid;
    pTIIface->TypeAttr.typekind = TKIND_INTERFACE;
    pTIIface->TypeAttr.wMajorVerNum = 0;
    pTIIface->TypeAttr.wMinorVerNum = 0;
    pTIIface->TypeAttr.cbAlignment = 2;
    pTIIface->TypeAttr.cbSizeInstance = -1;
    pTIIface->TypeAttr.cbSizeVft = -1;
    pTIIface->TypeAttr.cFuncs = 0;
    pTIIface->TypeAttr.cImplTypes = 0;
    pTIIface->TypeAttr.cVars = 0;
    pTIIface->TypeAttr.wTypeFlags = 0;

7713
    pTIIface->funcdescs = TLBFuncDesc_Constructor(pidata->cMembers);
7714
    pFuncDesc = pTIIface->funcdescs;
7715 7716
    for(func = 0; func < pidata->cMembers; func++) {
        METHODDATA *md = pidata->pmethdata + func;
7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732
        pFuncDesc->Name = SysAllocString(md->szName);
        pFuncDesc->funcdesc.memid = md->dispid;
        pFuncDesc->funcdesc.lprgscode = NULL;
        pFuncDesc->funcdesc.funckind = FUNC_VIRTUAL;
        pFuncDesc->funcdesc.invkind = md->wFlags;
        pFuncDesc->funcdesc.callconv = md->cc;
        pFuncDesc->funcdesc.cParams = md->cArgs;
        pFuncDesc->funcdesc.cParamsOpt = 0;
        pFuncDesc->funcdesc.oVft = md->iMeth * sizeof(void *);
        pFuncDesc->funcdesc.cScodes = 0;
        pFuncDesc->funcdesc.wFuncFlags = 0;
        pFuncDesc->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn;
        pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.wParamFlags = PARAMFLAG_NONE;
        pFuncDesc->funcdesc.elemdescFunc.u.paramdesc.pparamdescex = NULL;
        pFuncDesc->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                                                              md->cArgs * sizeof(ELEMDESC));
7733
        pFuncDesc->pParamDesc = TLBParDesc_Constructor(md->cArgs);
7734
        for(param = 0; param < md->cArgs; param++) {
7735 7736
            pFuncDesc->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
            pFuncDesc->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName);
7737
        }
7738 7739 7740 7741
        pFuncDesc->helpcontext = 0;
        pFuncDesc->HelpStringContext = 0;
        pFuncDesc->HelpString = NULL;
        pFuncDesc->Entry = NULL;
7742
        list_init(&pFuncDesc->custdata_list);
7743
        pTIIface->TypeAttr.cFuncs++;
7744
        ++pFuncDesc;
7745 7746
    }

7747 7748
    dump_TypeInfo(pTIIface);

7749
    pTIClass = pTypeLibImpl->typeinfos[1] = ITypeInfoImpl_Constructor();
7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766
    pTIClass->pTypeLib = pTypeLibImpl;
    pTIClass->index = 1;
    pTIClass->Name = NULL;
    pTIClass->dwHelpContext = -1;
    memset(&pTIClass->TypeAttr.guid, 0, sizeof(GUID));
    pTIClass->TypeAttr.lcid = lcid;
    pTIClass->TypeAttr.typekind = TKIND_COCLASS;
    pTIClass->TypeAttr.wMajorVerNum = 0;
    pTIClass->TypeAttr.wMinorVerNum = 0;
    pTIClass->TypeAttr.cbAlignment = 2;
    pTIClass->TypeAttr.cbSizeInstance = -1;
    pTIClass->TypeAttr.cbSizeVft = -1;
    pTIClass->TypeAttr.cFuncs = 0;
    pTIClass->TypeAttr.cImplTypes = 1;
    pTIClass->TypeAttr.cVars = 0;
    pTIClass->TypeAttr.wTypeFlags = 0;

7767
    pTIClass->impltypes = TLBImplType_Constructor(1);
7768

7769
    ref = heap_alloc_zero(sizeof(*ref));
7770 7771
    ref->pImpTLInfo = TLB_REF_INTERNAL;
    list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
7772

7773 7774
    dump_TypeInfo(pTIClass);

7775
    *pptinfo = (ITypeInfo*)pTIClass;
7776 7777 7778 7779

    ITypeInfo_AddRef(*pptinfo);
    ITypeLib_Release((ITypeLib *)&pTypeLibImpl->lpVtbl);

7780 7781 7782 7783
    return S_OK;

}

7784 7785
static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
{
7786
    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7787 7788 7789 7790 7791 7792

    return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv);
}

static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
{
7793
    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7794 7795 7796 7797 7798 7799

    return ITypeInfo_AddRef((ITypeInfo *)This);
}

static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
{
7800
    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7801 7802 7803 7804 7805 7806 7807

    return ITypeInfo_Release((ITypeInfo *)This);
}

static HRESULT WINAPI ITypeComp_fnBind(
    ITypeComp * iface,
    OLECHAR * szName,
7808 7809
    ULONG lHash,
    WORD wFlags,
7810 7811 7812 7813
    ITypeInfo ** ppTInfo,
    DESCKIND * pDescKind,
    BINDPTR * pBindPtr)
{
7814
    ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
7815 7816
    const TLBFuncDesc *pFDesc;
    const TLBVarDesc *pVDesc;
7817
    HRESULT hr = DISP_E_MEMBERNOTFOUND;
7818
    UINT fdc;
7819

7820
    TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
7821

7822 7823 7824 7825
    *pDescKind = DESCKIND_NONE;
    pBindPtr->lpfuncdesc = NULL;
    *ppTInfo = NULL;

7826 7827
    for(fdc = 0; fdc < This->TypeAttr.cFuncs; ++fdc){
        pFDesc = &This->funcdescs[fdc];
7828
        if (!strcmpiW(pFDesc->Name, szName)) {
7829
            if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
7830
                break;
7831 7832 7833 7834
            else
                /* name found, but wrong flags */
                hr = TYPE_E_TYPEMISMATCH;
        }
7835
    }
7836

7837
    if (fdc < This->TypeAttr.cFuncs)
7838
    {
7839 7840 7841 7842
        HRESULT hr = TLB_AllocAndInitFuncDesc(
            &pFDesc->funcdesc,
            &pBindPtr->lpfuncdesc,
            This->TypeAttr.typekind == TKIND_DISPATCH);
7843 7844
        if (FAILED(hr))
            return hr;
7845 7846
        *pDescKind = DESCKIND_FUNCDESC;
        *ppTInfo = (ITypeInfo *)&This->lpVtbl;
7847
        ITypeInfo_AddRef(*ppTInfo);
7848 7849
        return S_OK;
    } else {
7850 7851 7852 7853 7854 7855 7856 7857 7858
        pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->TypeAttr.cVars, szName);
        if(pVDesc){
            HRESULT hr = TLB_AllocAndInitVarDesc(&pVDesc->vardesc, &pBindPtr->lpvardesc);
            if (FAILED(hr))
                return hr;
            *pDescKind = DESCKIND_VARDESC;
            *ppTInfo = (ITypeInfo *)&This->lpVtbl;
            ITypeInfo_AddRef(*ppTInfo);
            return S_OK;
7859 7860
        }
    }
7861
    /* FIXME: search each inherited interface, not just the first */
7862
    if (hr == DISP_E_MEMBERNOTFOUND && This->impltypes) {
7863 7864 7865 7866
        /* recursive search */
        ITypeInfo *pTInfo;
        ITypeComp *pTComp;
        HRESULT hr;
7867
        hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypes[0].hRef, &pTInfo);
7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880
        if (SUCCEEDED(hr))
        {
            hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp);
            ITypeInfo_Release(pTInfo);
        }
        if (SUCCEEDED(hr))
        {
            hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
            ITypeComp_Release(pTComp);
            return hr;
        }
        WARN("Could not search inherited interface!\n");
    }
7881 7882
    if (hr == DISP_E_MEMBERNOTFOUND)
        hr = S_OK;
7883
    TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
7884
    return hr;
7885 7886 7887 7888 7889
}

static HRESULT WINAPI ITypeComp_fnBindType(
    ITypeComp * iface,
    OLECHAR * szName,
7890
    ULONG lHash,
7891 7892 7893
    ITypeInfo ** ppTInfo,
    ITypeComp ** ppTComp)
{
7894
    TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907

    /* strange behaviour (does nothing) but like the
     * original */

    if (!ppTInfo || !ppTComp)
        return E_POINTER;

    *ppTInfo = NULL;
    *ppTComp = NULL;

    return S_OK;
}

7908
static const ITypeCompVtbl tcompvt =
7909 7910 7911 7912 7913 7914 7915 7916 7917
{

    ITypeComp_fnQueryInterface,
    ITypeComp_fnAddRef,
    ITypeComp_fnRelease,

    ITypeComp_fnBind,
    ITypeComp_fnBindType
};