11421 lines
352 KiB
C
11421 lines
352 KiB
C
/*
|
|
* TYPELIB
|
|
*
|
|
* Copyright 1997 Marcus Meissner
|
|
* 1999 Rein Klazes
|
|
* 2000 Francois Jacques
|
|
* 2001 Huw D M Davies for CodeWeavers
|
|
* 2004 Alastair Bridgewater
|
|
* 2005 Robert Shearman, for CodeWeavers
|
|
* 2013 Andrew Eikum for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*
|
|
* --------------------------------------------------------------------------------------
|
|
* Known problems (2000, Francois Jacques)
|
|
*
|
|
* - Tested using OLEVIEW (Platform SDK tool) only.
|
|
*
|
|
* - dual interface dispinterfaces. vtable-interface ITypeInfo instances are
|
|
* creating by doing a straight copy of the dispinterface instance and just changing
|
|
* its typekind. Pointed structures aren't copied - only the address of the pointers.
|
|
*
|
|
* - locale stuff is partially implemented but hasn't been tested.
|
|
*
|
|
* - typelib file is still read in its entirety, but it is released now.
|
|
*
|
|
* --------------------------------------------------------------------------------------
|
|
* Known problems left from previous implementation (1999, Rein Klazes) :
|
|
*
|
|
* -. 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
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "wine/port.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#define COBJMACROS
|
|
#define NONAMELESSUNION
|
|
|
|
#include "winerror.h"
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winnls.h"
|
|
#include "winreg.h"
|
|
#include "winuser.h"
|
|
#include "winternl.h"
|
|
#include "lzexpand.h"
|
|
|
|
#include "wine/unicode.h"
|
|
#include "objbase.h"
|
|
#include "typelib.h"
|
|
#include "wine/debug.h"
|
|
#include "variant.h"
|
|
#include "wine/heap.h"
|
|
#include "wine/list.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|
WINE_DECLARE_DEBUG_CHANNEL(typelib);
|
|
|
|
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;
|
|
|
|
static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt);
|
|
static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr);
|
|
static void TLB_FreeVarDesc(VARDESC*);
|
|
|
|
/****************************************************************************
|
|
* 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
|
|
|
|
#define DISPATCH_HREF_OFFSET 0x01000000
|
|
#define DISPATCH_HREF_MASK 0xff000000
|
|
|
|
/****************************************************************************
|
|
* 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
|
|
|
|
/*
|
|
* Find a typelib key which matches a requested maj.min version.
|
|
*/
|
|
static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin )
|
|
{
|
|
static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
|
|
WCHAR buffer[60];
|
|
char key_name[16];
|
|
DWORD len, i;
|
|
INT best_maj = -1, best_min = -1;
|
|
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;
|
|
|
|
if (sscanf(key_name, "%x.%x", &v_maj, &v_min) == 2)
|
|
{
|
|
TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min);
|
|
|
|
if (*wMaj == 0xffff && *wMin == 0xffff)
|
|
{
|
|
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;
|
|
|
|
if (*wMin == v_min)
|
|
{
|
|
best_min = v_min;
|
|
break; /* exact match */
|
|
}
|
|
if (*wMin != 0xffff && v_min > best_min) best_min = v_min;
|
|
}
|
|
}
|
|
len = sizeof(key_name);
|
|
}
|
|
RegCloseKey( hkey );
|
|
|
|
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)
|
|
{
|
|
*wMin = best_min;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* 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};
|
|
static const WCHAR VersionFormatW[] = {'\\','%','x','.','%','x',0};
|
|
|
|
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};
|
|
static const WCHAR win64W[] = {'w','i','n','6','4',0};
|
|
|
|
sprintfW( buffer, LcidFormatW, lcid );
|
|
switch(syskind)
|
|
{
|
|
case SYS_WIN16: strcatW( buffer, win16W ); break;
|
|
case SYS_WIN32: strcatW( buffer, win32W ); break;
|
|
case SYS_WIN64: strcatW( buffer, win64W ); break;
|
|
default:
|
|
TRACE("Typelib is for unsupported syskind %i\n", syskind);
|
|
return NULL;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib);
|
|
|
|
struct tlibredirect_data
|
|
{
|
|
ULONG size;
|
|
DWORD res;
|
|
ULONG name_len;
|
|
ULONG name_offset;
|
|
LANGID langid;
|
|
WORD flags;
|
|
ULONG help_len;
|
|
ULONG help_offset;
|
|
WORD major_version;
|
|
WORD minor_version;
|
|
};
|
|
|
|
/* 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, BSTR *path, BOOL redir )
|
|
{
|
|
HRESULT hr = TYPE_E_LIBNOTREGISTERED;
|
|
LCID myLCID = lcid;
|
|
HKEY hkey;
|
|
WCHAR buffer[60];
|
|
WCHAR Path[MAX_PATH];
|
|
LONG res;
|
|
|
|
TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path);
|
|
|
|
if (redir)
|
|
{
|
|
ACTCTX_SECTION_KEYED_DATA data;
|
|
|
|
data.cbSize = sizeof(data);
|
|
if (FindActCtxSectionGuid( 0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, guid, &data ))
|
|
{
|
|
struct tlibredirect_data *tlib = (struct tlibredirect_data*)data.lpData;
|
|
WCHAR *nameW;
|
|
DWORD len;
|
|
|
|
if ((wMaj != 0xffff || wMin != 0xffff) && (tlib->major_version != wMaj || tlib->minor_version < wMin))
|
|
return TYPE_E_LIBNOTREGISTERED;
|
|
|
|
nameW = (WCHAR*)((BYTE*)data.lpSectionBase + tlib->name_offset);
|
|
len = SearchPathW( NULL, nameW, NULL, ARRAY_SIZE( Path ), Path, NULL );
|
|
if (!len) return TYPE_E_LIBNOTREGISTERED;
|
|
|
|
TRACE_(typelib)("got path from context %s\n", debugstr_w(Path));
|
|
*path = SysAllocString( Path );
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED;
|
|
get_typelib_key( guid, wMaj, wMin, buffer );
|
|
|
|
res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey );
|
|
if (res == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
TRACE_(typelib)("%s not found\n", debugstr_w(buffer));
|
|
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;
|
|
}
|
|
|
|
while (hr != S_OK)
|
|
{
|
|
LONG dwPathLen = sizeof(Path);
|
|
|
|
get_lcid_subkey( myLCID, syskind, buffer );
|
|
|
|
if (RegQueryValueW(hkey, buffer, Path, &dwPathLen))
|
|
{
|
|
if (!lcid)
|
|
break;
|
|
else if (myLCID == lcid)
|
|
{
|
|
/* try with sub-langid */
|
|
myLCID = SUBLANGID(lcid);
|
|
}
|
|
else if ((myLCID == SUBLANGID(lcid)) && myLCID)
|
|
{
|
|
/* try with system langid */
|
|
myLCID = 0;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*path = SysAllocString( Path );
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
RegCloseKey( hkey );
|
|
TRACE_(typelib)("-- 0x%08x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* 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 )
|
|
{
|
|
BOOL redir = TRUE;
|
|
#ifdef _WIN64
|
|
HRESULT hres = query_typelib_path( guid, wMaj, wMin, SYS_WIN64, lcid, path, TRUE );
|
|
if(SUCCEEDED(hres))
|
|
return hres;
|
|
redir = FALSE;
|
|
#endif
|
|
return query_typelib_path( guid, wMaj, wMin, SYS_WIN32, lcid, path, redir );
|
|
}
|
|
|
|
/******************************************************************************
|
|
* CreateTypeLib [OLEAUT32.160] creates a typelib
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK
|
|
* Failure: Status
|
|
*/
|
|
HRESULT WINAPI CreateTypeLib(
|
|
SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib
|
|
) {
|
|
FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib);
|
|
return E_FAIL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* LoadTypeLib [OLEAUT32.161]
|
|
*
|
|
* Loads a type library
|
|
*
|
|
* PARAMS
|
|
* szFile [I] Name of file to load from.
|
|
* pptLib [O] Pointer that receives ITypeLib object on success.
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK
|
|
* Failure: Status
|
|
*
|
|
* SEE
|
|
* LoadTypeLibEx, LoadRegTypeLib, CreateTypeLib.
|
|
*/
|
|
HRESULT WINAPI LoadTypeLib(const OLECHAR *szFile, ITypeLib * *pptLib)
|
|
{
|
|
TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib);
|
|
return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* LoadTypeLibEx [OLEAUT32.183]
|
|
*
|
|
* Loads and optionally registers a type library
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK
|
|
* Failure: Status
|
|
*/
|
|
HRESULT WINAPI LoadTypeLibEx(
|
|
LPCOLESTR szFile, /* [in] Name of file to load from */
|
|
REGKIND regkind, /* [in] Specify kind of registration */
|
|
ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */
|
|
{
|
|
WCHAR szPath[MAX_PATH+1];
|
|
HRESULT res;
|
|
|
|
TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
|
|
|
|
if (!szFile || !pptLib)
|
|
return E_INVALIDARG;
|
|
|
|
*pptLib = NULL;
|
|
|
|
res = TLB_ReadTypeLib(szFile, szPath, MAX_PATH + 1, (ITypeLib2**)pptLib);
|
|
|
|
if (SUCCEEDED(res))
|
|
switch(regkind)
|
|
{
|
|
case REGKIND_DEFAULT:
|
|
/* don't register typelibs supplied with full path. Experimentation confirms the following */
|
|
if (((szFile[0] == '\\') && (szFile[1] == '\\')) ||
|
|
(szFile[0] && (szFile[1] == ':'))) break;
|
|
/* else fall-through */
|
|
|
|
case REGKIND_REGISTER:
|
|
if (FAILED(res = RegisterTypeLib(*pptLib, szPath, NULL)))
|
|
{
|
|
ITypeLib_Release(*pptLib);
|
|
*pptLib = 0;
|
|
}
|
|
break;
|
|
case REGKIND_NONE:
|
|
break;
|
|
}
|
|
|
|
TRACE(" returns %08x\n",res);
|
|
return res;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* LoadRegTypeLib [OLEAUT32.162]
|
|
*
|
|
* 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.
|
|
*/
|
|
HRESULT WINAPI LoadRegTypeLib(
|
|
REFGUID rguid,
|
|
WORD wVerMajor,
|
|
WORD wVerMinor,
|
|
LCID lcid,
|
|
ITypeLib **ppTLib)
|
|
{
|
|
BSTR bstr=NULL;
|
|
HRESULT res;
|
|
|
|
*ppTLib = NULL;
|
|
|
|
res = QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr);
|
|
|
|
if(SUCCEEDED(res))
|
|
{
|
|
res= LoadTypeLib(bstr, ppTLib);
|
|
SysFreeString(bstr);
|
|
|
|
if ((wVerMajor!=0xffff || wVerMinor!=0xffff) && *ppTLib)
|
|
{
|
|
TLIBATTR *attr;
|
|
|
|
res = ITypeLib_GetLibAttr(*ppTLib, &attr);
|
|
if (res == S_OK)
|
|
{
|
|
BOOL mismatch = attr->wMajorVerNum != wVerMajor || attr->wMinorVerNum < wVerMinor;
|
|
ITypeLib_ReleaseTLibAttr(*ppTLib, attr);
|
|
|
|
if (mismatch)
|
|
{
|
|
ITypeLib_Release(*ppTLib);
|
|
*ppTLib = NULL;
|
|
res = TYPE_E_LIBNOTREGISTERED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/* 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};
|
|
|
|
static void TLB_register_interface(TLIBATTR *libattr, LPOLESTR name, TYPEATTR *tattr, DWORD flag)
|
|
{
|
|
WCHAR keyName[60];
|
|
HKEY key, subKey;
|
|
|
|
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};
|
|
|
|
get_interface_key( &tattr->guid, keyName );
|
|
if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
|
|
KEY_WRITE | flag, NULL, &key, NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (name)
|
|
RegSetValueExW(key, NULL, 0, REG_SZ,
|
|
(BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR));
|
|
|
|
if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0,
|
|
KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
|
|
RegSetValueExW(subKey, NULL, 0, REG_SZ,
|
|
(const BYTE *)PSOA, sizeof PSOA);
|
|
RegCloseKey(subKey);
|
|
}
|
|
|
|
if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0,
|
|
KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS) {
|
|
RegSetValueExW(subKey, NULL, 0, REG_SZ,
|
|
(const BYTE *)PSOA, sizeof PSOA);
|
|
RegCloseKey(subKey);
|
|
}
|
|
|
|
if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0,
|
|
KEY_WRITE | flag, NULL, &subKey, NULL) == ERROR_SUCCESS)
|
|
{
|
|
WCHAR buffer[40];
|
|
static const WCHAR fmtver[] = {'%','x','.','%','x',0 };
|
|
static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
|
|
|
|
StringFromGUID2(&libattr->guid, buffer, 40);
|
|
RegSetValueExW(subKey, NULL, 0, REG_SZ,
|
|
(BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
|
|
sprintfW(buffer, fmtver, libattr->wMajorVerNum, libattr->wMinorVerNum);
|
|
RegSetValueExW(subKey, VersionW, 0, REG_SZ,
|
|
(BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR));
|
|
RegCloseKey(subKey);
|
|
}
|
|
|
|
RegCloseKey(key);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* RegisterTypeLib [OLEAUT32.163]
|
|
* Adds information about a type library to the System Registry
|
|
* NOTES
|
|
* Docs: ITypeLib FAR * ptlib
|
|
* Docs: OLECHAR FAR* szFullPath
|
|
* Docs: OLECHAR FAR* szHelpDir
|
|
*
|
|
* RETURNS
|
|
* Success: S_OK
|
|
* Failure: Status
|
|
*/
|
|
HRESULT WINAPI RegisterTypeLib(
|
|
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*/
|
|
{
|
|
HRESULT res;
|
|
TLIBATTR *attr;
|
|
WCHAR keyName[60];
|
|
WCHAR tmp[16];
|
|
HKEY key, subKey;
|
|
UINT types, tidx;
|
|
TYPEKIND kind;
|
|
DWORD disposition;
|
|
|
|
if (ptlib == NULL || szFullPath == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
if (FAILED(ITypeLib_GetLibAttr(ptlib, &attr)))
|
|
return E_FAIL;
|
|
|
|
#ifndef _WIN64
|
|
if (attr->syskind == SYS_WIN64) return TYPE_E_BADMODULEKIND;
|
|
#endif
|
|
|
|
get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName );
|
|
|
|
res = S_OK;
|
|
if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0,
|
|
KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
|
|
{
|
|
LPOLESTR doc;
|
|
|
|
/* Set the human-readable name of the typelib */
|
|
if (FAILED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL)))
|
|
res = E_FAIL;
|
|
else if (doc)
|
|
{
|
|
if (RegSetValueExW(key, NULL, 0, REG_SZ,
|
|
(BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
|
|
res = E_FAIL;
|
|
|
|
SysFreeString(doc);
|
|
}
|
|
|
|
/* Make up the name of the typelib path subkey */
|
|
if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL;
|
|
|
|
/* Create the typelib path subkey */
|
|
if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0,
|
|
KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (RegSetValueExW(subKey, NULL, 0, REG_SZ,
|
|
(BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS)
|
|
res = E_FAIL;
|
|
|
|
RegCloseKey(subKey);
|
|
}
|
|
else
|
|
res = E_FAIL;
|
|
|
|
/* Create the flags subkey */
|
|
if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0,
|
|
KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS)
|
|
{
|
|
/* FIXME: is %u correct? */
|
|
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)
|
|
res = E_FAIL;
|
|
|
|
RegCloseKey(subKey);
|
|
}
|
|
else
|
|
res = E_FAIL;
|
|
|
|
/* create the helpdir subkey */
|
|
if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0,
|
|
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;
|
|
}
|
|
|
|
RegCloseKey(key);
|
|
}
|
|
else
|
|
res = E_FAIL;
|
|
|
|
/* 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;
|
|
|
|
ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL);
|
|
|
|
switch (kind) {
|
|
case TKIND_INTERFACE:
|
|
TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name));
|
|
ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
|
|
break;
|
|
|
|
case TKIND_DISPATCH:
|
|
TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name));
|
|
ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo);
|
|
break;
|
|
|
|
default:
|
|
TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name));
|
|
break;
|
|
}
|
|
|
|
if (tinfo) {
|
|
TYPEATTR *tattr = NULL;
|
|
ITypeInfo_GetTypeAttr(tinfo, &tattr);
|
|
|
|
if (tattr) {
|
|
TRACE_(typelib)("guid=%s, flags=%04x (",
|
|
debugstr_guid(&tattr->guid),
|
|
tattr->wTypeFlags);
|
|
|
|
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");
|
|
}
|
|
|
|
/* Register all dispinterfaces (which includes dual interfaces) and
|
|
oleautomation interfaces */
|
|
if ((kind == TKIND_INTERFACE && (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
|
|
kind == TKIND_DISPATCH)
|
|
{
|
|
BOOL is_wow64;
|
|
DWORD opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
|
|
|
|
/* register interface<->typelib coupling */
|
|
TLB_register_interface(attr, name, tattr, 0);
|
|
|
|
/* register TLBs into the opposite registry view, too */
|
|
if(opposite == KEY_WOW64_32KEY ||
|
|
(IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64))
|
|
TLB_register_interface(attr, name, tattr, opposite);
|
|
}
|
|
|
|
ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
|
|
}
|
|
|
|
ITypeInfo_Release(tinfo);
|
|
}
|
|
|
|
SysFreeString(name);
|
|
}
|
|
}
|
|
|
|
ITypeLib_ReleaseTLibAttr(ptlib, attr);
|
|
|
|
return res;
|
|
}
|
|
|
|
static void TLB_unregister_interface(GUID *guid, REGSAM flag)
|
|
{
|
|
WCHAR subKeyName[50];
|
|
HKEY subKey;
|
|
|
|
/* the path to the type */
|
|
get_interface_key( guid, subKeyName );
|
|
|
|
/* Delete its bits */
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE | flag, &subKey) != ERROR_SUCCESS)
|
|
return;
|
|
|
|
RegDeleteKeyW(subKey, ProxyStubClsidW);
|
|
RegDeleteKeyW(subKey, ProxyStubClsid32W);
|
|
RegDeleteKeyW(subKey, TypeLibW);
|
|
RegCloseKey(subKey);
|
|
RegDeleteKeyExW(HKEY_CLASSES_ROOT, subKeyName, flag, 0);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* UnRegisterTypeLib [OLEAUT32.186]
|
|
* Removes information about a type library from the System Registry
|
|
* 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)
|
|
{
|
|
BSTR tlibPath = NULL;
|
|
DWORD tmpLength;
|
|
WCHAR keyName[60];
|
|
WCHAR subKeyName[50];
|
|
int result = S_OK;
|
|
DWORD i = 0;
|
|
BOOL deleteOtherStuff;
|
|
HKEY key = NULL;
|
|
TYPEATTR* typeAttr = NULL;
|
|
TYPEKIND kind;
|
|
ITypeInfo* typeInfo = NULL;
|
|
ITypeLib* typeLib = NULL;
|
|
int numTypes;
|
|
|
|
TRACE("(IID: %s)\n",debugstr_guid(libid));
|
|
|
|
/* Create the path to the key */
|
|
get_typelib_key( libid, wVerMajor, wVerMinor, keyName );
|
|
|
|
if (syskind != SYS_WIN16 && syskind != SYS_WIN32 && syskind != SYS_WIN64)
|
|
{
|
|
TRACE("Unsupported syskind %i\n", syskind);
|
|
result = E_INVALIDARG;
|
|
goto end;
|
|
}
|
|
|
|
/* get the path to the typelib on disk */
|
|
if (query_typelib_path(libid, wVerMajor, wVerMinor, syskind, lcid, &tlibPath, FALSE) != S_OK) {
|
|
result = E_INVALIDARG;
|
|
goto end;
|
|
}
|
|
|
|
/* Try and open the key to the type library. */
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != ERROR_SUCCESS) {
|
|
result = E_INVALIDARG;
|
|
goto end;
|
|
}
|
|
|
|
/* Try and load the type library */
|
|
if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib) != S_OK) {
|
|
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;
|
|
}
|
|
|
|
if ((kind == TKIND_INTERFACE && (typeAttr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) ||
|
|
kind == TKIND_DISPATCH)
|
|
{
|
|
BOOL is_wow64;
|
|
REGSAM opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
|
|
|
|
TLB_unregister_interface(&typeAttr->guid, 0);
|
|
|
|
/* unregister TLBs into the opposite registry view, too */
|
|
if(opposite == KEY_WOW64_32KEY ||
|
|
(IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)) {
|
|
TLB_unregister_interface(&typeAttr->guid, opposite);
|
|
}
|
|
}
|
|
|
|
enddeleteloop:
|
|
if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr);
|
|
typeAttr = NULL;
|
|
if (typeInfo) ITypeInfo_Release(typeInfo);
|
|
typeInfo = NULL;
|
|
}
|
|
|
|
/* Now, delete the type library path subkey */
|
|
get_lcid_subkey( lcid, syskind, subKeyName );
|
|
RegDeleteKeyW(key, subKeyName);
|
|
*strrchrW( subKeyName, '\\' ) = 0; /* remove last path component */
|
|
RegDeleteKeyW(key, subKeyName);
|
|
|
|
/* check if there is anything besides the FLAGS/HELPDIR keys.
|
|
If there is, we don't delete them */
|
|
tmpLength = ARRAY_SIZE(subKeyName);
|
|
deleteOtherStuff = TRUE;
|
|
i = 0;
|
|
while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
tmpLength = ARRAY_SIZE(subKeyName);
|
|
|
|
/* if its not FLAGS or HELPDIR, then we must keep the rest of the key */
|
|
if (!strcmpW(subKeyName, FLAGSW)) continue;
|
|
if (!strcmpW(subKeyName, HELPDIRW)) continue;
|
|
deleteOtherStuff = FALSE;
|
|
break;
|
|
}
|
|
|
|
/* only delete the other parts of the key if we're absolutely sure */
|
|
if (deleteOtherStuff) {
|
|
RegDeleteKeyW(key, FLAGSW);
|
|
RegDeleteKeyW(key, HELPDIRW);
|
|
RegCloseKey(key);
|
|
key = NULL;
|
|
|
|
RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
|
|
*strrchrW( keyName, '\\' ) = 0; /* remove last path component */
|
|
RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName);
|
|
}
|
|
|
|
end:
|
|
SysFreeString(tlibPath);
|
|
if (typeLib) ITypeLib_Release(typeLib);
|
|
if (key) RegCloseKey(key);
|
|
return result;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* 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);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* 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);
|
|
}
|
|
|
|
/*======================= ITypeLib implementation =======================*/
|
|
|
|
typedef struct tagTLBGuid {
|
|
GUID guid;
|
|
INT hreftype;
|
|
UINT offset;
|
|
struct list entry;
|
|
} TLBGuid;
|
|
|
|
typedef struct tagTLBCustData
|
|
{
|
|
TLBGuid *guid;
|
|
VARIANT data;
|
|
struct list entry;
|
|
} TLBCustData;
|
|
|
|
/* data structure for import typelibs */
|
|
typedef struct tagTLBImpLib
|
|
{
|
|
int offset; /* offset in the file (MSFT)
|
|
offset in nametable (SLTG)
|
|
just used to identify library while reading
|
|
data from file */
|
|
TLBGuid *guid; /* libid */
|
|
BSTR name; /* name */
|
|
|
|
LCID lcid; /* lcid of imported typelib */
|
|
|
|
WORD wVersionMajor; /* major version number */
|
|
WORD wVersionMinor; /* minor version number */
|
|
|
|
struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or
|
|
NULL if not yet loaded */
|
|
struct list entry;
|
|
} TLBImpLib;
|
|
|
|
typedef struct tagTLBString {
|
|
BSTR str;
|
|
UINT offset;
|
|
struct list entry;
|
|
} TLBString;
|
|
|
|
/* internal ITypeLib data */
|
|
typedef struct tagITypeLibImpl
|
|
{
|
|
ITypeLib2 ITypeLib2_iface;
|
|
ITypeComp ITypeComp_iface;
|
|
ICreateTypeLib2 ICreateTypeLib2_iface;
|
|
LONG ref;
|
|
TLBGuid *guid;
|
|
LCID lcid;
|
|
SYSKIND syskind;
|
|
int ptr_size;
|
|
WORD ver_major;
|
|
WORD ver_minor;
|
|
WORD libflags;
|
|
LCID set_lcid;
|
|
|
|
/* strings can be stored in tlb as multibyte strings BUT they are *always*
|
|
* exported to the application as a UNICODE string.
|
|
*/
|
|
struct list string_list;
|
|
struct list name_list;
|
|
struct list guid_list;
|
|
|
|
const TLBString *Name;
|
|
const TLBString *DocString;
|
|
const TLBString *HelpFile;
|
|
const TLBString *HelpStringDll;
|
|
DWORD dwHelpContext;
|
|
int TypeInfoCount; /* nr of typeinfo's in librarry */
|
|
struct tagITypeInfoImpl **typeinfos;
|
|
struct list custdata_list;
|
|
struct list implib_list;
|
|
int ctTypeDesc; /* number of items in type desc array */
|
|
TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the
|
|
library. Only used while reading MSFT
|
|
typelibs */
|
|
struct list ref_list; /* list of ref types in this typelib */
|
|
HREFTYPE dispatch_href; /* reference to IDispatch, -1 if unused */
|
|
|
|
|
|
/* typelibs are cached, keyed by path and index, so store the linked list info within them */
|
|
struct list entry;
|
|
WCHAR *path;
|
|
INT index;
|
|
} ITypeLibImpl;
|
|
|
|
static const ITypeLib2Vtbl tlbvt;
|
|
static const ITypeCompVtbl tlbtcvt;
|
|
static const ICreateTypeLib2Vtbl CreateTypeLib2Vtbl;
|
|
|
|
static inline ITypeLibImpl *impl_from_ITypeLib2(ITypeLib2 *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, ITypeLibImpl, ITypeLib2_iface);
|
|
}
|
|
|
|
static inline ITypeLibImpl *impl_from_ITypeLib(ITypeLib *iface)
|
|
{
|
|
return impl_from_ITypeLib2((ITypeLib2*)iface);
|
|
}
|
|
|
|
static inline ITypeLibImpl *impl_from_ITypeComp( ITypeComp *iface )
|
|
{
|
|
return CONTAINING_RECORD(iface, ITypeLibImpl, ITypeComp_iface);
|
|
}
|
|
|
|
static inline ITypeLibImpl *impl_from_ICreateTypeLib2( ICreateTypeLib2 *iface )
|
|
{
|
|
return CONTAINING_RECORD(iface, ITypeLibImpl, ICreateTypeLib2_iface);
|
|
}
|
|
|
|
/* ITypeLib methods */
|
|
static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength);
|
|
static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength);
|
|
|
|
/*======================= ITypeInfo implementation =======================*/
|
|
|
|
/* data for referenced types */
|
|
typedef struct tagTLBRefType
|
|
{
|
|
INT index; /* Type index for internal ref or for external ref
|
|
it the format is SLTG. -2 indicates to
|
|
use guid */
|
|
|
|
TYPEKIND tkind;
|
|
TLBGuid *guid; /* guid of the referenced type */
|
|
/* 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 */
|
|
|
|
struct list entry;
|
|
} TLBRefType;
|
|
|
|
#define TLB_REF_USE_GUID -2
|
|
|
|
#define TLB_REF_INTERNAL (void*)-2
|
|
#define TLB_REF_NOT_FOUND (void*)-1
|
|
|
|
/* internal Parameter data */
|
|
typedef struct tagTLBParDesc
|
|
{
|
|
const TLBString *Name;
|
|
struct list custdata_list;
|
|
} TLBParDesc;
|
|
|
|
/* internal Function data */
|
|
typedef struct tagTLBFuncDesc
|
|
{
|
|
FUNCDESC funcdesc; /* lots of info on the function and its attributes. */
|
|
const TLBString *Name; /* the name of this function */
|
|
TLBParDesc *pParamDesc; /* array with param names and custom data */
|
|
int helpcontext;
|
|
int HelpStringContext;
|
|
const TLBString *HelpString;
|
|
const TLBString *Entry; /* if IS_INTRESOURCE true, it's numeric; if -1 it isn't present */
|
|
struct list custdata_list;
|
|
} TLBFuncDesc;
|
|
|
|
/* internal Variable data */
|
|
typedef struct tagTLBVarDesc
|
|
{
|
|
VARDESC vardesc; /* lots of info on the variable and its attributes. */
|
|
VARDESC *vardesc_create; /* additional data needed for storing VARDESC */
|
|
const TLBString *Name; /* the name of this variable */
|
|
int HelpContext;
|
|
int HelpStringContext;
|
|
const TLBString *HelpString;
|
|
struct list custdata_list;
|
|
} TLBVarDesc;
|
|
|
|
/* internal implemented interface data */
|
|
typedef struct tagTLBImplType
|
|
{
|
|
HREFTYPE hRef; /* hRef of interface */
|
|
int implflags; /* IMPLFLAG_*s */
|
|
struct list custdata_list;
|
|
} TLBImplType;
|
|
|
|
/* internal TypeInfo data */
|
|
typedef struct tagITypeInfoImpl
|
|
{
|
|
ITypeInfo2 ITypeInfo2_iface;
|
|
ITypeComp ITypeComp_iface;
|
|
ICreateTypeInfo2 ICreateTypeInfo2_iface;
|
|
LONG ref;
|
|
BOOL not_attached_to_typelib;
|
|
BOOL needs_layout;
|
|
|
|
TLBGuid *guid;
|
|
TYPEATTR typeattr;
|
|
TYPEDESC *tdescAlias;
|
|
|
|
ITypeLibImpl * pTypeLib; /* back pointer to typelib */
|
|
int index; /* index in this typelib; */
|
|
HREFTYPE hreftype; /* hreftype for app object binding */
|
|
/* type libs seem to store the doc strings in ascii
|
|
* so why should we do it in unicode?
|
|
*/
|
|
const TLBString *Name;
|
|
const TLBString *DocString;
|
|
const TLBString *DllName;
|
|
const TLBString *Schema;
|
|
DWORD dwHelpContext;
|
|
DWORD dwHelpStringContext;
|
|
|
|
/* functions */
|
|
TLBFuncDesc *funcdescs;
|
|
|
|
/* variables */
|
|
TLBVarDesc *vardescs;
|
|
|
|
/* Implemented Interfaces */
|
|
TLBImplType *impltypes;
|
|
|
|
struct list *pcustdata_list;
|
|
struct list custdata_list;
|
|
} ITypeInfoImpl;
|
|
|
|
static inline ITypeInfoImpl *info_impl_from_ITypeComp( ITypeComp *iface )
|
|
{
|
|
return CONTAINING_RECORD(iface, ITypeInfoImpl, ITypeComp_iface);
|
|
}
|
|
|
|
static inline ITypeInfoImpl *impl_from_ITypeInfo2( ITypeInfo2 *iface )
|
|
{
|
|
return CONTAINING_RECORD(iface, ITypeInfoImpl, ITypeInfo2_iface);
|
|
}
|
|
|
|
static inline ITypeInfoImpl *impl_from_ITypeInfo( ITypeInfo *iface )
|
|
{
|
|
return impl_from_ITypeInfo2((ITypeInfo2*)iface);
|
|
}
|
|
|
|
static inline ITypeInfoImpl *info_impl_from_ICreateTypeInfo2( ICreateTypeInfo2 *iface )
|
|
{
|
|
return CONTAINING_RECORD(iface, ITypeInfoImpl, ICreateTypeInfo2_iface);
|
|
}
|
|
|
|
static const ITypeInfo2Vtbl tinfvt;
|
|
static const ITypeCompVtbl tcompvt;
|
|
static const ICreateTypeInfo2Vtbl CreateTypeInfo2Vtbl;
|
|
|
|
static ITypeInfoImpl* ITypeInfoImpl_Constructor(void);
|
|
static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This);
|
|
|
|
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 */
|
|
MSFT_SegDir * pTblDir;
|
|
ITypeLibImpl* pLibInfo;
|
|
} TLBContext;
|
|
|
|
|
|
static inline BSTR TLB_get_bstr(const TLBString *str)
|
|
{
|
|
return str != NULL ? str->str : NULL;
|
|
}
|
|
|
|
static inline int TLB_str_memcmp(void *left, const TLBString *str, DWORD len)
|
|
{
|
|
if(!str)
|
|
return 1;
|
|
return memcmp(left, str->str, len);
|
|
}
|
|
|
|
static inline const GUID *TLB_get_guidref(const TLBGuid *guid)
|
|
{
|
|
return guid != NULL ? &guid->guid : NULL;
|
|
}
|
|
|
|
static inline const GUID *TLB_get_guid_null(const TLBGuid *guid)
|
|
{
|
|
return guid != NULL ? &guid->guid : &GUID_NULL;
|
|
}
|
|
|
|
static int get_ptr_size(SYSKIND syskind)
|
|
{
|
|
switch(syskind){
|
|
case SYS_WIN64:
|
|
return 8;
|
|
case SYS_WIN32:
|
|
case SYS_MAC:
|
|
case SYS_WIN16:
|
|
return 4;
|
|
}
|
|
WARN("Unhandled syskind: 0x%x\n", syskind);
|
|
return 4;
|
|
}
|
|
|
|
/*
|
|
debug
|
|
*/
|
|
static void dump_TypeDesc(const TYPEDESC *pTD,char *szVarType) {
|
|
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) {
|
|
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;
|
|
case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break;
|
|
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;
|
|
case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break;
|
|
case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %x",
|
|
pTD->u.hreftype); break;
|
|
case VT_LPSTR: sprintf(szVarType, "VT_LPSTR"); break;
|
|
case VT_LPWSTR: sprintf(szVarType, "VT_LPWSTR"); break;
|
|
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;
|
|
|
|
default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break;
|
|
}
|
|
}
|
|
|
|
static void dump_ELEMDESC(const ELEMDESC *edesc) {
|
|
char buf[200];
|
|
USHORT flags = edesc->u.paramdesc.wParamFlags;
|
|
dump_TypeDesc(&edesc->tdesc,buf);
|
|
MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf);
|
|
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);
|
|
}
|
|
static void dump_FUNCDESC(const FUNCDESC *funcdesc) {
|
|
int i;
|
|
MESSAGE("memid is %08x\n",funcdesc->memid);
|
|
for (i=0;i<funcdesc->cParams;i++) {
|
|
MESSAGE("Param %d:\n",i);
|
|
dump_ELEMDESC(funcdesc->lprgelemdescParam+i);
|
|
}
|
|
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);
|
|
|
|
MESSAGE("\telemdescFunc (return value type):\n");
|
|
dump_ELEMDESC(&funcdesc->elemdescFunc);
|
|
}
|
|
|
|
static const char * const typekind_desc[] =
|
|
{
|
|
"TKIND_ENUM",
|
|
"TKIND_RECORD",
|
|
"TKIND_MODULE",
|
|
"TKIND_INTERFACE",
|
|
"TKIND_DISPATCH",
|
|
"TKIND_COCLASS",
|
|
"TKIND_ALIAS",
|
|
"TKIND_UNION",
|
|
"TKIND_MAX"
|
|
};
|
|
|
|
static void dump_TLBFuncDescOne(const TLBFuncDesc * pfd)
|
|
{
|
|
int i;
|
|
MESSAGE("%s(%u)\n", debugstr_w(TLB_get_bstr(pfd->Name)), pfd->funcdesc.cParams);
|
|
for (i=0;i<pfd->funcdesc.cParams;i++)
|
|
MESSAGE("\tparm%d: %s\n",i,debugstr_w(TLB_get_bstr(pfd->pParamDesc[i].Name)));
|
|
|
|
|
|
dump_FUNCDESC(&(pfd->funcdesc));
|
|
|
|
MESSAGE("\thelpstring: %s\n", debugstr_w(TLB_get_bstr(pfd->HelpString)));
|
|
if(pfd->Entry == NULL)
|
|
MESSAGE("\tentry: (null)\n");
|
|
else if(pfd->Entry == (void*)-1)
|
|
MESSAGE("\tentry: invalid\n");
|
|
else if(IS_INTRESOURCE(pfd->Entry))
|
|
MESSAGE("\tentry: %p\n", pfd->Entry);
|
|
else
|
|
MESSAGE("\tentry: %s\n", debugstr_w(TLB_get_bstr(pfd->Entry)));
|
|
}
|
|
static void dump_TLBFuncDesc(const TLBFuncDesc * pfd, UINT n)
|
|
{
|
|
while (n)
|
|
{
|
|
dump_TLBFuncDescOne(pfd);
|
|
++pfd;
|
|
--n;
|
|
}
|
|
}
|
|
static void dump_TLBVarDesc(const TLBVarDesc * pvd, UINT n)
|
|
{
|
|
while (n)
|
|
{
|
|
TRACE_(typelib)("%s\n", debugstr_w(TLB_get_bstr(pvd->Name)));
|
|
++pvd;
|
|
--n;
|
|
}
|
|
}
|
|
|
|
static void dump_TLBImpLib(const TLBImpLib *import)
|
|
{
|
|
TRACE_(typelib)("%s %s\n", debugstr_guid(TLB_get_guidref(import->guid)),
|
|
debugstr_w(import->name));
|
|
TRACE_(typelib)("v%d.%d lcid=%x offset=%x\n", import->wVersionMajor,
|
|
import->wVersionMinor, import->lcid, import->offset);
|
|
}
|
|
|
|
static void dump_TLBRefType(const ITypeLibImpl *pTL)
|
|
{
|
|
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(TLB_get_guidref(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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dump_TLBImplType(const TLBImplType * impl, UINT n)
|
|
{
|
|
if(!impl)
|
|
return;
|
|
while (n) {
|
|
TRACE_(typelib)("implementing/inheriting interface hRef = %x implflags %x\n",
|
|
impl->hRef, impl->implflags);
|
|
++impl;
|
|
--n;
|
|
}
|
|
}
|
|
|
|
static void dump_DispParms(const DISPPARAMS * pdp)
|
|
{
|
|
unsigned int index;
|
|
|
|
TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs);
|
|
|
|
if (pdp->cNamedArgs && pdp->rgdispidNamedArgs)
|
|
{
|
|
TRACE("named args:\n");
|
|
for (index = 0; index < pdp->cNamedArgs; index++)
|
|
TRACE( "\t0x%x\n", pdp->rgdispidNamedArgs[index] );
|
|
}
|
|
|
|
if (pdp->cArgs && pdp->rgvarg)
|
|
{
|
|
TRACE("args:\n");
|
|
for (index = 0; index < pdp->cArgs; index++)
|
|
TRACE(" [%d] %s\n", index, debugstr_variant(pdp->rgvarg+index));
|
|
}
|
|
}
|
|
|
|
static void dump_TypeInfo(const ITypeInfoImpl * pty)
|
|
{
|
|
TRACE("%p ref=%u\n", pty, pty->ref);
|
|
TRACE("%s %s\n", debugstr_w(TLB_get_bstr(pty->Name)), debugstr_w(TLB_get_bstr(pty->DocString)));
|
|
TRACE("attr:%s\n", debugstr_guid(TLB_get_guidref(pty->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);
|
|
TRACE("wTypeFlags: 0x%04x\n", pty->typeattr.wTypeFlags);
|
|
TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index);
|
|
if (pty->typeattr.typekind == TKIND_MODULE) TRACE("dllname:%s\n", debugstr_w(TLB_get_bstr(pty->DllName)));
|
|
if (TRACE_ON(ole))
|
|
dump_TLBFuncDesc(pty->funcdescs, pty->typeattr.cFuncs);
|
|
dump_TLBVarDesc(pty->vardescs, pty->typeattr.cVars);
|
|
dump_TLBImplType(pty->impltypes, pty->typeattr.cImplTypes);
|
|
}
|
|
|
|
static void dump_VARDESC(const VARDESC *v)
|
|
{
|
|
MESSAGE("memid %d\n",v->memid);
|
|
MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema));
|
|
MESSAGE("oInst %d\n",v->u.oInst);
|
|
dump_ELEMDESC(&(v->elemdescVar));
|
|
MESSAGE("wVarFlags %x\n",v->wVarFlags);
|
|
MESSAGE("varkind %d\n",v->varkind);
|
|
}
|
|
|
|
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}
|
|
};
|
|
|
|
static void TLB_abort(void)
|
|
{
|
|
DebugBreak();
|
|
}
|
|
|
|
/* 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 )
|
|
{
|
|
SIZE_T size = 0;
|
|
|
|
if (alloc_initial_space)
|
|
size += sizeof(TYPEDESC);
|
|
|
|
switch (tdesc->vt)
|
|
{
|
|
case VT_PTR:
|
|
case VT_SAFEARRAY:
|
|
size += TLB_SizeTypeDesc(tdesc->u.lptdesc, TRUE);
|
|
break;
|
|
case VT_CARRAY:
|
|
size += FIELD_OFFSET(ARRAYDESC, rgbounds[tdesc->u.lpadesc->cDims]);
|
|
size += TLB_SizeTypeDesc(&tdesc->u.lpadesc->tdescElem, FALSE);
|
|
break;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
/* deep copy a typedesc into a flat buffer */
|
|
static void *TLB_CopyTypeDesc( TYPEDESC *dest, const TYPEDESC *src, void *buffer )
|
|
{
|
|
if (!dest)
|
|
{
|
|
dest = buffer;
|
|
buffer = (char *)buffer + sizeof(TYPEDESC);
|
|
}
|
|
|
|
*dest = *src;
|
|
|
|
switch (src->vt)
|
|
{
|
|
case VT_PTR:
|
|
case VT_SAFEARRAY:
|
|
dest->u.lptdesc = buffer;
|
|
buffer = TLB_CopyTypeDesc(NULL, src->u.lptdesc, buffer);
|
|
break;
|
|
case VT_CARRAY:
|
|
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;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
/* free custom data allocated by MSFT_CustData */
|
|
static inline void TLB_FreeCustData(struct list *custdata_list)
|
|
{
|
|
TLBCustData *cd, *cdn;
|
|
LIST_FOR_EACH_ENTRY_SAFE(cd, cdn, custdata_list, TLBCustData, entry)
|
|
{
|
|
list_remove(&cd->entry);
|
|
VariantClear(&cd->data);
|
|
heap_free(cd);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 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(TLB_get_bstr(vardescs->Name), name))
|
|
return vardescs;
|
|
++vardescs;
|
|
--n;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static inline TLBCustData *TLB_get_custdata_by_guid(struct list *custdata_list, REFGUID guid)
|
|
{
|
|
TLBCustData *cust_data;
|
|
LIST_FOR_EACH_ENTRY(cust_data, custdata_list, TLBCustData, entry)
|
|
if(IsEqualIID(TLB_get_guid_null(cust_data->guid), guid))
|
|
return cust_data;
|
|
return NULL;
|
|
}
|
|
|
|
static inline ITypeInfoImpl *TLB_get_typeinfo_by_name(ITypeInfoImpl **typeinfos,
|
|
UINT n, const OLECHAR *name)
|
|
{
|
|
while(n){
|
|
if(!lstrcmpiW(TLB_get_bstr((*typeinfos)->Name), name))
|
|
return *typeinfos;
|
|
++typeinfos;
|
|
--n;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void TLBVarDesc_Constructor(TLBVarDesc *var_desc)
|
|
{
|
|
list_init(&var_desc->custdata_list);
|
|
}
|
|
|
|
static TLBVarDesc *TLBVarDesc_Alloc(UINT n)
|
|
{
|
|
TLBVarDesc *ret;
|
|
|
|
ret = heap_alloc_zero(sizeof(TLBVarDesc) * n);
|
|
if(!ret)
|
|
return NULL;
|
|
|
|
while(n){
|
|
TLBVarDesc_Constructor(&ret[n-1]);
|
|
--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 void TLBFuncDesc_Constructor(TLBFuncDesc *func_desc)
|
|
{
|
|
list_init(&func_desc->custdata_list);
|
|
}
|
|
|
|
static TLBFuncDesc *TLBFuncDesc_Alloc(UINT n)
|
|
{
|
|
TLBFuncDesc *ret;
|
|
|
|
ret = heap_alloc_zero(sizeof(TLBFuncDesc) * n);
|
|
if(!ret)
|
|
return NULL;
|
|
|
|
while(n){
|
|
TLBFuncDesc_Constructor(&ret[n-1]);
|
|
--n;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void TLBImplType_Constructor(TLBImplType *impl)
|
|
{
|
|
list_init(&impl->custdata_list);
|
|
}
|
|
|
|
static TLBImplType *TLBImplType_Alloc(UINT n)
|
|
{
|
|
TLBImplType *ret;
|
|
|
|
ret = heap_alloc_zero(sizeof(TLBImplType) * n);
|
|
if(!ret)
|
|
return NULL;
|
|
|
|
while(n){
|
|
TLBImplType_Constructor(&ret[n-1]);
|
|
--n;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static TLBGuid *TLB_append_guid(struct list *guid_list,
|
|
const GUID *new_guid, HREFTYPE hreftype)
|
|
{
|
|
TLBGuid *guid;
|
|
|
|
LIST_FOR_EACH_ENTRY(guid, guid_list, TLBGuid, entry) {
|
|
if (IsEqualGUID(&guid->guid, new_guid))
|
|
return guid;
|
|
}
|
|
|
|
guid = heap_alloc(sizeof(TLBGuid));
|
|
if (!guid)
|
|
return NULL;
|
|
|
|
memcpy(&guid->guid, new_guid, sizeof(GUID));
|
|
guid->hreftype = hreftype;
|
|
|
|
list_add_tail(guid_list, &guid->entry);
|
|
|
|
return guid;
|
|
}
|
|
|
|
static HRESULT TLB_set_custdata(struct list *custdata_list, TLBGuid *tlbguid, VARIANT *var)
|
|
{
|
|
TLBCustData *cust_data;
|
|
|
|
switch(V_VT(var)){
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_UI4:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
case VT_HRESULT:
|
|
case VT_BSTR:
|
|
break;
|
|
default:
|
|
return DISP_E_BADVARTYPE;
|
|
}
|
|
|
|
cust_data = TLB_get_custdata_by_guid(custdata_list, TLB_get_guid_null(tlbguid));
|
|
|
|
if (!cust_data) {
|
|
cust_data = heap_alloc(sizeof(TLBCustData));
|
|
if (!cust_data)
|
|
return E_OUTOFMEMORY;
|
|
|
|
cust_data->guid = tlbguid;
|
|
VariantInit(&cust_data->data);
|
|
|
|
list_add_tail(custdata_list, &cust_data->entry);
|
|
}else
|
|
VariantClear(&cust_data->data);
|
|
|
|
return VariantCopy(&cust_data->data, var);
|
|
}
|
|
|
|
static TLBString *TLB_append_str(struct list *string_list, BSTR new_str)
|
|
{
|
|
TLBString *str;
|
|
|
|
if(!new_str)
|
|
return NULL;
|
|
|
|
LIST_FOR_EACH_ENTRY(str, string_list, TLBString, entry) {
|
|
if (strcmpW(str->str, new_str) == 0)
|
|
return str;
|
|
}
|
|
|
|
str = heap_alloc(sizeof(TLBString));
|
|
if (!str)
|
|
return NULL;
|
|
|
|
str->str = SysAllocString(new_str);
|
|
if (!str->str) {
|
|
heap_free(str);
|
|
return NULL;
|
|
}
|
|
|
|
list_add_tail(string_list, &str->entry);
|
|
|
|
return str;
|
|
}
|
|
|
|
static HRESULT TLB_get_size_from_hreftype(ITypeInfoImpl *info, HREFTYPE href,
|
|
ULONG *size, WORD *align)
|
|
{
|
|
ITypeInfo *other;
|
|
TYPEATTR *attr;
|
|
HRESULT hr;
|
|
|
|
hr = ITypeInfo2_GetRefTypeInfo(&info->ITypeInfo2_iface, href, &other);
|
|
if(FAILED(hr))
|
|
return hr;
|
|
|
|
hr = ITypeInfo_GetTypeAttr(other, &attr);
|
|
if(FAILED(hr)){
|
|
ITypeInfo_Release(other);
|
|
return hr;
|
|
}
|
|
|
|
if(size)
|
|
*size = attr->cbSizeInstance;
|
|
if(align)
|
|
*align = attr->cbAlignment;
|
|
|
|
ITypeInfo_ReleaseTypeAttr(other, attr);
|
|
ITypeInfo_Release(other);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT TLB_size_instance(ITypeInfoImpl *info, SYSKIND sys,
|
|
TYPEDESC *tdesc, ULONG *size, WORD *align)
|
|
{
|
|
ULONG i, sub, ptr_size;
|
|
HRESULT hr;
|
|
|
|
ptr_size = get_ptr_size(sys);
|
|
|
|
switch(tdesc->vt){
|
|
case VT_VOID:
|
|
*size = 0;
|
|
break;
|
|
case VT_I1:
|
|
case VT_UI1:
|
|
*size = 1;
|
|
break;
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
case VT_UI2:
|
|
*size = 2;
|
|
break;
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_ERROR:
|
|
case VT_UI4:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
case VT_HRESULT:
|
|
*size = 4;
|
|
break;
|
|
case VT_R8:
|
|
case VT_I8:
|
|
case VT_UI8:
|
|
*size = 8;
|
|
break;
|
|
case VT_BSTR:
|
|
case VT_DISPATCH:
|
|
case VT_UNKNOWN:
|
|
case VT_PTR:
|
|
case VT_SAFEARRAY:
|
|
case VT_LPSTR:
|
|
case VT_LPWSTR:
|
|
*size = ptr_size;
|
|
break;
|
|
case VT_DATE:
|
|
*size = sizeof(DATE);
|
|
break;
|
|
case VT_VARIANT:
|
|
*size = sizeof(VARIANT);
|
|
#ifdef _WIN64
|
|
if(sys == SYS_WIN32)
|
|
*size -= 8; /* 32-bit VARIANT is 8 bytes smaller than 64-bit VARIANT */
|
|
#endif
|
|
break;
|
|
case VT_DECIMAL:
|
|
*size = sizeof(DECIMAL);
|
|
break;
|
|
case VT_CY:
|
|
*size = sizeof(CY);
|
|
break;
|
|
case VT_CARRAY:
|
|
*size = 0;
|
|
for(i = 0; i < tdesc->u.lpadesc->cDims; ++i)
|
|
*size += tdesc->u.lpadesc->rgbounds[i].cElements;
|
|
hr = TLB_size_instance(info, sys, &tdesc->u.lpadesc->tdescElem, &sub, align);
|
|
if(FAILED(hr))
|
|
return hr;
|
|
*size *= sub;
|
|
return S_OK;
|
|
case VT_USERDEFINED:
|
|
return TLB_get_size_from_hreftype(info, tdesc->u.hreftype, size, align);
|
|
default:
|
|
FIXME("Unsized VT: 0x%x\n", tdesc->vt);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(align){
|
|
if(*size < 4)
|
|
*align = *size;
|
|
else
|
|
*align = 4;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**********************************************************************
|
|
*
|
|
* Functions for reading MSFT typelibs (those created by CreateTypeLib2)
|
|
*/
|
|
|
|
static inline void MSFT_Seek(TLBContext *pcx, LONG where)
|
|
{
|
|
if (where != DO_NOT_SEEK)
|
|
{
|
|
where += pcx->oStart;
|
|
if (where > pcx->length)
|
|
{
|
|
/* FIXME */
|
|
ERR("seek beyond end (%d/%d)\n", where, pcx->length );
|
|
TLB_abort();
|
|
}
|
|
pcx->pos = where;
|
|
}
|
|
}
|
|
|
|
/* read function */
|
|
static DWORD MSFT_Read(void *buffer, DWORD count, TLBContext *pcx, LONG where )
|
|
{
|
|
TRACE_(typelib)("pos=0x%08x len=0x%08x 0x%08x 0x%08x 0x%08x\n",
|
|
pcx->pos, count, pcx->oStart, pcx->length, where);
|
|
|
|
MSFT_Seek(pcx, where);
|
|
if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos;
|
|
memcpy( buffer, (char *)pcx->mapping + pcx->pos, count );
|
|
pcx->pos += count;
|
|
return count;
|
|
}
|
|
|
|
static DWORD MSFT_ReadLEDWords(void *buffer, DWORD count, TLBContext *pcx,
|
|
LONG where )
|
|
{
|
|
DWORD ret;
|
|
|
|
ret = MSFT_Read(buffer, count, pcx, where);
|
|
FromLEDWords(buffer, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static DWORD MSFT_ReadLEWords(void *buffer, DWORD count, TLBContext *pcx,
|
|
LONG where )
|
|
{
|
|
DWORD ret;
|
|
|
|
ret = MSFT_Read(buffer, count, pcx, where);
|
|
FromLEWords(buffer, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static HRESULT MSFT_ReadAllGuids(TLBContext *pcx)
|
|
{
|
|
TLBGuid *guid;
|
|
MSFT_GuidEntry entry;
|
|
int offs = 0;
|
|
|
|
MSFT_Seek(pcx, pcx->pTblDir->pGuidTab.offset);
|
|
while (1) {
|
|
if (offs >= pcx->pTblDir->pGuidTab.length)
|
|
return S_OK;
|
|
|
|
MSFT_ReadLEWords(&entry, sizeof(MSFT_GuidEntry), pcx, DO_NOT_SEEK);
|
|
|
|
guid = heap_alloc(sizeof(TLBGuid));
|
|
|
|
guid->offset = offs;
|
|
guid->guid = entry.guid;
|
|
guid->hreftype = entry.hreftype;
|
|
|
|
list_add_tail(&pcx->pLibInfo->guid_list, &guid->entry);
|
|
|
|
offs += sizeof(MSFT_GuidEntry);
|
|
}
|
|
}
|
|
|
|
static TLBGuid *MSFT_ReadGuid( int offset, TLBContext *pcx)
|
|
{
|
|
TLBGuid *ret;
|
|
|
|
LIST_FOR_EACH_ENTRY(ret, &pcx->pLibInfo->guid_list, TLBGuid, entry){
|
|
if(ret->offset == offset){
|
|
TRACE_(typelib)("%s\n", debugstr_guid(&ret->guid));
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static HRESULT MSFT_ReadAllNames(TLBContext *pcx)
|
|
{
|
|
char *string;
|
|
MSFT_NameIntro intro;
|
|
INT16 len_piece;
|
|
int offs = 0, lengthInChars;
|
|
|
|
MSFT_Seek(pcx, pcx->pTblDir->pNametab.offset);
|
|
while (1) {
|
|
TLBString *tlbstr;
|
|
|
|
if (offs >= pcx->pTblDir->pNametab.length)
|
|
return S_OK;
|
|
|
|
MSFT_ReadLEWords(&intro, sizeof(MSFT_NameIntro), pcx, DO_NOT_SEEK);
|
|
intro.namelen &= 0xFF;
|
|
len_piece = intro.namelen + sizeof(MSFT_NameIntro);
|
|
if(len_piece % 4)
|
|
len_piece = (len_piece + 4) & ~0x3;
|
|
if(len_piece < 8)
|
|
len_piece = 8;
|
|
|
|
string = heap_alloc(len_piece + 1);
|
|
MSFT_Read(string, len_piece - sizeof(MSFT_NameIntro), pcx, DO_NOT_SEEK);
|
|
string[intro.namelen] = '\0';
|
|
|
|
lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
|
|
string, -1, NULL, 0);
|
|
if (!lengthInChars) {
|
|
heap_free(string);
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
tlbstr = heap_alloc(sizeof(TLBString));
|
|
|
|
tlbstr->offset = offs;
|
|
tlbstr->str = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, tlbstr->str, lengthInChars);
|
|
|
|
heap_free(string);
|
|
|
|
list_add_tail(&pcx->pLibInfo->name_list, &tlbstr->entry);
|
|
|
|
offs += len_piece;
|
|
}
|
|
}
|
|
|
|
static TLBString *MSFT_ReadName( TLBContext *pcx, int offset)
|
|
{
|
|
TLBString *tlbstr;
|
|
|
|
LIST_FOR_EACH_ENTRY(tlbstr, &pcx->pLibInfo->name_list, TLBString, entry) {
|
|
if (tlbstr->offset == offset) {
|
|
TRACE_(typelib)("%s\n", debugstr_w(tlbstr->str));
|
|
return tlbstr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static TLBString *MSFT_ReadString( TLBContext *pcx, int offset)
|
|
{
|
|
TLBString *tlbstr;
|
|
|
|
LIST_FOR_EACH_ENTRY(tlbstr, &pcx->pLibInfo->string_list, TLBString, entry) {
|
|
if (tlbstr->offset == offset) {
|
|
TRACE_(typelib)("%s\n", debugstr_w(tlbstr->str));
|
|
return tlbstr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* read a value and fill a VARIANT structure
|
|
*/
|
|
static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx )
|
|
{
|
|
int size;
|
|
|
|
TRACE_(typelib)("\n");
|
|
|
|
if(offset <0) { /* data are packed in here */
|
|
V_VT(pVar) = (offset & 0x7c000000 )>> 26;
|
|
V_I4(pVar) = offset & 0x3ffffff;
|
|
return;
|
|
}
|
|
MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx,
|
|
pcx->pTblDir->pCustData.offset + offset );
|
|
TRACE_(typelib)("Vartype = %x\n", V_VT(pVar));
|
|
switch (V_VT(pVar)){
|
|
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 :
|
|
case VT_ERROR :
|
|
case VT_BOOL :
|
|
case VT_I1 :
|
|
case VT_UI1 :
|
|
case VT_UI2 :
|
|
case VT_UI4 :
|
|
case VT_INT :
|
|
case VT_UINT :
|
|
case VT_VOID : /* FIXME: is this right? */
|
|
case VT_HRESULT :
|
|
size=4; break;
|
|
case VT_R8 :
|
|
case VT_CY :
|
|
case VT_DATE :
|
|
case VT_I8 :
|
|
case VT_UI8 :
|
|
case VT_DECIMAL : /* FIXME: is this right? */
|
|
case VT_FILETIME :
|
|
size=8;break;
|
|
/* pointer types with known behaviour */
|
|
case VT_BSTR :{
|
|
char * ptr;
|
|
MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK );
|
|
if(size == -1){
|
|
V_BSTR(pVar) = NULL;
|
|
}else{
|
|
ptr = heap_alloc_zero(size);
|
|
MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);
|
|
V_BSTR(pVar)=SysAllocStringLen(NULL,size);
|
|
/* FIXME: do we need a AtoW conversion here? */
|
|
V_UNION(pVar, bstrVal[size])='\0';
|
|
while(size--) V_UNION(pVar, bstrVal[size])=ptr[size];
|
|
heap_free(ptr);
|
|
}
|
|
}
|
|
size=-4; break;
|
|
/* FIXME: this will not work AT ALL when the variant contains a pointer */
|
|
case VT_DISPATCH :
|
|
case VT_VARIANT :
|
|
case VT_UNKNOWN :
|
|
case VT_PTR :
|
|
case VT_SAFEARRAY :
|
|
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;
|
|
FIXME("VARTYPE %d is not supported, setting pointer to NULL\n",
|
|
V_VT(pVar));
|
|
}
|
|
|
|
if(size>0) /* (big|small) endian correct? */
|
|
MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK );
|
|
return;
|
|
}
|
|
/*
|
|
* create a linked list with custom data
|
|
*/
|
|
static int MSFT_CustData( TLBContext *pcx, int offset, struct list *custdata_list)
|
|
{
|
|
MSFT_CDGuid entry;
|
|
TLBCustData* pNew;
|
|
int count=0;
|
|
|
|
TRACE_(typelib)("\n");
|
|
|
|
if (pcx->pTblDir->pCDGuids.offset < 0) return 0;
|
|
|
|
while(offset >=0){
|
|
count++;
|
|
pNew=heap_alloc_zero(sizeof(TLBCustData));
|
|
MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset);
|
|
pNew->guid = MSFT_ReadGuid(entry.GuidOffset, pcx);
|
|
MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx);
|
|
list_add_head(custdata_list, &pNew->entry);
|
|
offset = entry.next;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd)
|
|
{
|
|
if(type <0)
|
|
pTd->vt=type & VT_TYPEMASK;
|
|
else
|
|
*pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))];
|
|
|
|
TRACE_(typelib)("vt type = %X\n", pTd->vt);
|
|
}
|
|
|
|
static BOOL TLB_is_propgetput(INVOKEKIND invkind)
|
|
{
|
|
return (invkind == INVOKE_PROPERTYGET ||
|
|
invkind == INVOKE_PROPERTYPUT ||
|
|
invkind == INVOKE_PROPERTYPUTREF);
|
|
}
|
|
|
|
static void
|
|
MSFT_DoFuncs(TLBContext* pcx,
|
|
ITypeInfoImpl* pTI,
|
|
int cFuncs,
|
|
int cVars,
|
|
int offset,
|
|
TLBFuncDesc** pptfd)
|
|
{
|
|
/*
|
|
* member information is stored in a data structure at offset
|
|
* indicated by the memoffset field of the typeinfo structure
|
|
* There are several distinctive parts.
|
|
* The first part starts with a field that holds the total length
|
|
* of this (first) part excluding this field. Then follow the records,
|
|
* for each member there is one record.
|
|
*
|
|
* The first entry is always the length of the record (including this
|
|
* length word).
|
|
* 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)
|
|
* 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.
|
|
*
|
|
* Second follows an array sized nrMEM*sizeof(INT) with a member id
|
|
* for each member;
|
|
*
|
|
* Third is an equal sized array with file offsets to the name entry
|
|
* of each member.
|
|
*
|
|
* The fourth and last (?) part is an array with offsets to the records
|
|
* in the first part of this file segment.
|
|
*/
|
|
|
|
int infolen, nameoffset, reclength, i;
|
|
int recoffset = offset + sizeof(INT);
|
|
|
|
char *recbuf = heap_alloc(0xffff);
|
|
MSFT_FuncRecord *pFuncRec = (MSFT_FuncRecord*)recbuf;
|
|
TLBFuncDesc *ptfd_prev = NULL, *ptfd;
|
|
|
|
TRACE_(typelib)("\n");
|
|
|
|
MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset);
|
|
|
|
*pptfd = TLBFuncDesc_Alloc(cFuncs);
|
|
ptfd = *pptfd;
|
|
for ( i = 0; i < cFuncs ; i++ )
|
|
{
|
|
int optional;
|
|
|
|
/* name, eventually add to a hash table */
|
|
MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
|
|
offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT));
|
|
|
|
/* read the function information record */
|
|
MSFT_ReadLEDWords(&reclength, sizeof(pFuncRec->Info), pcx, recoffset);
|
|
|
|
reclength &= 0xffff;
|
|
|
|
MSFT_ReadLEDWords(&pFuncRec->DataType, reclength - FIELD_OFFSET(MSFT_FuncRecord, DataType), pcx, DO_NOT_SEEK);
|
|
|
|
/* size without argument data */
|
|
optional = reclength - pFuncRec->nrargs*sizeof(MSFT_ParameterInfo);
|
|
if (pFuncRec->FKCCIC & 0x1000)
|
|
optional -= pFuncRec->nrargs * sizeof(INT);
|
|
|
|
if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpContext))
|
|
ptfd->helpcontext = pFuncRec->HelpContext;
|
|
|
|
if (optional > FIELD_OFFSET(MSFT_FuncRecord, oHelpString))
|
|
ptfd->HelpString = MSFT_ReadString(pcx, pFuncRec->oHelpString);
|
|
|
|
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);
|
|
ptfd->Entry = (TLBString*)(DWORD_PTR)LOWORD(pFuncRec->oEntry);
|
|
}
|
|
else
|
|
ptfd->Entry = MSFT_ReadString(pcx, pFuncRec->oEntry);
|
|
}
|
|
else
|
|
ptfd->Entry = (TLBString*)-1;
|
|
|
|
if (optional > FIELD_OFFSET(MSFT_FuncRecord, HelpStringContext))
|
|
ptfd->HelpStringContext = pFuncRec->HelpStringContext;
|
|
|
|
if (optional > FIELD_OFFSET(MSFT_FuncRecord, oCustData) && pFuncRec->FKCCIC & 0x80)
|
|
MSFT_CustData(pcx, pFuncRec->oCustData, &ptfd->custdata_list);
|
|
|
|
/* fill the FuncDesc Structure */
|
|
MSFT_ReadLEDWords( & ptfd->funcdesc.memid, sizeof(INT), pcx,
|
|
offset + infolen + ( i + 1) * sizeof(INT));
|
|
|
|
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) * sizeof(void *) / pTI->pTypeLib->ptr_size;
|
|
ptfd->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags) ;
|
|
|
|
/* nameoffset is sometimes -1 on the second half of a propget/propput
|
|
* pair of functions */
|
|
if ((nameoffset == -1) && (i > 0) &&
|
|
TLB_is_propgetput(ptfd_prev->funcdesc.invkind) &&
|
|
TLB_is_propgetput(ptfd->funcdesc.invkind))
|
|
ptfd->Name = ptfd_prev->Name;
|
|
else
|
|
ptfd->Name = MSFT_ReadName(pcx, nameoffset);
|
|
|
|
MSFT_GetTdesc(pcx,
|
|
pFuncRec->DataType,
|
|
&ptfd->funcdesc.elemdescFunc.tdesc);
|
|
|
|
/* do the parameters/arguments */
|
|
if(pFuncRec->nrargs)
|
|
{
|
|
int j = 0;
|
|
MSFT_ParameterInfo paraminfo;
|
|
|
|
ptfd->funcdesc.lprgelemdescParam =
|
|
heap_alloc_zero(pFuncRec->nrargs * (sizeof(ELEMDESC) + sizeof(PARAMDESCEX)));
|
|
|
|
ptfd->pParamDesc = TLBParDesc_Constructor(pFuncRec->nrargs);
|
|
|
|
MSFT_ReadLEDWords(¶minfo, sizeof(paraminfo), pcx,
|
|
recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo));
|
|
|
|
for ( j = 0 ; j < pFuncRec->nrargs ; j++ )
|
|
{
|
|
ELEMDESC *elemdesc = &ptfd->funcdesc.lprgelemdescParam[j];
|
|
|
|
MSFT_GetTdesc(pcx,
|
|
paraminfo.DataType,
|
|
&elemdesc->tdesc);
|
|
|
|
elemdesc->u.paramdesc.wParamFlags = paraminfo.Flags;
|
|
|
|
/* name */
|
|
if (paraminfo.oName != -1)
|
|
ptfd->pParamDesc[j].Name =
|
|
MSFT_ReadName( pcx, paraminfo.oName );
|
|
TRACE_(typelib)("param[%d] = %s\n", j, debugstr_w(TLB_get_bstr(ptfd->pParamDesc[j].Name)));
|
|
|
|
/* default value */
|
|
if ( (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) &&
|
|
(pFuncRec->FKCCIC & 0x1000) )
|
|
{
|
|
INT* pInt = (INT *)((char *)pFuncRec +
|
|
reclength -
|
|
(pFuncRec->nrargs * 4) * sizeof(INT) );
|
|
|
|
PARAMDESC* pParamDesc = &elemdesc->u.paramdesc;
|
|
|
|
pParamDesc->pparamdescex = (PARAMDESCEX*)(ptfd->funcdesc.lprgelemdescParam+pFuncRec->nrargs)+j;
|
|
pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX);
|
|
|
|
MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue),
|
|
pInt[j], pcx);
|
|
}
|
|
else
|
|
elemdesc->u.paramdesc.pparamdescex = NULL;
|
|
|
|
/* custom info */
|
|
if (optional > (FIELD_OFFSET(MSFT_FuncRecord, oArgCustData) +
|
|
j*sizeof(pFuncRec->oArgCustData[0])) &&
|
|
pFuncRec->FKCCIC & 0x80 )
|
|
{
|
|
MSFT_CustData(pcx,
|
|
pFuncRec->oArgCustData[j],
|
|
&ptfd->pParamDesc[j].custdata_list);
|
|
}
|
|
|
|
/* SEEK value = jump to offset,
|
|
* from there jump to the end of record,
|
|
* go back by (j-1) arguments
|
|
*/
|
|
MSFT_ReadLEDWords( ¶minfo ,
|
|
sizeof(MSFT_ParameterInfo), pcx,
|
|
recoffset + reclength - ((pFuncRec->nrargs - j - 1)
|
|
* sizeof(MSFT_ParameterInfo)));
|
|
}
|
|
}
|
|
|
|
/* scode is not used: archaic win16 stuff FIXME: right? */
|
|
ptfd->funcdesc.cScodes = 0 ;
|
|
ptfd->funcdesc.lprgscode = NULL ;
|
|
|
|
ptfd_prev = ptfd;
|
|
++ptfd;
|
|
recoffset += reclength;
|
|
}
|
|
heap_free(recbuf);
|
|
}
|
|
|
|
static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
|
|
int cVars, int offset, TLBVarDesc ** pptvd)
|
|
{
|
|
int infolen, nameoffset, reclength;
|
|
char recbuf[256];
|
|
MSFT_VarRecord *pVarRec = (MSFT_VarRecord*)recbuf;
|
|
TLBVarDesc *ptvd;
|
|
int i;
|
|
int recoffset;
|
|
|
|
TRACE_(typelib)("\n");
|
|
|
|
ptvd = *pptvd = TLBVarDesc_Alloc(cVars);
|
|
MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset);
|
|
MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen +
|
|
((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT));
|
|
recoffset += offset+sizeof(INT);
|
|
for(i=0;i<cVars;i++, ++ptvd){
|
|
/* name, eventually add to a hash table */
|
|
MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx,
|
|
offset + infolen + (2*cFuncs + cVars + i + 1) * sizeof(INT));
|
|
ptvd->Name=MSFT_ReadName(pcx, nameoffset);
|
|
/* read the variable information record */
|
|
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))
|
|
ptvd->HelpContext = pVarRec->HelpContext;
|
|
|
|
if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpString))
|
|
ptvd->HelpString = MSFT_ReadString(pcx, pVarRec->HelpString);
|
|
|
|
if(reclength > FIELD_OFFSET(MSFT_VarRecord, HelpStringContext))
|
|
ptvd->HelpStringContext = pVarRec->HelpStringContext;
|
|
|
|
/* fill the VarDesc Structure */
|
|
MSFT_ReadLEDWords(&ptvd->vardesc.memid, sizeof(INT), pcx,
|
|
offset + infolen + (cFuncs + i + 1) * sizeof(INT));
|
|
ptvd->vardesc.varkind = pVarRec->VarKind;
|
|
ptvd->vardesc.wVarFlags = pVarRec->Flags;
|
|
MSFT_GetTdesc(pcx, pVarRec->DataType,
|
|
&ptvd->vardesc.elemdescVar.tdesc);
|
|
/* ptvd->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */
|
|
if(pVarRec->VarKind == VAR_CONST ){
|
|
ptvd->vardesc.u.lpvarValue = heap_alloc_zero(sizeof(VARIANT));
|
|
MSFT_ReadValue(ptvd->vardesc.u.lpvarValue,
|
|
pVarRec->OffsValue, pcx);
|
|
} else
|
|
ptvd->vardesc.u.oInst=pVarRec->OffsValue;
|
|
recoffset += reclength;
|
|
}
|
|
}
|
|
|
|
/* process Implemented Interfaces of a com class */
|
|
static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count,
|
|
int offset)
|
|
{
|
|
int i;
|
|
MSFT_RefRecord refrec;
|
|
TLBImplType *pImpl;
|
|
|
|
TRACE_(typelib)("\n");
|
|
|
|
pTI->impltypes = TLBImplType_Alloc(count);
|
|
pImpl = pTI->impltypes;
|
|
for(i=0;i<count;i++){
|
|
if(offset<0) break; /* paranoia */
|
|
MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset);
|
|
pImpl->hRef = refrec.reftype;
|
|
pImpl->implflags=refrec.flags;
|
|
MSFT_CustData(pcx, refrec.oCustData, &pImpl->custdata_list);
|
|
offset=refrec.onext;
|
|
++pImpl;
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
/* when a 32-bit typelib is loaded in 64-bit mode, we need to resize pointers
|
|
* and some structures, and fix the alignment */
|
|
static void TLB_fix_32on64_typeinfo(ITypeInfoImpl *info)
|
|
{
|
|
if(info->typeattr.typekind == TKIND_ALIAS){
|
|
switch(info->tdescAlias->vt){
|
|
case VT_BSTR:
|
|
case VT_DISPATCH:
|
|
case VT_UNKNOWN:
|
|
case VT_PTR:
|
|
case VT_SAFEARRAY:
|
|
case VT_LPSTR:
|
|
case VT_LPWSTR:
|
|
info->typeattr.cbSizeInstance = sizeof(void*);
|
|
info->typeattr.cbAlignment = sizeof(void*);
|
|
break;
|
|
case VT_CARRAY:
|
|
case VT_USERDEFINED:
|
|
TLB_size_instance(info, SYS_WIN64, info->tdescAlias, &info->typeattr.cbSizeInstance, &info->typeattr.cbAlignment);
|
|
break;
|
|
case VT_VARIANT:
|
|
info->typeattr.cbSizeInstance = sizeof(VARIANT);
|
|
info->typeattr.cbAlignment = 8;
|
|
default:
|
|
if(info->typeattr.cbSizeInstance < sizeof(void*))
|
|
info->typeattr.cbAlignment = info->typeattr.cbSizeInstance;
|
|
else
|
|
info->typeattr.cbAlignment = sizeof(void*);
|
|
break;
|
|
}
|
|
}else if(info->typeattr.typekind == TKIND_INTERFACE ||
|
|
info->typeattr.typekind == TKIND_DISPATCH ||
|
|
info->typeattr.typekind == TKIND_COCLASS){
|
|
info->typeattr.cbSizeInstance = sizeof(void*);
|
|
info->typeattr.cbAlignment = sizeof(void*);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* process a typeinfo record
|
|
*/
|
|
static ITypeInfoImpl * MSFT_DoTypeInfo(
|
|
TLBContext *pcx,
|
|
int count,
|
|
ITypeLibImpl * pLibInfo)
|
|
{
|
|
MSFT_TypeInfoBase tiBase;
|
|
ITypeInfoImpl *ptiRet;
|
|
|
|
TRACE_(typelib)("count=%u\n", count);
|
|
|
|
ptiRet = ITypeInfoImpl_Constructor();
|
|
MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx ,
|
|
pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase));
|
|
|
|
/* this is where we are coming from */
|
|
ptiRet->pTypeLib = pLibInfo;
|
|
ptiRet->index=count;
|
|
|
|
ptiRet->guid = MSFT_ReadGuid(tiBase.posguid, pcx);
|
|
ptiRet->typeattr.lcid = pLibInfo->set_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;
|
|
ptiRet->typeattr.cbSizeVft = tiBase.cbSizeVft;
|
|
if (ptiRet->typeattr.typekind == TKIND_ALIAS) {
|
|
TYPEDESC tmp;
|
|
MSFT_GetTdesc(pcx, tiBase.datatype1, &tmp);
|
|
ptiRet->tdescAlias = heap_alloc(TLB_SizeTypeDesc(&tmp, TRUE));
|
|
TLB_CopyTypeDesc(NULL, &tmp, ptiRet->tdescAlias);
|
|
}
|
|
|
|
/* FIXME: */
|
|
/* IDLDESC idldescType; *//* never saw this one != zero */
|
|
|
|
/* name, eventually add to a hash table */
|
|
ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset);
|
|
ptiRet->hreftype = MSFT_ReadHreftype(pcx, tiBase.NameOffset);
|
|
TRACE_(typelib)("reading %s\n", debugstr_w(TLB_get_bstr(ptiRet->Name)));
|
|
/* help info */
|
|
ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs);
|
|
ptiRet->dwHelpStringContext=tiBase.helpstringcontext;
|
|
ptiRet->dwHelpContext=tiBase.helpcontext;
|
|
|
|
if (ptiRet->typeattr.typekind == TKIND_MODULE)
|
|
ptiRet->DllName = MSFT_ReadString(pcx, tiBase.datatype1);
|
|
|
|
/* 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 )
|
|
MSFT_DoFuncs(pcx, ptiRet, ptiRet->typeattr.cFuncs,
|
|
ptiRet->typeattr.cVars,
|
|
tiBase.memoffset, &ptiRet->funcdescs);
|
|
/* variables */
|
|
if(ptiRet->typeattr.cVars >0 )
|
|
MSFT_DoVars(pcx, ptiRet, ptiRet->typeattr.cFuncs,
|
|
ptiRet->typeattr.cVars,
|
|
tiBase.memoffset, &ptiRet->vardescs);
|
|
if(ptiRet->typeattr.cImplTypes >0 ) {
|
|
switch(ptiRet->typeattr.typekind)
|
|
{
|
|
case TKIND_COCLASS:
|
|
MSFT_DoImplTypes(pcx, ptiRet, ptiRet->typeattr.cImplTypes,
|
|
tiBase.datatype1);
|
|
break;
|
|
case TKIND_DISPATCH:
|
|
/* This is not -1 when the interface is a non-base dual interface or
|
|
when a dispinterface wraps an interface, i.e., the idl 'dispinterface x {interface y;};'.
|
|
Note however that GetRefTypeOfImplType(0) always returns a ref to IDispatch and
|
|
not this interface.
|
|
*/
|
|
|
|
if (tiBase.datatype1 != -1)
|
|
{
|
|
ptiRet->impltypes = TLBImplType_Alloc(1);
|
|
ptiRet->impltypes[0].hRef = tiBase.datatype1;
|
|
}
|
|
break;
|
|
default:
|
|
ptiRet->impltypes = TLBImplType_Alloc(1);
|
|
ptiRet->impltypes[0].hRef = tiBase.datatype1;
|
|
break;
|
|
}
|
|
}
|
|
MSFT_CustData(pcx, tiBase.oCustData, ptiRet->pcustdata_list);
|
|
|
|
TRACE_(typelib)("%s guid: %s kind:%s\n",
|
|
debugstr_w(TLB_get_bstr(ptiRet->Name)),
|
|
debugstr_guid(TLB_get_guidref(ptiRet->guid)),
|
|
typekind_desc[ptiRet->typeattr.typekind]);
|
|
if (TRACE_ON(typelib))
|
|
dump_TypeInfo(ptiRet);
|
|
|
|
return ptiRet;
|
|
}
|
|
|
|
static HRESULT MSFT_ReadAllStrings(TLBContext *pcx)
|
|
{
|
|
char *string;
|
|
INT16 len_str, len_piece;
|
|
int offs = 0, lengthInChars;
|
|
|
|
MSFT_Seek(pcx, pcx->pTblDir->pStringtab.offset);
|
|
while (1) {
|
|
TLBString *tlbstr;
|
|
|
|
if (offs >= pcx->pTblDir->pStringtab.length)
|
|
return S_OK;
|
|
|
|
MSFT_ReadLEWords(&len_str, sizeof(INT16), pcx, DO_NOT_SEEK);
|
|
len_piece = len_str + sizeof(INT16);
|
|
if(len_piece % 4)
|
|
len_piece = (len_piece + 4) & ~0x3;
|
|
if(len_piece < 8)
|
|
len_piece = 8;
|
|
|
|
string = heap_alloc(len_piece + 1);
|
|
MSFT_Read(string, len_piece - sizeof(INT16), pcx, DO_NOT_SEEK);
|
|
string[len_str] = '\0';
|
|
|
|
lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
|
|
string, -1, NULL, 0);
|
|
if (!lengthInChars) {
|
|
heap_free(string);
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
tlbstr = heap_alloc(sizeof(TLBString));
|
|
|
|
tlbstr->offset = offs;
|
|
tlbstr->str = SysAllocStringByteLen(NULL, lengthInChars * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, tlbstr->str, lengthInChars);
|
|
|
|
heap_free(string);
|
|
|
|
list_add_tail(&pcx->pLibInfo->string_list, &tlbstr->entry);
|
|
|
|
offs += len_piece;
|
|
}
|
|
}
|
|
|
|
static HRESULT MSFT_ReadAllRefs(TLBContext *pcx)
|
|
{
|
|
TLBRefType *ref;
|
|
int offs = 0;
|
|
|
|
MSFT_Seek(pcx, pcx->pTblDir->pImpInfo.offset);
|
|
while (offs < pcx->pTblDir->pImpInfo.length) {
|
|
MSFT_ImpInfo impinfo;
|
|
TLBImpLib *pImpLib;
|
|
|
|
MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx, DO_NOT_SEEK);
|
|
|
|
ref = heap_alloc_zero(sizeof(TLBRefType));
|
|
list_add_tail(&pcx->pLibInfo->ref_list, &ref->entry);
|
|
|
|
LIST_FOR_EACH_ENTRY(pImpLib, &pcx->pLibInfo->implib_list, TLBImpLib, entry)
|
|
if(pImpLib->offset==impinfo.oImpFile)
|
|
break;
|
|
|
|
if(&pImpLib->entry != &pcx->pLibInfo->implib_list){
|
|
ref->reference = offs;
|
|
ref->pImpTLInfo = pImpLib;
|
|
if(impinfo.flags & MSFT_IMPINFO_OFFSET_IS_GUID) {
|
|
ref->guid = MSFT_ReadGuid(impinfo.oGuid, pcx);
|
|
TRACE("importing by guid %s\n", debugstr_guid(TLB_get_guidref(ref->guid)));
|
|
ref->index = TLB_REF_USE_GUID;
|
|
} else
|
|
ref->index = impinfo.oGuid;
|
|
}else{
|
|
ERR("Cannot find a reference\n");
|
|
ref->reference = -1;
|
|
ref->pImpTLInfo = TLB_REF_NOT_FOUND;
|
|
}
|
|
|
|
offs += sizeof(impinfo);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* 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.
|
|
*/
|
|
static struct list tlb_cache = LIST_INIT(tlb_cache);
|
|
static CRITICAL_SECTION cache_section;
|
|
static CRITICAL_SECTION_DEBUG cache_section_debug =
|
|
{
|
|
0, 0, &cache_section,
|
|
{ &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
|
|
0, 0, { (DWORD_PTR)(__FILE__ ": typelib loader cache") }
|
|
};
|
|
static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
|
|
|
|
|
|
typedef struct TLB_PEFile
|
|
{
|
|
IUnknown IUnknown_iface;
|
|
LONG refs;
|
|
HMODULE dll;
|
|
HRSRC typelib_resource;
|
|
HGLOBAL typelib_global;
|
|
LPVOID typelib_base;
|
|
} TLB_PEFile;
|
|
|
|
static inline TLB_PEFile *pefile_impl_from_IUnknown(IUnknown *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, TLB_PEFile, IUnknown_iface);
|
|
}
|
|
|
|
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 = pefile_impl_from_IUnknown(iface);
|
|
return InterlockedIncrement(&This->refs);
|
|
}
|
|
|
|
static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface)
|
|
{
|
|
TLB_PEFile *This = pefile_impl_from_IUnknown(iface);
|
|
ULONG refs = InterlockedDecrement(&This->refs);
|
|
if (!refs)
|
|
{
|
|
if (This->typelib_global)
|
|
FreeResource(This->typelib_global);
|
|
if (This->dll)
|
|
FreeLibrary(This->dll);
|
|
heap_free(This);
|
|
}
|
|
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;
|
|
HRESULT hr = TYPE_E_CANTLOADLIBRARY;
|
|
|
|
This = heap_alloc(sizeof(TLB_PEFile));
|
|
if (!This)
|
|
return E_OUTOFMEMORY;
|
|
|
|
This->IUnknown_iface.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 = &This->IUnknown_iface;
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE("No TYPELIB resource found\n");
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
TLB_PEFile_Release(&This->IUnknown_iface);
|
|
return hr;
|
|
}
|
|
|
|
typedef struct TLB_NEFile
|
|
{
|
|
IUnknown IUnknown_iface;
|
|
LONG refs;
|
|
LPVOID typelib_base;
|
|
} TLB_NEFile;
|
|
|
|
static inline TLB_NEFile *nefile_impl_from_IUnknown(IUnknown *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, TLB_NEFile, IUnknown_iface);
|
|
}
|
|
|
|
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 = nefile_impl_from_IUnknown(iface);
|
|
return InterlockedIncrement(&This->refs);
|
|
}
|
|
|
|
static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
|
|
{
|
|
TLB_NEFile *This = nefile_impl_from_IUnknown(iface);
|
|
ULONG refs = InterlockedDecrement(&This->refs);
|
|
if (!refs)
|
|
{
|
|
heap_free(This->typelib_base);
|
|
heap_free(This);
|
|
}
|
|
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 FALSE;
|
|
|
|
resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
|
|
if ( !resTabSize )
|
|
{
|
|
TRACE("No resources in NE dll\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
/* Read in resource table */
|
|
resTab = heap_alloc( resTabSize );
|
|
if ( !resTab ) return FALSE;
|
|
|
|
LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
|
|
if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
|
|
{
|
|
heap_free( resTab );
|
|
return FALSE;
|
|
}
|
|
|
|
/* Find resource */
|
|
typeInfo = (NE_TYPEINFO *)(resTab + 2);
|
|
|
|
if (!IS_INTRESOURCE(typeid)) /* named type */
|
|
{
|
|
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 );
|
|
heap_free( resTab );
|
|
return FALSE;
|
|
|
|
found_type:
|
|
nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
|
|
|
|
if (!IS_INTRESOURCE(resid)) /* named resource */
|
|
{
|
|
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 );
|
|
heap_free( resTab );
|
|
return FALSE;
|
|
|
|
found_name:
|
|
/* Return resource data */
|
|
if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
|
|
if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
|
|
|
|
heap_free( resTab );
|
|
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;
|
|
TLB_NEFile *This;
|
|
|
|
This = heap_alloc(sizeof(TLB_NEFile));
|
|
if (!This) return E_OUTOFMEMORY;
|
|
|
|
This->IUnknown_iface.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 ) )
|
|
{
|
|
This->typelib_base = heap_alloc(reslen);
|
|
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 = &This->IUnknown_iface;
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( lzfd >= 0) LZClose( lzfd );
|
|
TLB_NEFile_Release(&This->IUnknown_iface);
|
|
return hr;
|
|
}
|
|
|
|
typedef struct TLB_Mapping
|
|
{
|
|
IUnknown IUnknown_iface;
|
|
LONG refs;
|
|
HANDLE file;
|
|
HANDLE mapping;
|
|
LPVOID typelib_base;
|
|
} TLB_Mapping;
|
|
|
|
static inline TLB_Mapping *mapping_impl_from_IUnknown(IUnknown *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, TLB_Mapping, IUnknown_iface);
|
|
}
|
|
|
|
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 = mapping_impl_from_IUnknown(iface);
|
|
return InterlockedIncrement(&This->refs);
|
|
}
|
|
|
|
static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface)
|
|
{
|
|
TLB_Mapping *This = mapping_impl_from_IUnknown(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);
|
|
heap_free(This);
|
|
}
|
|
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;
|
|
|
|
This = heap_alloc(sizeof(TLB_Mapping));
|
|
if (!This)
|
|
return E_OUTOFMEMORY;
|
|
|
|
This->IUnknown_iface.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 = &This->IUnknown_iface;
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
IUnknown_Release(&This->IUnknown_iface);
|
|
return TYPE_E_CANTLOADLIBRARY;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* TLB_ReadTypeLib
|
|
*
|
|
* find the type of the typelib file and map the typelib resource into
|
|
* the memory
|
|
*/
|
|
|
|
#define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
|
|
static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib)
|
|
{
|
|
ITypeLibImpl *entry;
|
|
HRESULT ret;
|
|
INT index = 1;
|
|
LPWSTR index_str, file = (LPWSTR)pszFileName;
|
|
LPVOID pBase = NULL;
|
|
DWORD dwTLBLength = 0;
|
|
IUnknown *pFile = NULL;
|
|
HANDLE h;
|
|
|
|
*ppTypeLib = NULL;
|
|
|
|
index_str = strrchrW(pszFileName, '\\');
|
|
if(index_str && *++index_str != '\0')
|
|
{
|
|
LPWSTR end_ptr;
|
|
LONG idx = strtolW(index_str, &end_ptr, 10);
|
|
if(*end_ptr == '\0')
|
|
{
|
|
int str_len = index_str - pszFileName - 1;
|
|
index = idx;
|
|
file = heap_alloc((str_len + 1) * sizeof(WCHAR));
|
|
memcpy(file, pszFileName, str_len * sizeof(WCHAR));
|
|
file[str_len] = 0;
|
|
}
|
|
}
|
|
|
|
if(!SearchPathW(NULL, file, NULL, cchPath, pszPath, NULL))
|
|
{
|
|
if(strchrW(file, '\\'))
|
|
{
|
|
lstrcpyW(pszPath, file);
|
|
}
|
|
else
|
|
{
|
|
int len = GetSystemDirectoryW(pszPath, cchPath);
|
|
pszPath[len] = '\\';
|
|
memcpy(pszPath + len + 1, file, (strlenW(file) + 1) * sizeof(WCHAR));
|
|
}
|
|
}
|
|
|
|
if(file != pszFileName) heap_free(file);
|
|
|
|
h = CreateFileW(pszPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if(h != INVALID_HANDLE_VALUE){
|
|
FILE_NAME_INFORMATION size_info;
|
|
BOOL br;
|
|
|
|
/* GetFileInformationByHandleEx returns the path of the file without
|
|
* WOW64 redirection */
|
|
br = GetFileInformationByHandleEx(h, FileNameInfo, &size_info, sizeof(size_info));
|
|
if(br || GetLastError() == ERROR_MORE_DATA){
|
|
FILE_NAME_INFORMATION *info;
|
|
DWORD size = sizeof(*info) + size_info.FileNameLength + sizeof(WCHAR);
|
|
|
|
info = HeapAlloc(GetProcessHeap(), 0, size);
|
|
|
|
br = GetFileInformationByHandleEx(h, FileNameInfo, info, size);
|
|
if(br){
|
|
info->FileName[info->FileNameLength / sizeof(WCHAR)] = 0;
|
|
lstrcpynW(pszPath + 2, info->FileName, cchPath - 2);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, info);
|
|
}
|
|
|
|
CloseHandle(h);
|
|
}
|
|
|
|
TRACE_(typelib)("File %s index %d\n", debugstr_w(pszPath), index);
|
|
|
|
/* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
|
|
EnterCriticalSection(&cache_section);
|
|
LIST_FOR_EACH_ENTRY(entry, &tlb_cache, ITypeLibImpl, entry)
|
|
{
|
|
if (!strcmpiW(entry->path, pszPath) && entry->index == index)
|
|
{
|
|
TRACE("cache hit\n");
|
|
*ppTypeLib = &entry->ITypeLib2_iface;
|
|
ITypeLib2_AddRef(*ppTypeLib);
|
|
LeaveCriticalSection(&cache_section);
|
|
return S_OK;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&cache_section);
|
|
|
|
/* now actually load and parse the typelib */
|
|
|
|
ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
|
|
if (ret == TYPE_E_CANTLOADLIBRARY)
|
|
ret = TLB_NEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile);
|
|
if (ret == TYPE_E_CANTLOADLIBRARY)
|
|
ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile);
|
|
if (SUCCEEDED(ret))
|
|
{
|
|
if (dwTLBLength >= 4)
|
|
{
|
|
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
|
|
{
|
|
FIXME("Header type magic 0x%08x not supported.\n",dwSignature);
|
|
ret = TYPE_E_CANTLOADLIBRARY;
|
|
}
|
|
}
|
|
else
|
|
ret = TYPE_E_CANTLOADLIBRARY;
|
|
IUnknown_Release(pFile);
|
|
}
|
|
|
|
if(*ppTypeLib) {
|
|
ITypeLibImpl *impl = impl_from_ITypeLib2(*ppTypeLib);
|
|
|
|
TRACE("adding to cache\n");
|
|
impl->path = heap_alloc((strlenW(pszPath)+1) * sizeof(WCHAR));
|
|
lstrcpyW(impl->path, pszPath);
|
|
/* We should really canonicalise the path here. */
|
|
impl->index = index;
|
|
|
|
/* FIXME: check if it has added already in the meantime */
|
|
EnterCriticalSection(&cache_section);
|
|
list_add_head(&tlb_cache, &impl->entry);
|
|
LeaveCriticalSection(&cache_section);
|
|
ret = S_OK;
|
|
}
|
|
else
|
|
{
|
|
if(ret != E_FAIL)
|
|
ERR("Loading of typelib %s failed with error %d\n", debugstr_w(pszFileName), GetLastError());
|
|
|
|
ret = TYPE_E_CANTLOADLIBRARY;
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*================== ITypeLib(2) Methods ===================================*/
|
|
|
|
static ITypeLibImpl* TypeLibImpl_Constructor(void)
|
|
{
|
|
ITypeLibImpl* pTypeLibImpl;
|
|
|
|
pTypeLibImpl = heap_alloc_zero(sizeof(ITypeLibImpl));
|
|
if (!pTypeLibImpl) return NULL;
|
|
|
|
pTypeLibImpl->ITypeLib2_iface.lpVtbl = &tlbvt;
|
|
pTypeLibImpl->ITypeComp_iface.lpVtbl = &tlbtcvt;
|
|
pTypeLibImpl->ICreateTypeLib2_iface.lpVtbl = &CreateTypeLib2Vtbl;
|
|
pTypeLibImpl->ref = 1;
|
|
|
|
list_init(&pTypeLibImpl->implib_list);
|
|
list_init(&pTypeLibImpl->custdata_list);
|
|
list_init(&pTypeLibImpl->name_list);
|
|
list_init(&pTypeLibImpl->string_list);
|
|
list_init(&pTypeLibImpl->guid_list);
|
|
list_init(&pTypeLibImpl->ref_list);
|
|
pTypeLibImpl->dispatch_href = -1;
|
|
|
|
return pTypeLibImpl;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ITypeLib2_Constructor_MSFT
|
|
*
|
|
* loading an MSFT typelib from an in-memory image
|
|
*/
|
|
static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength)
|
|
{
|
|
TLBContext cx;
|
|
LONG lPSegDir;
|
|
MSFT_Header tlbHeader;
|
|
MSFT_SegDir tlbSegDir;
|
|
ITypeLibImpl * pTypeLibImpl;
|
|
int i;
|
|
|
|
TRACE("%p, TLB length = %d\n", pLib, dwTLBLength);
|
|
|
|
pTypeLibImpl = TypeLibImpl_Constructor();
|
|
if (!pTypeLibImpl) return NULL;
|
|
|
|
/* get pointer to beginning of typelib data */
|
|
cx.pos = 0;
|
|
cx.oStart=0;
|
|
cx.mapping = pLib;
|
|
cx.pLibInfo = pTypeLibImpl;
|
|
cx.length = dwTLBLength;
|
|
|
|
/* read header */
|
|
MSFT_ReadLEDWords(&tlbHeader, sizeof(tlbHeader), &cx, 0);
|
|
TRACE_(typelib)("header:\n");
|
|
TRACE_(typelib)("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 );
|
|
if (tlbHeader.magic1 != MSFT_SIGNATURE) {
|
|
FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1);
|
|
return NULL;
|
|
}
|
|
TRACE_(typelib)("\tdispatchpos = 0x%x\n", tlbHeader.dispatchpos);
|
|
|
|
/* there is a small amount of information here until the next important
|
|
* part:
|
|
* the segment directory . Try to calculate the amount of data */
|
|
lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0);
|
|
|
|
/* now read the segment directory */
|
|
TRACE("read segment directory (at %d)\n",lPSegDir);
|
|
MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir);
|
|
cx.pTblDir = &tlbSegDir;
|
|
|
|
/* just check two entries */
|
|
if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F)
|
|
{
|
|
ERR("cannot find the table directory, ptr=0x%x\n",lPSegDir);
|
|
heap_free(pTypeLibImpl);
|
|
return NULL;
|
|
}
|
|
|
|
MSFT_ReadAllNames(&cx);
|
|
MSFT_ReadAllStrings(&cx);
|
|
MSFT_ReadAllGuids(&cx);
|
|
|
|
/* now fill our internal data */
|
|
/* TLIBATTR fields */
|
|
pTypeLibImpl->guid = MSFT_ReadGuid(tlbHeader.posguid, &cx);
|
|
|
|
pTypeLibImpl->syskind = tlbHeader.varflags & 0x0f; /* check the mask */
|
|
pTypeLibImpl->ptr_size = get_ptr_size(pTypeLibImpl->syskind);
|
|
pTypeLibImpl->ver_major = LOWORD(tlbHeader.version);
|
|
pTypeLibImpl->ver_minor = HIWORD(tlbHeader.version);
|
|
pTypeLibImpl->libflags = ((WORD) tlbHeader.flags & 0xffff) /* check mask */ | LIBFLAG_FHASDISKIMAGE;
|
|
|
|
pTypeLibImpl->set_lcid = tlbHeader.lcid2;
|
|
pTypeLibImpl->lcid = tlbHeader.lcid;
|
|
|
|
/* name, eventually add to a hash table */
|
|
pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset);
|
|
|
|
/* help info */
|
|
pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring);
|
|
pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile);
|
|
|
|
if( tlbHeader.varflags & HELPDLLFLAG)
|
|
{
|
|
int offset;
|
|
MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader));
|
|
pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset);
|
|
}
|
|
|
|
pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext;
|
|
|
|
/* custom data */
|
|
if(tlbHeader.CustomDataOffset >= 0)
|
|
{
|
|
MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->custdata_list);
|
|
}
|
|
|
|
/* fill in type descriptions */
|
|
if(tlbSegDir.pTypdescTab.length > 0)
|
|
{
|
|
int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT));
|
|
INT16 td[4];
|
|
pTypeLibImpl->ctTypeDesc = cTD;
|
|
pTypeLibImpl->pTypeDesc = heap_alloc_zero( cTD * sizeof(TYPEDESC));
|
|
MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset);
|
|
for(i=0; i<cTD; )
|
|
{
|
|
/* FIXME: add several sanity checks here */
|
|
pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK;
|
|
if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY)
|
|
{
|
|
/* FIXME: check safearray */
|
|
if(td[3] < 0)
|
|
pTypeLibImpl->pTypeDesc[i].u.lptdesc = &std_typedesc[td[2]];
|
|
else
|
|
pTypeLibImpl->pTypeDesc[i].u.lptdesc = &pTypeLibImpl->pTypeDesc[td[2]/8];
|
|
}
|
|
else if(td[0] == VT_CARRAY)
|
|
{
|
|
/* array descr table here */
|
|
pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)(INT_PTR)td[2]; /* temp store offset in*/
|
|
}
|
|
else if(td[0] == VT_USERDEFINED)
|
|
{
|
|
pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]);
|
|
}
|
|
if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK);
|
|
}
|
|
|
|
/* second time around to fill the array subscript info */
|
|
for(i=0;i<cTD;i++)
|
|
{
|
|
if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue;
|
|
if(tlbSegDir.pArrayDescriptions.offset>0)
|
|
{
|
|
MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (INT_PTR)pTypeLibImpl->pTypeDesc[i].u.lpadesc);
|
|
pTypeLibImpl->pTypeDesc[i].u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1));
|
|
|
|
if(td[1]<0)
|
|
pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK;
|
|
else
|
|
pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = cx.pLibInfo->pTypeDesc[td[0]/(2*sizeof(INT))];
|
|
|
|
pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2];
|
|
|
|
for(j = 0; j<td[2]; j++)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL;
|
|
ERR("didn't find array description data\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* imported type libs */
|
|
if(tlbSegDir.pImpFiles.offset>0)
|
|
{
|
|
TLBImpLib *pImpLib;
|
|
int oGuid, offset = tlbSegDir.pImpFiles.offset;
|
|
UINT16 size;
|
|
|
|
while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length)
|
|
{
|
|
char *name;
|
|
|
|
pImpLib = heap_alloc_zero(sizeof(TLBImpLib));
|
|
pImpLib->offset = offset - tlbSegDir.pImpFiles.offset;
|
|
MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset);
|
|
|
|
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);
|
|
MSFT_ReadLEWords(& size, sizeof(UINT16), &cx, DO_NOT_SEEK);
|
|
|
|
size >>= 2;
|
|
name = heap_alloc_zero(size+1);
|
|
MSFT_Read(name, size, &cx, DO_NOT_SEEK);
|
|
pImpLib->name = TLB_MultiByteToBSTR(name);
|
|
heap_free(name);
|
|
|
|
pImpLib->guid = MSFT_ReadGuid(oGuid, &cx);
|
|
offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3;
|
|
|
|
list_add_tail(&pTypeLibImpl->implib_list, &pImpLib->entry);
|
|
}
|
|
}
|
|
|
|
MSFT_ReadAllRefs(&cx);
|
|
|
|
pTypeLibImpl->dispatch_href = tlbHeader.dispatchpos;
|
|
|
|
/* type infos */
|
|
if(tlbHeader.nrtypeinfos >= 0 )
|
|
{
|
|
ITypeInfoImpl **ppTI;
|
|
|
|
ppTI = pTypeLibImpl->typeinfos = heap_alloc_zero(sizeof(ITypeInfoImpl*) * tlbHeader.nrtypeinfos);
|
|
|
|
for(i = 0; i < tlbHeader.nrtypeinfos; i++)
|
|
{
|
|
*ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl);
|
|
|
|
++ppTI;
|
|
(pTypeLibImpl->TypeInfoCount)++;
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
if(pTypeLibImpl->syskind == SYS_WIN32){
|
|
for(i = 0; i < pTypeLibImpl->TypeInfoCount; ++i)
|
|
TLB_fix_32on64_typeinfo(pTypeLibImpl->typeinfos[i]);
|
|
}
|
|
#endif
|
|
|
|
TRACE("(%p)\n", pTypeLibImpl);
|
|
return &pTypeLibImpl->ITypeLib2_iface;
|
|
}
|
|
|
|
|
|
static BOOL TLB_GUIDFromString(const char *str, GUID *guid)
|
|
{
|
|
char b[3];
|
|
int i;
|
|
short s;
|
|
|
|
if(sscanf(str, "%x-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) {
|
|
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;
|
|
}
|
|
|
|
static WORD SLTG_ReadString(const char *ptr, const TLBString **pStr, ITypeLibImpl *lib)
|
|
{
|
|
WORD bytelen;
|
|
DWORD len;
|
|
BSTR tmp_str;
|
|
|
|
*pStr = NULL;
|
|
bytelen = *(const WORD*)ptr;
|
|
if(bytelen == 0xffff) return 2;
|
|
|
|
len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0);
|
|
tmp_str = SysAllocStringLen(NULL, len);
|
|
if (tmp_str) {
|
|
MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, tmp_str, len);
|
|
*pStr = TLB_append_str(&lib->string_list, tmp_str);
|
|
SysFreeString(tmp_str);
|
|
}
|
|
return bytelen + 2;
|
|
}
|
|
|
|
static WORD SLTG_ReadStringA(const char *ptr, char **str)
|
|
{
|
|
WORD bytelen;
|
|
|
|
*str = NULL;
|
|
bytelen = *(const WORD*)ptr;
|
|
if(bytelen == 0xffff) return 2;
|
|
*str = heap_alloc(bytelen + 1);
|
|
memcpy(*str, ptr + 2, bytelen);
|
|
(*str)[bytelen] = '\0';
|
|
return bytelen + 2;
|
|
}
|
|
|
|
static TLBString *SLTG_ReadName(const char *pNameTable, int offset, ITypeLibImpl *lib)
|
|
{
|
|
BSTR tmp_str;
|
|
TLBString *tlbstr;
|
|
|
|
LIST_FOR_EACH_ENTRY(tlbstr, &lib->name_list, TLBString, entry) {
|
|
if (tlbstr->offset == offset)
|
|
return tlbstr;
|
|
}
|
|
|
|
tmp_str = TLB_MultiByteToBSTR(pNameTable + offset);
|
|
tlbstr = TLB_append_str(&lib->name_list, tmp_str);
|
|
SysFreeString(tmp_str);
|
|
|
|
return tlbstr;
|
|
}
|
|
|
|
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, pTypeLibImpl);
|
|
|
|
ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile, pTypeLibImpl);
|
|
|
|
pTypeLibImpl->dwHelpContext = *(DWORD*)ptr;
|
|
ptr += 4;
|
|
|
|
pTypeLibImpl->syskind = *(WORD*)ptr;
|
|
pTypeLibImpl->ptr_size = get_ptr_size(pTypeLibImpl->syskind);
|
|
ptr += 2;
|
|
|
|
if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL)
|
|
pTypeLibImpl->lcid = pTypeLibImpl->set_lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0);
|
|
else
|
|
pTypeLibImpl->lcid = pTypeLibImpl->set_lcid = 0;
|
|
ptr += 2;
|
|
|
|
ptr += 4; /* skip res12 */
|
|
|
|
pTypeLibImpl->libflags = *(WORD*)ptr;
|
|
ptr += 2;
|
|
|
|
pTypeLibImpl->ver_major = *(WORD*)ptr;
|
|
ptr += 2;
|
|
|
|
pTypeLibImpl->ver_minor = *(WORD*)ptr;
|
|
ptr += 2;
|
|
|
|
pTypeLibImpl->guid = TLB_append_guid(&pTypeLibImpl->guid_list, (GUID*)ptr, -2);
|
|
ptr += sizeof(GUID);
|
|
|
|
return ptr - (char*)pLibBlk;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
static HRESULT sltg_get_typelib_ref(const sltg_ref_lookup_t *table, DWORD typeinfo_ref,
|
|
HREFTYPE *typelib_ref)
|
|
{
|
|
if(table && typeinfo_ref < table->num)
|
|
{
|
|
*typelib_ref = table->refs[typeinfo_ref];
|
|
return S_OK;
|
|
}
|
|
|
|
ERR_(typelib)("Unable to find reference\n");
|
|
*typelib_ref = -1;
|
|
return E_FAIL;
|
|
}
|
|
|
|
static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_lookup_t *ref_lookup)
|
|
{
|
|
BOOL done = FALSE;
|
|
|
|
while(!done) {
|
|
if((*pType & 0xe00) == 0xe00) {
|
|
pTD->vt = VT_PTR;
|
|
pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
|
|
pTD = pTD->u.lptdesc;
|
|
}
|
|
switch(*pType & 0x3f) {
|
|
case VT_PTR:
|
|
pTD->vt = VT_PTR;
|
|
pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
|
|
pTD = pTD->u.lptdesc;
|
|
break;
|
|
|
|
case VT_USERDEFINED:
|
|
pTD->vt = VT_USERDEFINED;
|
|
sltg_get_typelib_ref(ref_lookup, *(++pType) / 4, &pTD->u.hreftype);
|
|
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;
|
|
pTD->u.lpadesc = heap_alloc_zero(sizeof(ARRAYDESC) + (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
|
|
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;
|
|
pTD->u.lptdesc = heap_alloc_zero(sizeof(TYPEDESC));
|
|
pTD = pTD->u.lptdesc;
|
|
break;
|
|
}
|
|
default:
|
|
pTD->vt = *pType & 0x3f;
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
pType++;
|
|
}
|
|
return pType;
|
|
}
|
|
|
|
static WORD *SLTG_DoElem(WORD *pType, char *pBlk,
|
|
ELEMDESC *pElem, const sltg_ref_lookup_t *ref_lookup)
|
|
{
|
|
/* 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;
|
|
|
|
return SLTG_DoType(pType, pBlk, &pElem->tdesc, ref_lookup);
|
|
}
|
|
|
|
|
|
static sltg_ref_lookup_t *SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeLibImpl *pTL,
|
|
char *pNameTable)
|
|
{
|
|
unsigned int ref;
|
|
char *name;
|
|
TLBRefType *ref_type;
|
|
sltg_ref_lookup_t *table;
|
|
HREFTYPE typelib_ref;
|
|
|
|
if(pRef->magic != SLTG_REF_MAGIC) {
|
|
FIXME("Ref magic = %x\n", pRef->magic);
|
|
return NULL;
|
|
}
|
|
name = ( (char*)pRef->names + pRef->number);
|
|
|
|
table = heap_alloc(sizeof(*table) + ((pRef->number >> 3) - 1) * sizeof(table->refs[0]));
|
|
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;
|
|
|
|
for(ref = 0; ref < pRef->number >> 3; ref++) {
|
|
char *refname;
|
|
unsigned int lib_offs, type_num;
|
|
|
|
ref_type = heap_alloc_zero(sizeof(TLBRefType));
|
|
|
|
name += SLTG_ReadStringA(name, &refname);
|
|
if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2)
|
|
FIXME_(typelib)("Can't sscanf ref\n");
|
|
if(lib_offs != 0xffff) {
|
|
TLBImpLib *import;
|
|
|
|
LIST_FOR_EACH_ENTRY(import, &pTL->implib_list, TLBImpLib, entry)
|
|
if(import->offset == lib_offs)
|
|
break;
|
|
|
|
if(&import->entry == &pTL->implib_list) {
|
|
char fname[MAX_PATH+1];
|
|
int len;
|
|
GUID tmpguid;
|
|
|
|
import = heap_alloc_zero(sizeof(*import));
|
|
import->offset = lib_offs;
|
|
TLB_GUIDFromString( pNameTable + lib_offs + 4, &tmpguid);
|
|
import->guid = TLB_append_guid(&pTL->guid_list, &tmpguid, 2);
|
|
if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%x#%s",
|
|
&import->wVersionMajor,
|
|
&import->wVersionMinor,
|
|
&import->lcid, fname) != 4) {
|
|
FIXME_(typelib)("can't sscanf ref %s\n",
|
|
pNameTable + lib_offs + 40);
|
|
}
|
|
len = strlen(fname);
|
|
if(fname[len-1] != '#')
|
|
FIXME("fname = %s\n", fname);
|
|
fname[len-1] = '\0';
|
|
import->name = TLB_MultiByteToBSTR(fname);
|
|
list_add_tail(&pTL->implib_list, &import->entry);
|
|
}
|
|
ref_type->pImpTLInfo = import;
|
|
|
|
/* Store a reference to IDispatch */
|
|
if(pTL->dispatch_href == -1 && IsEqualGUID(&import->guid->guid, &IID_StdOle) && type_num == 4)
|
|
pTL->dispatch_href = typelib_ref;
|
|
|
|
} else { /* internal ref */
|
|
ref_type->pImpTLInfo = TLB_REF_INTERNAL;
|
|
}
|
|
ref_type->reference = typelib_ref;
|
|
ref_type->index = type_num;
|
|
|
|
heap_free(refname);
|
|
list_add_tail(&pTL->ref_list, &ref_type->entry);
|
|
|
|
table->refs[ref] = typelib_ref;
|
|
typelib_ref += 4;
|
|
}
|
|
if((BYTE)*name != SLTG_REF_MAGIC)
|
|
FIXME_(typelib)("End of ref block magic = %x\n", *name);
|
|
dump_TLBRefType(pTL);
|
|
return table;
|
|
}
|
|
|
|
static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI,
|
|
BOOL OneOnly, const sltg_ref_lookup_t *ref_lookup)
|
|
{
|
|
SLTG_ImplInfo *info;
|
|
TLBImplType *pImplType;
|
|
/* 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;
|
|
while(1){
|
|
pTI->typeattr.cImplTypes++;
|
|
if(info->next == 0xffff)
|
|
break;
|
|
info = (SLTG_ImplInfo*)(pBlk + info->next);
|
|
}
|
|
|
|
info = (SLTG_ImplInfo*)pBlk;
|
|
pTI->impltypes = TLBImplType_Alloc(pTI->typeattr.cImplTypes);
|
|
pImplType = pTI->impltypes;
|
|
while(1) {
|
|
sltg_get_typelib_ref(ref_lookup, info->ref, &pImplType->hRef);
|
|
pImplType->implflags = info->impltypeflags;
|
|
++pImplType;
|
|
|
|
if(info->next == 0xffff)
|
|
break;
|
|
if(OneOnly)
|
|
FIXME_(typelib)("Interface inheriting more than one interface\n");
|
|
info = (SLTG_ImplInfo*)(pBlk + info->next);
|
|
}
|
|
info++; /* see comment at top of function */
|
|
return (char*)info;
|
|
}
|
|
|
|
static void SLTG_DoVars(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI, unsigned short cVars,
|
|
const char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
|
|
{
|
|
TLBVarDesc *pVarDesc;
|
|
const TLBString *prevName = NULL;
|
|
SLTG_Variable *pItem;
|
|
unsigned short i;
|
|
WORD *pType;
|
|
|
|
pVarDesc = pTI->vardescs = TLBVarDesc_Alloc(cVars);
|
|
|
|
for(pItem = (SLTG_Variable *)pFirstItem, i = 0; i < cVars;
|
|
pItem = (SLTG_Variable *)(pBlk + pItem->next), i++, ++pVarDesc) {
|
|
|
|
pVarDesc->vardesc.memid = pItem->memid;
|
|
|
|
if (pItem->magic != SLTG_VAR_MAGIC &&
|
|
pItem->magic != SLTG_VAR_WITH_FLAGS_MAGIC) {
|
|
FIXME_(typelib)("var magic = %02x\n", pItem->magic);
|
|
return;
|
|
}
|
|
|
|
if (pItem->name == 0xfffe)
|
|
pVarDesc->Name = prevName;
|
|
else
|
|
pVarDesc->Name = SLTG_ReadName(pNameTable, pItem->name, pTI->pTypeLib);
|
|
|
|
TRACE_(typelib)("name: %s\n", debugstr_w(TLB_get_bstr(pVarDesc->Name)));
|
|
TRACE_(typelib)("byte_offs = 0x%x\n", pItem->byte_offs);
|
|
TRACE_(typelib)("memid = 0x%x\n", pItem->memid);
|
|
|
|
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,
|
|
&pVarDesc->vardesc.elemdescVar, ref_lookup);
|
|
|
|
if (TRACE_ON(typelib)) {
|
|
char buf[300];
|
|
dump_TypeDesc(&pVarDesc->vardesc.elemdescVar.tdesc, buf);
|
|
TRACE_(typelib)("elemdescVar: %s\n", buf);
|
|
}
|
|
|
|
if (pItem->flags & 0x40) {
|
|
TRACE_(typelib)("VAR_DISPATCH\n");
|
|
pVarDesc->vardesc.varkind = VAR_DISPATCH;
|
|
}
|
|
else if (pItem->flags & 0x10) {
|
|
TRACE_(typelib)("VAR_CONST\n");
|
|
pVarDesc->vardesc.varkind = VAR_CONST;
|
|
pVarDesc->vardesc.u.lpvarValue = heap_alloc(sizeof(VARIANT));
|
|
V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_INT;
|
|
if (pItem->flags & 0x08)
|
|
V_INT(pVarDesc->vardesc.u.lpvarValue) = pItem->byte_offs;
|
|
else {
|
|
switch (pVarDesc->vardesc.elemdescVar.tdesc.vt)
|
|
{
|
|
case VT_LPSTR:
|
|
case VT_LPWSTR:
|
|
case VT_BSTR:
|
|
{
|
|
WORD len = *(WORD *)(pBlk + pItem->byte_offs);
|
|
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);
|
|
}
|
|
V_VT(pVarDesc->vardesc.u.lpvarValue) = VT_BSTR;
|
|
V_BSTR(pVarDesc->vardesc.u.lpvarValue) = str;
|
|
break;
|
|
}
|
|
case VT_I2:
|
|
case VT_UI2:
|
|
case VT_I4:
|
|
case VT_UI4:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
V_INT(pVarDesc->vardesc.u.lpvarValue) =
|
|
*(INT*)(pBlk + pItem->byte_offs);
|
|
break;
|
|
default:
|
|
FIXME_(typelib)("VAR_CONST unimplemented for type %d\n", pVarDesc->vardesc.elemdescVar.tdesc.vt);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
TRACE_(typelib)("VAR_PERINSTANCE\n");
|
|
pVarDesc->vardesc.u.oInst = pItem->byte_offs;
|
|
pVarDesc->vardesc.varkind = VAR_PERINSTANCE;
|
|
}
|
|
|
|
if (pItem->magic == SLTG_VAR_WITH_FLAGS_MAGIC)
|
|
pVarDesc->vardesc.wVarFlags = pItem->varflags;
|
|
|
|
if (pItem->flags & 0x80)
|
|
pVarDesc->vardesc.wVarFlags |= VARFLAG_FREADONLY;
|
|
|
|
prevName = pVarDesc->Name;
|
|
}
|
|
pTI->typeattr.cVars = cVars;
|
|
}
|
|
|
|
static void SLTG_DoFuncs(char *pBlk, char *pFirstItem, ITypeInfoImpl *pTI,
|
|
unsigned short cFuncs, char *pNameTable, const sltg_ref_lookup_t *ref_lookup)
|
|
{
|
|
SLTG_Function *pFunc;
|
|
unsigned short i;
|
|
TLBFuncDesc *pFuncDesc;
|
|
|
|
pTI->funcdescs = TLBFuncDesc_Alloc(cFuncs);
|
|
|
|
pFuncDesc = pTI->funcdescs;
|
|
for(pFunc = (SLTG_Function*)pFirstItem, i = 0; i < cFuncs && pFunc != (SLTG_Function*)0xFFFF;
|
|
pFunc = (SLTG_Function*)(pBlk + pFunc->next), i++, ++pFuncDesc) {
|
|
|
|
int param;
|
|
WORD *pType, *pArg;
|
|
|
|
switch (pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT) {
|
|
case SLTG_FUNCTION_MAGIC:
|
|
pFuncDesc->funcdesc.funckind = FUNC_PUREVIRTUAL;
|
|
break;
|
|
case SLTG_DISPATCH_FUNCTION_MAGIC:
|
|
pFuncDesc->funcdesc.funckind = FUNC_DISPATCH;
|
|
break;
|
|
case SLTG_STATIC_FUNCTION_MAGIC:
|
|
pFuncDesc->funcdesc.funckind = FUNC_STATIC;
|
|
break;
|
|
default:
|
|
FIXME("unimplemented func magic = %02x\n", pFunc->magic & ~SLTG_FUNCTION_FLAGS_PRESENT);
|
|
continue;
|
|
}
|
|
pFuncDesc->Name = SLTG_ReadName(pNameTable, pFunc->name, pTI->pTypeLib);
|
|
|
|
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) * sizeof(void *) / pTI->pTypeLib->ptr_size;
|
|
|
|
if(pFunc->magic & SLTG_FUNCTION_FLAGS_PRESENT)
|
|
pFuncDesc->funcdesc.wFuncFlags = pFunc->funcflags;
|
|
|
|
if(pFunc->retnextopt & 0x80)
|
|
pType = &pFunc->rettype;
|
|
else
|
|
pType = (WORD*)(pBlk + pFunc->rettype);
|
|
|
|
SLTG_DoElem(pType, pBlk, &pFuncDesc->funcdesc.elemdescFunc, ref_lookup);
|
|
|
|
pFuncDesc->funcdesc.lprgelemdescParam =
|
|
heap_alloc_zero(pFuncDesc->funcdesc.cParams * sizeof(ELEMDESC));
|
|
pFuncDesc->pParamDesc = TLBParDesc_Constructor(pFuncDesc->funcdesc.cParams);
|
|
|
|
pArg = (WORD*)(pBlk + pFunc->arg_off);
|
|
|
|
for(param = 0; param < pFuncDesc->funcdesc.cParams; param++) {
|
|
char *paramName = pNameTable + *pArg;
|
|
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
|
|
meaning that the next WORD is an offset to the type. */
|
|
|
|
HaveOffs = FALSE;
|
|
if(*pArg == 0xffff)
|
|
paramName = NULL;
|
|
else if(*pArg == 0xfffe) {
|
|
paramName = NULL;
|
|
HaveOffs = TRUE;
|
|
}
|
|
else if(paramName[-1] && !isalnum(paramName[-1]))
|
|
HaveOffs = TRUE;
|
|
|
|
pArg++;
|
|
|
|
if(HaveOffs) { /* the next word is an offset to type */
|
|
pType = (WORD*)(pBlk + *pArg);
|
|
SLTG_DoElem(pType, pBlk,
|
|
&pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
|
|
pArg++;
|
|
} else {
|
|
if(paramName)
|
|
paramName--;
|
|
pArg = SLTG_DoElem(pArg, pBlk,
|
|
&pFuncDesc->funcdesc.lprgelemdescParam[param], ref_lookup);
|
|
}
|
|
|
|
/* Are we an optional param ? */
|
|
if(pFuncDesc->funcdesc.cParams - param <=
|
|
pFuncDesc->funcdesc.cParamsOpt)
|
|
pFuncDesc->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT;
|
|
|
|
if(paramName) {
|
|
pFuncDesc->pParamDesc[param].Name = SLTG_ReadName(pNameTable,
|
|
paramName - pNameTable, pTI->pTypeLib);
|
|
} else {
|
|
pFuncDesc->pParamDesc[param].Name = pFuncDesc->Name;
|
|
}
|
|
}
|
|
}
|
|
pTI->typeattr.cFuncs = cFuncs;
|
|
}
|
|
|
|
static void SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI,
|
|
char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
|
|
SLTG_TypeInfoTail *pTITail)
|
|
{
|
|
char *pFirstItem;
|
|
sltg_ref_lookup_t *ref_lookup = NULL;
|
|
|
|
if(pTIHeader->href_table != 0xffffffff) {
|
|
ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
|
|
pNameTable);
|
|
}
|
|
|
|
pFirstItem = pBlk;
|
|
|
|
if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
|
|
SLTG_DoImpls(pFirstItem, pTI, FALSE, ref_lookup);
|
|
}
|
|
heap_free(ref_lookup);
|
|
}
|
|
|
|
|
|
static void SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI,
|
|
char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
|
|
const SLTG_TypeInfoTail *pTITail)
|
|
{
|
|
char *pFirstItem;
|
|
sltg_ref_lookup_t *ref_lookup = NULL;
|
|
|
|
if(pTIHeader->href_table != 0xffffffff) {
|
|
ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
|
|
pNameTable);
|
|
}
|
|
|
|
pFirstItem = pBlk;
|
|
|
|
if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) {
|
|
SLTG_DoImpls(pFirstItem, pTI, TRUE, ref_lookup);
|
|
}
|
|
|
|
if (pTITail->funcs_off != 0xffff)
|
|
SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
|
|
|
|
heap_free(ref_lookup);
|
|
|
|
if (TRACE_ON(typelib))
|
|
dump_TLBFuncDesc(pTI->funcdescs, pTI->typeattr.cFuncs);
|
|
}
|
|
|
|
static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
|
|
const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
|
|
const SLTG_TypeInfoTail *pTITail)
|
|
{
|
|
SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
|
|
}
|
|
|
|
static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
|
|
char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
|
|
const SLTG_TypeInfoTail *pTITail)
|
|
{
|
|
WORD *pType;
|
|
sltg_ref_lookup_t *ref_lookup = NULL;
|
|
|
|
if (pTITail->simple_alias) {
|
|
/* if simple alias, no more processing required */
|
|
pTI->tdescAlias = heap_alloc_zero(sizeof(TYPEDESC));
|
|
pTI->tdescAlias->vt = pTITail->tdescalias_vt;
|
|
return;
|
|
}
|
|
|
|
if(pTIHeader->href_table != 0xffffffff) {
|
|
ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
|
|
pNameTable);
|
|
}
|
|
|
|
/* otherwise it is an offset to a type */
|
|
pType = (WORD *)(pBlk + pTITail->tdescalias_vt);
|
|
|
|
pTI->tdescAlias = heap_alloc(sizeof(TYPEDESC));
|
|
SLTG_DoType(pType, pBlk, pTI->tdescAlias, ref_lookup);
|
|
|
|
heap_free(ref_lookup);
|
|
}
|
|
|
|
static void SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI,
|
|
char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
|
|
const SLTG_TypeInfoTail *pTITail)
|
|
{
|
|
sltg_ref_lookup_t *ref_lookup = NULL;
|
|
if (pTIHeader->href_table != 0xffffffff)
|
|
ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
|
|
pNameTable);
|
|
|
|
if (pTITail->vars_off != 0xffff)
|
|
SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
|
|
|
|
if (pTITail->funcs_off != 0xffff)
|
|
SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
|
|
|
|
if (pTITail->impls_off != 0xffff)
|
|
SLTG_DoImpls(pBlk + pTITail->impls_off, pTI, FALSE, ref_lookup);
|
|
|
|
/* this is necessary to cope with MSFT typelibs that set cFuncs to the number
|
|
* of dispinterface functions including the IDispatch ones, so
|
|
* ITypeInfo::GetFuncDesc takes the real value for cFuncs from cbSizeVft */
|
|
pTI->typeattr.cbSizeVft = pTI->typeattr.cFuncs * pTI->pTypeLib->ptr_size;
|
|
|
|
heap_free(ref_lookup);
|
|
if (TRACE_ON(typelib))
|
|
dump_TLBFuncDesc(pTI->funcdescs, pTI->typeattr.cFuncs);
|
|
}
|
|
|
|
static void SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI,
|
|
const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
|
|
const SLTG_TypeInfoTail *pTITail)
|
|
{
|
|
SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL);
|
|
}
|
|
|
|
static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI,
|
|
char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
|
|
const SLTG_TypeInfoTail *pTITail)
|
|
{
|
|
sltg_ref_lookup_t *ref_lookup = NULL;
|
|
if (pTIHeader->href_table != 0xffffffff)
|
|
ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table), pTI->pTypeLib,
|
|
pNameTable);
|
|
|
|
if (pTITail->vars_off != 0xffff)
|
|
SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, ref_lookup);
|
|
|
|
if (pTITail->funcs_off != 0xffff)
|
|
SLTG_DoFuncs(pBlk, pBlk + pTITail->funcs_off, pTI, pTITail->cFuncs, pNameTable, ref_lookup);
|
|
heap_free(ref_lookup);
|
|
if (TRACE_ON(typelib))
|
|
dump_TypeInfo(pTI);
|
|
}
|
|
|
|
/* Because SLTG_OtherTypeInfo is such a painful struct, we make a more
|
|
manageable copy of it into this */
|
|
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;
|
|
|
|
TRACE_(typelib)("%p, TLB length = %d\n", pLib, dwTLBLength);
|
|
|
|
|
|
pTypeLibImpl = TypeLibImpl_Constructor();
|
|
if (!pTypeLibImpl) return NULL;
|
|
|
|
pHeader = pLib;
|
|
|
|
TRACE_(typelib)("header:\n");
|
|
TRACE_(typelib)("\tmagic=0x%08x, file blocks = %d\n", pHeader->SLTG_magic,
|
|
pHeader->nrOfFileBlks );
|
|
if (pHeader->SLTG_magic != SLTG_SIGNATURE) {
|
|
FIXME_(typelib)("Header type magic 0x%08x not supported.\n",
|
|
pHeader->SLTG_magic);
|
|
return NULL;
|
|
}
|
|
|
|
/* 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))) {
|
|
FIXME_(typelib)("CompObj magic = %s\n", pMagic->CompObj_magic);
|
|
return NULL;
|
|
}
|
|
if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC,
|
|
sizeof(SLTG_DIR_MAGIC))) {
|
|
FIXME_(typelib)("dir magic = %s\n", pMagic->dir_magic);
|
|
return NULL;
|
|
}
|
|
|
|
pIndex = (SLTG_Index*)(pMagic+1);
|
|
|
|
pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount);
|
|
|
|
pFirstBlk = pPad9 + 1;
|
|
|
|
/* We'll set up a ptr to the main library block, which is the last one. */
|
|
|
|
for(pBlk = pFirstBlk, order = pHeader->first_blk - 1;
|
|
pBlkEntry[order].next != 0;
|
|
order = pBlkEntry[order].next - 1) {
|
|
pBlk = (char*)pBlk + pBlkEntry[order].len;
|
|
}
|
|
pLibBlk = pBlk;
|
|
|
|
len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl);
|
|
|
|
/* Now there are 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount
|
|
interspersed */
|
|
|
|
len += 0x40;
|
|
|
|
/* And now TypeInfoCount of SLTG_OtherTypeInfo */
|
|
|
|
pOtherTypeInfoBlks = heap_alloc_zero(sizeof(*pOtherTypeInfoBlks) * pTypeLibImpl->TypeInfoCount);
|
|
|
|
|
|
ptr = (char*)pLibBlk + len;
|
|
|
|
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;
|
|
pOtherTypeInfoBlks[i].index_name = heap_alloc(w+1);
|
|
memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w);
|
|
pOtherTypeInfoBlks[i].index_name[w] = '\0';
|
|
}
|
|
w = *(WORD*)(ptr + 4 + len);
|
|
if(w != 0xffff) {
|
|
TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w));
|
|
len += w;
|
|
pOtherTypeInfoBlks[i].other_name = heap_alloc(w+1);
|
|
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) {
|
|
pOtherTypeInfoBlks[i].extra = heap_alloc(extra);
|
|
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);
|
|
|
|
/* 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
|
|
table */
|
|
|
|
pNameTable = (char*)pLibBlk + len;
|
|
|
|
switch(*(WORD*)pNameTable) {
|
|
case 0xffff:
|
|
break;
|
|
case 0x0200:
|
|
pNameTable += 0x20;
|
|
break;
|
|
default:
|
|
FIXME_(typelib)("pNameTable jump = %x\n", *(WORD*)pNameTable);
|
|
break;
|
|
}
|
|
|
|
pNameTable += 0x216;
|
|
|
|
pNameTable += 2;
|
|
|
|
TRACE_(typelib)("Library name is %s\n", pNameTable + pLibBlk->name);
|
|
|
|
pTypeLibImpl->Name = SLTG_ReadName(pNameTable, pLibBlk->name, pTypeLibImpl);
|
|
|
|
|
|
/* 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
|
|
them in the order in which they are in the file */
|
|
|
|
pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
|
|
ppTypeInfoImpl = pTypeLibImpl->typeinfos;
|
|
|
|
for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0;
|
|
pBlkEntry[order].next != 0;
|
|
order = pBlkEntry[order].next - 1, i++) {
|
|
|
|
SLTG_TypeInfoHeader *pTIHeader;
|
|
SLTG_TypeInfoTail *pTITail;
|
|
SLTG_MemberHeader *pMemHeader;
|
|
|
|
if(strcmp(pBlkEntry[order].index_string + (char*)pMagic, pOtherTypeInfoBlks[i].index_name)) {
|
|
FIXME_(typelib)("Index strings don't match\n");
|
|
heap_free(pOtherTypeInfoBlks);
|
|
return NULL;
|
|
}
|
|
|
|
pTIHeader = pBlk;
|
|
if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) {
|
|
FIXME_(typelib)("TypeInfoHeader magic = %04x\n", pTIHeader->magic);
|
|
heap_free(pOtherTypeInfoBlks);
|
|
return NULL;
|
|
}
|
|
TRACE_(typelib)("pTIHeader->res06 = %x, pTIHeader->res0e = %x, "
|
|
"pTIHeader->res16 = %x, pTIHeader->res1e = %x\n",
|
|
pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
|
|
|
|
*ppTypeInfoImpl = ITypeInfoImpl_Constructor();
|
|
(*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl;
|
|
(*ppTypeInfoImpl)->index = i;
|
|
(*ppTypeInfoImpl)->Name = SLTG_ReadName(pNameTable, pOtherTypeInfoBlks[i].name_offs, pTypeLibImpl);
|
|
(*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext;
|
|
(*ppTypeInfoImpl)->guid = TLB_append_guid(&pTypeLibImpl->guid_list, &pOtherTypeInfoBlks[i].uuid, 2);
|
|
(*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);
|
|
|
|
if((*ppTypeInfoImpl)->typeattr.wTypeFlags & TYPEFLAG_FDUAL)
|
|
(*ppTypeInfoImpl)->typeattr.typekind = TKIND_DISPATCH;
|
|
|
|
if((pTIHeader->typeflags1 & 7) != 2)
|
|
FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1);
|
|
if(pTIHeader->typeflags3 != 2)
|
|
FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
|
|
|
|
TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n",
|
|
debugstr_w(TLB_get_bstr((*ppTypeInfoImpl)->Name)),
|
|
typekind_desc[pTIHeader->typekind],
|
|
debugstr_guid(TLB_get_guidref((*ppTypeInfoImpl)->guid)),
|
|
(*ppTypeInfoImpl)->typeattr.wTypeFlags);
|
|
|
|
pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
|
|
|
|
pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
|
|
|
|
(*ppTypeInfoImpl)->typeattr.cbAlignment = pTITail->cbAlignment;
|
|
(*ppTypeInfoImpl)->typeattr.cbSizeInstance = pTITail->cbSizeInstance;
|
|
(*ppTypeInfoImpl)->typeattr.cbSizeVft = pTITail->cbSizeVft;
|
|
|
|
switch(pTIHeader->typekind) {
|
|
case TKIND_ENUM:
|
|
SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
|
|
pTIHeader, pTITail);
|
|
break;
|
|
|
|
case TKIND_RECORD:
|
|
SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
|
|
pTIHeader, pTITail);
|
|
break;
|
|
|
|
case TKIND_INTERFACE:
|
|
SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
|
|
pTIHeader, pTITail);
|
|
break;
|
|
|
|
case TKIND_COCLASS:
|
|
SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
|
|
pTIHeader, pTITail);
|
|
break;
|
|
|
|
case TKIND_ALIAS:
|
|
SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
|
|
pTIHeader, pTITail);
|
|
break;
|
|
|
|
case TKIND_DISPATCH:
|
|
SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
|
|
pTIHeader, pTITail);
|
|
break;
|
|
|
|
case TKIND_MODULE:
|
|
SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
|
|
pTIHeader, pTITail);
|
|
break;
|
|
|
|
default:
|
|
FIXME("Not processing typekind %d\n", pTIHeader->typekind);
|
|
break;
|
|
|
|
}
|
|
|
|
/* could get cFuncs, cVars and cImplTypes from here
|
|
but we've already set those */
|
|
#define X(x) TRACE_(typelib)("tt "#x": %x\n",pTITail->res##x);
|
|
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
|
|
++ppTypeInfoImpl;
|
|
pBlk = (char*)pBlk + pBlkEntry[order].len;
|
|
}
|
|
|
|
if(i != pTypeLibImpl->TypeInfoCount) {
|
|
FIXME("Somehow processed %d TypeInfos\n", i);
|
|
heap_free(pOtherTypeInfoBlks);
|
|
return NULL;
|
|
}
|
|
|
|
heap_free(pOtherTypeInfoBlks);
|
|
return &pTypeLibImpl->ITypeLib2_iface;
|
|
}
|
|
|
|
static HRESULT WINAPI ITypeLib2_fnQueryInterface(ITypeLib2 *iface, REFIID riid, void **ppv)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
|
|
TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
|
|
|
|
if(IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid,&IID_ITypeLib)||
|
|
IsEqualIID(riid,&IID_ITypeLib2))
|
|
{
|
|
*ppv = &This->ITypeLib2_iface;
|
|
}
|
|
else if(IsEqualIID(riid, &IID_ICreateTypeLib) ||
|
|
IsEqualIID(riid, &IID_ICreateTypeLib2))
|
|
{
|
|
*ppv = &This->ICreateTypeLib2_iface;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
TRACE("-- Interface: E_NOINTERFACE\n");
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown*)*ppv);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
ULONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%u\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
ULONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%u\n",This, ref);
|
|
|
|
if (!ref)
|
|
{
|
|
TLBImpLib *pImpLib, *pImpLibNext;
|
|
TLBRefType *ref_type, *ref_type_next;
|
|
TLBString *tlbstr, *tlbstr_next;
|
|
TLBGuid *tlbguid, *tlbguid_next;
|
|
int i;
|
|
|
|
/* remove cache entry */
|
|
if(This->path)
|
|
{
|
|
TRACE("removing from cache list\n");
|
|
EnterCriticalSection(&cache_section);
|
|
if(This->entry.next)
|
|
list_remove(&This->entry);
|
|
LeaveCriticalSection(&cache_section);
|
|
heap_free(This->path);
|
|
}
|
|
TRACE(" destroying ITypeLib(%p)\n",This);
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(tlbstr, tlbstr_next, &This->string_list, TLBString, entry) {
|
|
list_remove(&tlbstr->entry);
|
|
SysFreeString(tlbstr->str);
|
|
heap_free(tlbstr);
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(tlbstr, tlbstr_next, &This->name_list, TLBString, entry) {
|
|
list_remove(&tlbstr->entry);
|
|
SysFreeString(tlbstr->str);
|
|
heap_free(tlbstr);
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(tlbguid, tlbguid_next, &This->guid_list, TLBGuid, entry) {
|
|
list_remove(&tlbguid->entry);
|
|
heap_free(tlbguid);
|
|
}
|
|
|
|
TLB_FreeCustData(&This->custdata_list);
|
|
|
|
for (i = 0; i < This->ctTypeDesc; i++)
|
|
if (This->pTypeDesc[i].vt == VT_CARRAY)
|
|
heap_free(This->pTypeDesc[i].u.lpadesc);
|
|
|
|
heap_free(This->pTypeDesc);
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(pImpLib, pImpLibNext, &This->implib_list, TLBImpLib, entry)
|
|
{
|
|
if (pImpLib->pImpTypeLib)
|
|
ITypeLib2_Release(&pImpLib->pImpTypeLib->ITypeLib2_iface);
|
|
SysFreeString(pImpLib->name);
|
|
|
|
list_remove(&pImpLib->entry);
|
|
heap_free(pImpLib);
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(ref_type, ref_type_next, &This->ref_list, TLBRefType, entry)
|
|
{
|
|
list_remove(&ref_type->entry);
|
|
heap_free(ref_type);
|
|
}
|
|
|
|
for (i = 0; i < This->TypeInfoCount; ++i){
|
|
heap_free(This->typeinfos[i]->tdescAlias);
|
|
ITypeInfoImpl_Destroy(This->typeinfos[i]);
|
|
}
|
|
heap_free(This->typeinfos);
|
|
heap_free(This);
|
|
return 0;
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
/* ITypeLib::GetTypeInfoCount
|
|
*
|
|
* Returns the number of type descriptions in the type library
|
|
*/
|
|
static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
TRACE("(%p)->count is %d\n",This, This->TypeInfoCount);
|
|
return This->TypeInfoCount;
|
|
}
|
|
|
|
/* ITypeLib::GetTypeInfo
|
|
*
|
|
* retrieves the specified type description in the library.
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetTypeInfo(
|
|
ITypeLib2 *iface,
|
|
UINT index,
|
|
ITypeInfo **ppTInfo)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
|
|
TRACE("%p %u %p\n", This, index, ppTInfo);
|
|
|
|
if(!ppTInfo)
|
|
return E_INVALIDARG;
|
|
|
|
if(index >= This->TypeInfoCount)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
*ppTInfo = (ITypeInfo *)&This->typeinfos[index]->ITypeInfo2_iface;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* ITypeLibs::GetTypeInfoType
|
|
*
|
|
* Retrieves the type of a type description.
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType(
|
|
ITypeLib2 *iface,
|
|
UINT index,
|
|
TYPEKIND *pTKind)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
|
|
TRACE("(%p, %d, %p)\n", This, index, pTKind);
|
|
|
|
if(!pTKind)
|
|
return E_INVALIDARG;
|
|
|
|
if(index >= This->TypeInfoCount)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
*pTKind = This->typeinfos[index]->typeattr.typekind;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeLib::GetTypeInfoOfGuid
|
|
*
|
|
* Retrieves the type description that corresponds to the specified GUID.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid(
|
|
ITypeLib2 *iface,
|
|
REFGUID guid,
|
|
ITypeInfo **ppTInfo)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
int i;
|
|
|
|
TRACE("%p %s %p\n", This, debugstr_guid(guid), ppTInfo);
|
|
|
|
for(i = 0; i < This->TypeInfoCount; ++i){
|
|
if(IsEqualIID(TLB_get_guid_null(This->typeinfos[i]->guid), guid)){
|
|
*ppTInfo = (ITypeInfo *)&This->typeinfos[i]->ITypeInfo2_iface;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
|
|
/* ITypeLib::GetLibAttr
|
|
*
|
|
* Retrieves the structure that contains the library's attributes.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetLibAttr(
|
|
ITypeLib2 *iface,
|
|
LPTLIBATTR *attr)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
|
|
TRACE("(%p, %p)\n", This, attr);
|
|
|
|
if (!attr) return E_INVALIDARG;
|
|
|
|
*attr = heap_alloc(sizeof(**attr));
|
|
if (!*attr) return E_OUTOFMEMORY;
|
|
|
|
(*attr)->guid = *TLB_get_guid_null(This->guid);
|
|
(*attr)->lcid = This->set_lcid;
|
|
(*attr)->syskind = This->syskind;
|
|
(*attr)->wMajorVerNum = This->ver_major;
|
|
(*attr)->wMinorVerNum = This->ver_minor;
|
|
(*attr)->wLibFlags = This->libflags;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeLib::GetTypeComp
|
|
*
|
|
* Enables a client compiler to bind to a library's types, variables,
|
|
* constants, and global functions.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetTypeComp(
|
|
ITypeLib2 *iface,
|
|
ITypeComp **ppTComp)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n",This,ppTComp);
|
|
*ppTComp = &This->ITypeComp_iface;
|
|
ITypeComp_AddRef(*ppTComp);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* 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.
|
|
*
|
|
* On a successful return all non-null BSTR pointers will have been set,
|
|
* possibly to NULL.
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetDocumentation(
|
|
ITypeLib2 *iface,
|
|
INT index,
|
|
BSTR *pBstrName,
|
|
BSTR *pBstrDocString,
|
|
DWORD *pdwHelpContext,
|
|
BSTR *pBstrHelpFile)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
HRESULT result = E_INVALIDARG;
|
|
ITypeInfo *pTInfo;
|
|
|
|
TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n",
|
|
This, index,
|
|
pBstrName, pBstrDocString,
|
|
pdwHelpContext, pBstrHelpFile);
|
|
|
|
if(index<0)
|
|
{
|
|
/* documentation for the typelib */
|
|
if(pBstrName)
|
|
{
|
|
if (This->Name)
|
|
{
|
|
if(!(*pBstrName = SysAllocString(TLB_get_bstr(This->Name))))
|
|
goto memerr1;
|
|
}
|
|
else
|
|
*pBstrName = NULL;
|
|
}
|
|
if(pBstrDocString)
|
|
{
|
|
if (This->DocString)
|
|
{
|
|
if(!(*pBstrDocString = SysAllocString(TLB_get_bstr(This->DocString))))
|
|
goto memerr2;
|
|
}
|
|
else
|
|
*pBstrDocString = NULL;
|
|
}
|
|
if(pdwHelpContext)
|
|
{
|
|
*pdwHelpContext = This->dwHelpContext;
|
|
}
|
|
if(pBstrHelpFile)
|
|
{
|
|
if (This->HelpFile)
|
|
{
|
|
if(!(*pBstrHelpFile = SysAllocString(TLB_get_bstr(This->HelpFile))))
|
|
goto memerr3;
|
|
}
|
|
else
|
|
*pBstrHelpFile = NULL;
|
|
}
|
|
|
|
result = S_OK;
|
|
}
|
|
else
|
|
{
|
|
/* for a typeinfo */
|
|
result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo);
|
|
|
|
if(SUCCEEDED(result))
|
|
{
|
|
result = ITypeInfo_GetDocumentation(pTInfo,
|
|
MEMBERID_NIL,
|
|
pBstrName,
|
|
pBstrDocString,
|
|
pdwHelpContext, pBstrHelpFile);
|
|
|
|
ITypeInfo_Release(pTInfo);
|
|
}
|
|
}
|
|
return result;
|
|
memerr3:
|
|
if (pBstrDocString) SysFreeString (*pBstrDocString);
|
|
memerr2:
|
|
if (pBstrName) SysFreeString (*pBstrName);
|
|
memerr1:
|
|
return STG_E_INSUFFICIENTMEMORY;
|
|
}
|
|
|
|
/* ITypeLib::IsName
|
|
*
|
|
* Indicates whether a passed-in string contains the name of a type or member
|
|
* described in the library.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnIsName(
|
|
ITypeLib2 *iface,
|
|
LPOLESTR szNameBuf,
|
|
ULONG lHashVal,
|
|
BOOL *pfName)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
int tic;
|
|
UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR), fdc, vrc;
|
|
|
|
TRACE("(%p)->(%s,%08x,%p)\n", This, debugstr_w(szNameBuf), lHashVal,
|
|
pfName);
|
|
|
|
*pfName=TRUE;
|
|
for(tic = 0; tic < This->TypeInfoCount; ++tic){
|
|
ITypeInfoImpl *pTInfo = This->typeinfos[tic];
|
|
if(!TLB_str_memcmp(szNameBuf, pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
|
|
for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) {
|
|
TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc];
|
|
int pc;
|
|
if(!TLB_str_memcmp(szNameBuf, pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
|
|
for(pc=0; pc < pFInfo->funcdesc.cParams; pc++){
|
|
if(!TLB_str_memcmp(szNameBuf, pFInfo->pParamDesc[pc].Name, nNameBufLen))
|
|
goto ITypeLib2_fnIsName_exit;
|
|
}
|
|
}
|
|
for(vrc = 0; vrc < pTInfo->typeattr.cVars; ++vrc){
|
|
TLBVarDesc *pVInfo = &pTInfo->vardescs[vrc];
|
|
if(!TLB_str_memcmp(szNameBuf, pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit;
|
|
}
|
|
|
|
}
|
|
*pfName=FALSE;
|
|
|
|
ITypeLib2_fnIsName_exit:
|
|
TRACE("(%p)slow! search for %s: %sfound!\n", This,
|
|
debugstr_w(szNameBuf), *pfName ? "" : "NOT ");
|
|
|
|
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.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnFindName(
|
|
ITypeLib2 *iface,
|
|
LPOLESTR name,
|
|
ULONG hash,
|
|
ITypeInfo **ppTInfo,
|
|
MEMBERID *memid,
|
|
UINT16 *found)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
int tic;
|
|
UINT count = 0;
|
|
UINT len;
|
|
|
|
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; count < *found && tic < This->TypeInfoCount; ++tic) {
|
|
ITypeInfoImpl *pTInfo = This->typeinfos[tic];
|
|
TLBVarDesc *var;
|
|
UINT fdc;
|
|
|
|
if(!TLB_str_memcmp(name, pTInfo->Name, len)) {
|
|
memid[count] = MEMBERID_NIL;
|
|
goto ITypeLib2_fnFindName_exit;
|
|
}
|
|
|
|
for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) {
|
|
TLBFuncDesc *func = &pTInfo->funcdescs[fdc];
|
|
|
|
if(!TLB_str_memcmp(name, func->Name, len)) {
|
|
memid[count] = func->funcdesc.memid;
|
|
goto ITypeLib2_fnFindName_exit;
|
|
}
|
|
}
|
|
|
|
var = TLB_get_vardesc_by_name(pTInfo->vardescs, pTInfo->typeattr.cVars, name);
|
|
if (var) {
|
|
memid[count] = var->vardesc.memid;
|
|
goto ITypeLib2_fnFindName_exit;
|
|
}
|
|
|
|
continue;
|
|
ITypeLib2_fnFindName_exit:
|
|
ITypeInfo2_AddRef(&pTInfo->ITypeInfo2_iface);
|
|
ppTInfo[count] = (ITypeInfo *)&pTInfo->ITypeInfo2_iface;
|
|
count++;
|
|
}
|
|
TRACE("found %d typeinfos\n", count);
|
|
|
|
*found = count;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeLib::ReleaseTLibAttr
|
|
*
|
|
* Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr.
|
|
*
|
|
*/
|
|
static VOID WINAPI ITypeLib2_fnReleaseTLibAttr(
|
|
ITypeLib2 *iface,
|
|
TLIBATTR *pTLibAttr)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
TRACE("(%p)->(%p)\n", This, pTLibAttr);
|
|
heap_free(pTLibAttr);
|
|
}
|
|
|
|
/* ITypeLib2::GetCustData
|
|
*
|
|
* gets the custom data
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetCustData(
|
|
ITypeLib2 * iface,
|
|
REFGUID guid,
|
|
VARIANT *pVarVal)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
TLBCustData *pCData;
|
|
|
|
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(guid), pVarVal);
|
|
|
|
pCData = TLB_get_custdata_by_guid(&This->custdata_list, guid);
|
|
if(!pCData)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
VariantInit(pVarVal);
|
|
VariantCopy(pVarVal, &pCData->data);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeLib2::GetLibStatistics
|
|
*
|
|
* Returns statistics about a type library that are required for efficient
|
|
* sizing of hash tables.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetLibStatistics(
|
|
ITypeLib2 * iface,
|
|
ULONG *pcUniqueNames,
|
|
ULONG *pcchUniqueNames)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
|
|
FIXME("(%p): stub!\n", This);
|
|
|
|
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.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetDocumentation2(
|
|
ITypeLib2 * iface,
|
|
INT index,
|
|
LCID lcid,
|
|
BSTR *pbstrHelpString,
|
|
DWORD *pdwHelpStringContext,
|
|
BSTR *pbstrHelpStringDll)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
HRESULT result;
|
|
ITypeInfo *pTInfo;
|
|
|
|
FIXME("(%p) index %d lcid %d half implemented stub!\n", This, index, lcid);
|
|
|
|
/* the help string should be obtained from the helpstringdll,
|
|
* using the _DLLGetDocumentation function, based on the supplied
|
|
* lcid. Nice to do sometime...
|
|
*/
|
|
if(index<0)
|
|
{
|
|
/* documentation for the typelib */
|
|
if(pbstrHelpString)
|
|
*pbstrHelpString=SysAllocString(TLB_get_bstr(This->DocString));
|
|
if(pdwHelpStringContext)
|
|
*pdwHelpStringContext=This->dwHelpContext;
|
|
if(pbstrHelpStringDll)
|
|
*pbstrHelpStringDll=SysAllocString(TLB_get_bstr(This->HelpStringDll));
|
|
|
|
result = S_OK;
|
|
}
|
|
else
|
|
{
|
|
/* for a typeinfo */
|
|
result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo);
|
|
|
|
if(SUCCEEDED(result))
|
|
{
|
|
ITypeInfo2 * pTInfo2;
|
|
result = ITypeInfo_QueryInterface(pTInfo,
|
|
&IID_ITypeInfo2,
|
|
(LPVOID*) &pTInfo2);
|
|
|
|
if(SUCCEEDED(result))
|
|
{
|
|
result = ITypeInfo2_GetDocumentation2(pTInfo2,
|
|
MEMBERID_NIL,
|
|
lcid,
|
|
pbstrHelpString,
|
|
pdwHelpStringContext,
|
|
pbstrHelpStringDll);
|
|
|
|
ITypeInfo2_Release(pTInfo2);
|
|
}
|
|
|
|
ITypeInfo_Release(pTInfo);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
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 = CoTaskMemAlloc(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 = *TLB_get_guid_null(pCData->guid);
|
|
VariantCopy(&cdi->varValue, &pCData->data);
|
|
++cdi;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* ITypeLib2::GetAllCustData
|
|
*
|
|
* Gets all custom data items for the library.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeLib2_fnGetAllCustData(
|
|
ITypeLib2 * iface,
|
|
CUSTDATA *pCustData)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeLib2(iface);
|
|
TRACE("(%p)->(%p)\n", This, pCustData);
|
|
return TLB_copy_all_custdata(&This->custdata_list, pCustData);
|
|
}
|
|
|
|
static const ITypeLib2Vtbl tlbvt = {
|
|
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
|
|
};
|
|
|
|
|
|
static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeComp(iface);
|
|
|
|
return ITypeLib2_QueryInterface(&This->ITypeLib2_iface, riid, ppv);
|
|
}
|
|
|
|
static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeComp(iface);
|
|
|
|
return ITypeLib2_AddRef(&This->ITypeLib2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeComp(iface);
|
|
|
|
return ITypeLib2_Release(&This->ITypeLib2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI ITypeLibComp_fnBind(
|
|
ITypeComp * iface,
|
|
OLECHAR * szName,
|
|
ULONG lHash,
|
|
WORD wFlags,
|
|
ITypeInfo ** ppTInfo,
|
|
DESCKIND * pDescKind,
|
|
BINDPTR * pBindPtr)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeComp(iface);
|
|
BOOL typemismatch = FALSE;
|
|
int i;
|
|
|
|
TRACE("(%p)->(%s, 0x%x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
|
|
|
|
*pDescKind = DESCKIND_NONE;
|
|
pBindPtr->lptcomp = NULL;
|
|
*ppTInfo = NULL;
|
|
|
|
for(i = 0; i < This->TypeInfoCount; ++i){
|
|
ITypeInfoImpl *pTypeInfo = This->typeinfos[i];
|
|
TRACE("testing %s\n", debugstr_w(TLB_get_bstr(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->str, szName))
|
|
{
|
|
*pDescKind = DESCKIND_TYPECOMP;
|
|
pBindPtr->lptcomp = &pTypeInfo->ITypeComp_iface;
|
|
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 = &pTypeInfo->ITypeComp_iface;
|
|
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;
|
|
}
|
|
else if (hr == TYPE_E_TYPEMISMATCH)
|
|
typemismatch = TRUE;
|
|
}
|
|
|
|
if ((pTypeInfo->typeattr.typekind == TKIND_COCLASS) &&
|
|
(pTypeInfo->typeattr.wTypeFlags & TYPEFLAG_FAPPOBJECT))
|
|
{
|
|
ITypeComp *pSubTypeComp = &pTypeInfo->ITypeComp_iface;
|
|
HRESULT hr;
|
|
ITypeInfo *subtypeinfo;
|
|
BINDPTR subbindptr;
|
|
DESCKIND subdesckind;
|
|
|
|
hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags,
|
|
&subtypeinfo, &subdesckind, &subbindptr);
|
|
if (SUCCEEDED(hr) && (subdesckind != DESCKIND_NONE))
|
|
{
|
|
TYPEDESC tdesc_appobject;
|
|
const VARDESC vardesc_appobject =
|
|
{
|
|
-2, /* memid */
|
|
NULL, /* lpstrSchema */
|
|
{
|
|
0 /* oInst */
|
|
},
|
|
{
|
|
/* ELEMDESC */
|
|
{
|
|
/* TYPEDESC */
|
|
{
|
|
&tdesc_appobject
|
|
},
|
|
VT_PTR
|
|
},
|
|
},
|
|
0, /* wVarFlags */
|
|
VAR_STATIC /* varkind */
|
|
};
|
|
|
|
tdesc_appobject.u.hreftype = pTypeInfo->hreftype;
|
|
tdesc_appobject.vt = VT_USERDEFINED;
|
|
|
|
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);
|
|
|
|
if (pTypeInfo->hreftype == -1)
|
|
FIXME("no hreftype for interface %p\n", pTypeInfo);
|
|
|
|
hr = TLB_AllocAndInitVarDesc(&vardesc_appobject, &pBindPtr->lpvardesc);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
*pDescKind = DESCKIND_IMPLICITAPPOBJ;
|
|
*ppTInfo = (ITypeInfo *)&pTypeInfo->ITypeInfo2_iface;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
return S_OK;
|
|
}
|
|
else if (hr == TYPE_E_TYPEMISMATCH)
|
|
typemismatch = TRUE;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static HRESULT WINAPI ITypeLibComp_fnBindType(
|
|
ITypeComp * iface,
|
|
OLECHAR * szName,
|
|
ULONG lHash,
|
|
ITypeInfo ** ppTInfo,
|
|
ITypeComp ** ppTComp)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ITypeComp(iface);
|
|
ITypeInfoImpl *info;
|
|
|
|
TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
|
|
|
|
if(!szName || !ppTInfo || !ppTComp)
|
|
return E_INVALIDARG;
|
|
|
|
info = TLB_get_typeinfo_by_name(This->typeinfos, This->TypeInfoCount, szName);
|
|
if(!info){
|
|
*ppTInfo = NULL;
|
|
*ppTComp = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
*ppTInfo = (ITypeInfo *)&info->ITypeInfo2_iface;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
*ppTComp = &info->ITypeComp_iface;
|
|
ITypeComp_AddRef(*ppTComp);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const ITypeCompVtbl tlbtcvt =
|
|
{
|
|
|
|
ITypeLibComp_fnQueryInterface,
|
|
ITypeLibComp_fnAddRef,
|
|
ITypeLibComp_fnRelease,
|
|
|
|
ITypeLibComp_fnBind,
|
|
ITypeLibComp_fnBindType
|
|
};
|
|
|
|
/*================== ITypeInfo(2) Methods ===================================*/
|
|
static ITypeInfoImpl* ITypeInfoImpl_Constructor(void)
|
|
{
|
|
ITypeInfoImpl *pTypeInfoImpl;
|
|
|
|
pTypeInfoImpl = heap_alloc_zero(sizeof(ITypeInfoImpl));
|
|
if (pTypeInfoImpl)
|
|
{
|
|
pTypeInfoImpl->ITypeInfo2_iface.lpVtbl = &tinfvt;
|
|
pTypeInfoImpl->ITypeComp_iface.lpVtbl = &tcompvt;
|
|
pTypeInfoImpl->ICreateTypeInfo2_iface.lpVtbl = &CreateTypeInfo2Vtbl;
|
|
pTypeInfoImpl->ref = 0;
|
|
pTypeInfoImpl->hreftype = -1;
|
|
pTypeInfoImpl->typeattr.memidConstructor = MEMBERID_NIL;
|
|
pTypeInfoImpl->typeattr.memidDestructor = MEMBERID_NIL;
|
|
pTypeInfoImpl->pcustdata_list = &pTypeInfoImpl->custdata_list;
|
|
list_init(pTypeInfoImpl->pcustdata_list);
|
|
}
|
|
TRACE("(%p)\n", pTypeInfoImpl);
|
|
return pTypeInfoImpl;
|
|
}
|
|
|
|
/* ITypeInfo::QueryInterface
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnQueryInterface(
|
|
ITypeInfo2 *iface,
|
|
REFIID riid,
|
|
VOID **ppvObject)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
|
|
TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid));
|
|
|
|
*ppvObject=NULL;
|
|
if(IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid,&IID_ITypeInfo)||
|
|
IsEqualIID(riid,&IID_ITypeInfo2))
|
|
*ppvObject = &This->ITypeInfo2_iface;
|
|
else if(IsEqualIID(riid, &IID_ICreateTypeInfo) ||
|
|
IsEqualIID(riid, &IID_ICreateTypeInfo2))
|
|
*ppvObject = &This->ICreateTypeInfo2_iface;
|
|
else if(IsEqualIID(riid, &IID_ITypeComp))
|
|
*ppvObject = &This->ITypeComp_iface;
|
|
|
|
if(*ppvObject){
|
|
IUnknown_AddRef((IUnknown*)*ppvObject);
|
|
TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject);
|
|
return S_OK;
|
|
}
|
|
TRACE("-- Interface: E_NOINTERFACE\n");
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
/* ITypeInfo::AddRef
|
|
*/
|
|
static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
ULONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p)->ref is %u\n",This, ref);
|
|
|
|
if (ref == 1 /* incremented from 0 */)
|
|
ITypeLib2_AddRef(&This->pTypeLib->ITypeLib2_iface);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This)
|
|
{
|
|
UINT i;
|
|
|
|
TRACE("destroying ITypeInfo(%p)\n",This);
|
|
|
|
for (i = 0; i < This->typeattr.cFuncs; ++i)
|
|
{
|
|
int j;
|
|
TLBFuncDesc *pFInfo = &This->funcdescs[i];
|
|
for(j = 0; j < pFInfo->funcdesc.cParams; j++)
|
|
{
|
|
ELEMDESC *elemdesc = &pFInfo->funcdesc.lprgelemdescParam[j];
|
|
if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
|
|
VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
|
|
TLB_FreeCustData(&pFInfo->pParamDesc[j].custdata_list);
|
|
}
|
|
heap_free(pFInfo->funcdesc.lprgelemdescParam);
|
|
heap_free(pFInfo->pParamDesc);
|
|
TLB_FreeCustData(&pFInfo->custdata_list);
|
|
}
|
|
heap_free(This->funcdescs);
|
|
|
|
for(i = 0; i < This->typeattr.cVars; ++i)
|
|
{
|
|
TLBVarDesc *pVInfo = &This->vardescs[i];
|
|
if (pVInfo->vardesc_create) {
|
|
TLB_FreeVarDesc(pVInfo->vardesc_create);
|
|
} else if (pVInfo->vardesc.varkind == VAR_CONST) {
|
|
VariantClear(pVInfo->vardesc.u.lpvarValue);
|
|
heap_free(pVInfo->vardesc.u.lpvarValue);
|
|
}
|
|
TLB_FreeCustData(&pVInfo->custdata_list);
|
|
}
|
|
heap_free(This->vardescs);
|
|
|
|
if(This->impltypes){
|
|
for (i = 0; i < This->typeattr.cImplTypes; ++i){
|
|
TLBImplType *pImpl = &This->impltypes[i];
|
|
TLB_FreeCustData(&pImpl->custdata_list);
|
|
}
|
|
heap_free(This->impltypes);
|
|
}
|
|
|
|
TLB_FreeCustData(&This->custdata_list);
|
|
|
|
heap_free(This);
|
|
}
|
|
|
|
/* ITypeInfo::Release
|
|
*/
|
|
static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
ULONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p)->(%u)\n",This, ref);
|
|
|
|
if (!ref)
|
|
{
|
|
BOOL not_attached_to_typelib = This->not_attached_to_typelib;
|
|
ITypeLib2_Release(&This->pTypeLib->ITypeLib2_iface);
|
|
if (not_attached_to_typelib)
|
|
heap_free(This);
|
|
/* otherwise This will be freed when typelib is freed */
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
/* ITypeInfo::GetTypeAttr
|
|
*
|
|
* Retrieves a TYPEATTR structure that contains the attributes of the type
|
|
* description.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface,
|
|
LPTYPEATTR *ppTypeAttr)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
SIZE_T size;
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
size = sizeof(**ppTypeAttr);
|
|
if (This->typeattr.typekind == TKIND_ALIAS && This->tdescAlias)
|
|
size += TLB_SizeTypeDesc(This->tdescAlias, FALSE);
|
|
|
|
*ppTypeAttr = heap_alloc(size);
|
|
if (!*ppTypeAttr)
|
|
return E_OUTOFMEMORY;
|
|
|
|
**ppTypeAttr = This->typeattr;
|
|
(*ppTypeAttr)->guid = *TLB_get_guid_null(This->guid);
|
|
|
|
if (This->tdescAlias)
|
|
TLB_CopyTypeDesc(&(*ppTypeAttr)->tdescAlias, This->tdescAlias, *ppTypeAttr + 1);
|
|
|
|
if((*ppTypeAttr)->typekind == TKIND_DISPATCH) {
|
|
/* This should include all the inherited funcs */
|
|
(*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / This->pTypeLib->ptr_size;
|
|
/* This is always the size of IDispatch's vtbl */
|
|
(*ppTypeAttr)->cbSizeVft = sizeof(IDispatchVtbl);
|
|
(*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION;
|
|
}
|
|
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.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface,
|
|
ITypeComp * *ppTComp)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, ppTComp);
|
|
|
|
*ppTComp = &This->ITypeComp_iface;
|
|
ITypeComp_AddRef(*ppTComp);
|
|
return S_OK;
|
|
}
|
|
|
|
static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
|
|
{
|
|
SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
|
|
if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
|
|
size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
|
|
return size;
|
|
}
|
|
|
|
static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
|
|
{
|
|
*dest = *src;
|
|
*buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
|
|
if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
|
|
{
|
|
const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
|
|
PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
|
|
*buffer += sizeof(PARAMDESCEX);
|
|
*pparamdescex_dest = *pparamdescex_src;
|
|
pparamdescex_dest->cBytes = sizeof(PARAMDESCEX);
|
|
VariantInit(&pparamdescex_dest->varDefaultValue);
|
|
return VariantCopy(&pparamdescex_dest->varDefaultValue,
|
|
(VARIANTARG *)&pparamdescex_src->varDefaultValue);
|
|
}
|
|
else
|
|
dest->u.paramdesc.pparamdescex = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT TLB_SanitizeBSTR(BSTR str)
|
|
{
|
|
UINT len = SysStringLen(str), i;
|
|
for (i = 0; i < len; ++i)
|
|
if (str[i] > 0x7f)
|
|
str[i] = '?';
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT TLB_SanitizeVariant(VARIANT *var)
|
|
{
|
|
if (V_VT(var) == VT_INT)
|
|
return VariantChangeType(var, var, 0, VT_I4);
|
|
else if (V_VT(var) == VT_UINT)
|
|
return VariantChangeType(var, var, 0, VT_UI4);
|
|
else if (V_VT(var) == VT_BSTR)
|
|
return TLB_SanitizeBSTR(V_BSTR(var));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
|
|
{
|
|
if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
|
|
VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
|
|
}
|
|
|
|
static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
|
|
{
|
|
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;
|
|
|
|
*dest = *src;
|
|
if (dispinterface) /* overwrite funckind */
|
|
dest->funckind = FUNC_DISPATCH;
|
|
buffer = (char *)(dest + 1);
|
|
|
|
dest->oVft = dest->oVft & 0xFFFC;
|
|
|
|
if (dest->cScodes) {
|
|
dest->lprgscode = (SCODE *)buffer;
|
|
memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
|
|
buffer += sizeof(*src->lprgscode) * src->cScodes;
|
|
} else
|
|
dest->lprgscode = NULL;
|
|
|
|
hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
|
|
if (FAILED(hr))
|
|
{
|
|
SysFreeString((BSTR)dest);
|
|
return hr;
|
|
}
|
|
|
|
if (dest->cParams) {
|
|
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;
|
|
}
|
|
} else
|
|
dest->lprgelemdescParam = NULL;
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
*dest_ptr = dest;
|
|
return S_OK;
|
|
}
|
|
|
|
static void TLB_FreeVarDesc(VARDESC *var_desc)
|
|
{
|
|
TLB_FreeElemDesc(&var_desc->elemdescVar);
|
|
if (var_desc->varkind == VAR_CONST)
|
|
VariantClear(var_desc->u.lpvarValue);
|
|
SysFreeString((BSTR)var_desc);
|
|
}
|
|
|
|
HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo(iface);
|
|
|
|
if (index >= This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
*ppFuncDesc = &This->funcdescs[index].funcdesc;
|
|
return S_OK;
|
|
}
|
|
|
|
/* internal function to make the inherited interfaces' methods appear
|
|
* part of the interface */
|
|
static HRESULT ITypeInfoImpl_GetInternalDispatchFuncDesc( ITypeInfo *iface,
|
|
UINT index, const FUNCDESC **ppFuncDesc, UINT *funcs, UINT *hrefoffset)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo(iface);
|
|
HRESULT hr;
|
|
UINT implemented_funcs = 0;
|
|
|
|
if (funcs)
|
|
*funcs = 0;
|
|
else
|
|
*hrefoffset = DISPATCH_HREF_OFFSET;
|
|
|
|
if(This->impltypes)
|
|
{
|
|
ITypeInfo *pSubTypeInfo;
|
|
UINT sub_funcs;
|
|
|
|
hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = ITypeInfoImpl_GetInternalDispatchFuncDesc(pSubTypeInfo,
|
|
index,
|
|
ppFuncDesc,
|
|
&sub_funcs, hrefoffset);
|
|
implemented_funcs += sub_funcs;
|
|
ITypeInfo_Release(pSubTypeInfo);
|
|
if (SUCCEEDED(hr))
|
|
return hr;
|
|
*hrefoffset += DISPATCH_HREF_OFFSET;
|
|
}
|
|
|
|
if (funcs)
|
|
*funcs = implemented_funcs + This->typeattr.cFuncs;
|
|
else
|
|
*hrefoffset = 0;
|
|
|
|
if (index < implemented_funcs)
|
|
return E_INVALIDARG;
|
|
return ITypeInfoImpl_GetInternalFuncDesc(iface, index - implemented_funcs,
|
|
ppFuncDesc);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/* ITypeInfo::GetFuncDesc
|
|
*
|
|
* Retrieves the FUNCDESC structure that contains information about a
|
|
* specified function.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index,
|
|
LPFUNCDESC *ppFuncDesc)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
const FUNCDESC *internal_funcdesc;
|
|
HRESULT hr;
|
|
UINT hrefoffset = 0;
|
|
|
|
TRACE("(%p) index %d\n", This, index);
|
|
|
|
if (!ppFuncDesc)
|
|
return E_INVALIDARG;
|
|
|
|
if (This->needs_layout)
|
|
ICreateTypeInfo2_LayOut(&This->ICreateTypeInfo2_iface);
|
|
|
|
if (This->typeattr.typekind == TKIND_DISPATCH)
|
|
hr = ITypeInfoImpl_GetInternalDispatchFuncDesc((ITypeInfo *)iface, index,
|
|
&internal_funcdesc, NULL,
|
|
&hrefoffset);
|
|
else
|
|
hr = ITypeInfoImpl_GetInternalFuncDesc((ITypeInfo *)iface, index,
|
|
&internal_funcdesc);
|
|
if (FAILED(hr))
|
|
{
|
|
WARN("description for function %d not found\n", index);
|
|
return hr;
|
|
}
|
|
|
|
hr = TLB_AllocAndInitFuncDesc(
|
|
internal_funcdesc,
|
|
ppFuncDesc,
|
|
This->typeattr.typekind == TKIND_DISPATCH);
|
|
|
|
if ((This->typeattr.typekind == TKIND_DISPATCH) && hrefoffset)
|
|
ITypeInfoImpl_FuncDescAddHrefOffset(*ppFuncDesc, hrefoffset);
|
|
|
|
TRACE("-- 0x%08x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT TLB_AllocAndInitVarDesc( const VARDESC *src, VARDESC **dest_ptr )
|
|
{
|
|
VARDESC *dest;
|
|
char *buffer;
|
|
SIZE_T size = sizeof(*src);
|
|
HRESULT hr;
|
|
|
|
if (src->lpstrSchema) size += (strlenW(src->lpstrSchema) + 1) * sizeof(WCHAR);
|
|
if (src->varkind == VAR_CONST)
|
|
size += sizeof(VARIANT);
|
|
size += TLB_SizeElemDesc(&src->elemdescVar);
|
|
|
|
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);
|
|
VariantInit(dest->u.lpvarValue);
|
|
hr = VariantCopy(dest->u.lpvarValue, src->u.lpvarValue);
|
|
if (FAILED(hr))
|
|
{
|
|
SysFreeString((BSTR)dest);
|
|
return hr;
|
|
}
|
|
}
|
|
hr = TLB_CopyElemDesc(&src->elemdescVar, &dest->elemdescVar, &buffer);
|
|
if (FAILED(hr))
|
|
{
|
|
if (src->varkind == VAR_CONST)
|
|
VariantClear(dest->u.lpvarValue);
|
|
SysFreeString((BSTR)dest);
|
|
return hr;
|
|
}
|
|
*dest_ptr = dest;
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo::GetVarDesc
|
|
*
|
|
* Retrieves a VARDESC structure that describes the specified variable.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index,
|
|
LPVARDESC *ppVarDesc)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
const TLBVarDesc *pVDesc = &This->vardescs[index];
|
|
|
|
TRACE("(%p) index %d\n", This, index);
|
|
|
|
if(index >= This->typeattr.cVars)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
if (This->needs_layout)
|
|
ICreateTypeInfo2_LayOut(&This->ICreateTypeInfo2_iface);
|
|
|
|
return TLB_AllocAndInitVarDesc(&pVDesc->vardesc, ppVarDesc);
|
|
}
|
|
|
|
/* 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.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid,
|
|
BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
const TLBFuncDesc *pFDesc;
|
|
const TLBVarDesc *pVDesc;
|
|
int i;
|
|
TRACE("(%p) memid=0x%08x Maxname=%d\n", This, memid, cMaxNames);
|
|
|
|
if(!rgBstrNames)
|
|
return E_INVALIDARG;
|
|
|
|
*pcNames = 0;
|
|
|
|
pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
|
|
if(pFDesc)
|
|
{
|
|
if(!cMaxNames || !pFDesc->Name)
|
|
return S_OK;
|
|
|
|
*rgBstrNames = SysAllocString(TLB_get_bstr(pFDesc->Name));
|
|
++(*pcNames);
|
|
|
|
for(i = 0; i < pFDesc->funcdesc.cParams; ++i){
|
|
if(*pcNames >= cMaxNames || !pFDesc->pParamDesc[i].Name)
|
|
return S_OK;
|
|
rgBstrNames[*pcNames] = SysAllocString(TLB_get_bstr(pFDesc->pParamDesc[i].Name));
|
|
++(*pcNames);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
|
|
if(pVDesc)
|
|
{
|
|
*rgBstrNames=SysAllocString(TLB_get_bstr(pVDesc->Name));
|
|
*pcNames=1;
|
|
}
|
|
else
|
|
{
|
|
if(This->impltypes &&
|
|
(This->typeattr.typekind == TKIND_INTERFACE || This->typeattr.typekind == TKIND_DISPATCH)) {
|
|
/* recursive search */
|
|
ITypeInfo *pTInfo;
|
|
HRESULT result;
|
|
result = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
|
|
if(SUCCEEDED(result))
|
|
{
|
|
result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames);
|
|
ITypeInfo_Release(pTInfo);
|
|
return result;
|
|
}
|
|
WARN("Could not search inherited interface!\n");
|
|
}
|
|
else
|
|
{
|
|
WARN("no names found\n");
|
|
}
|
|
*pcNames=0;
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
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.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType(
|
|
ITypeInfo2 *iface,
|
|
UINT index,
|
|
HREFTYPE *pRefType)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE("(%p) index %d\n", This, index);
|
|
if (TRACE_ON(ole)) dump_TypeInfo(This);
|
|
|
|
if(index==(UINT)-1)
|
|
{
|
|
/* only valid on dual interfaces;
|
|
retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH
|
|
*/
|
|
|
|
if (This->typeattr.wTypeFlags & TYPEFLAG_FDUAL)
|
|
{
|
|
*pRefType = -2;
|
|
}
|
|
else
|
|
{
|
|
hr = TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
if(index >= This->typeattr.cImplTypes)
|
|
hr = TYPE_E_ELEMENTNOTFOUND;
|
|
else{
|
|
*pRefType = This->impltypes[index].hRef;
|
|
if (This->typeattr.typekind == TKIND_INTERFACE)
|
|
*pRefType |= 0x2;
|
|
}
|
|
}
|
|
|
|
if(TRACE_ON(ole))
|
|
{
|
|
if(SUCCEEDED(hr))
|
|
TRACE("SUCCESS -- hRef = 0x%08x\n", *pRefType );
|
|
else
|
|
TRACE("FAILURE -- hresult = 0x%08x\n", hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* ITypeInfo::GetImplTypeFlags
|
|
*
|
|
* Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface
|
|
* or base interface in a type description.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface,
|
|
UINT index, INT *pImplTypeFlags)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
|
|
TRACE("(%p) index %d\n", This, index);
|
|
|
|
if(!pImplTypeFlags)
|
|
return E_INVALIDARG;
|
|
|
|
if(This->typeattr.typekind == TKIND_DISPATCH && index == 0){
|
|
*pImplTypeFlags = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
if(index >= This->typeattr.cImplTypes)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
*pImplTypeFlags = This->impltypes[index].implflags;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* GetIDsOfNames
|
|
* Maps between member names and member IDs, and parameter names and
|
|
* parameter IDs.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface,
|
|
LPOLESTR *rgszNames, UINT cNames, MEMBERID *pMemId)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
const TLBVarDesc *pVDesc;
|
|
HRESULT ret=S_OK;
|
|
UINT i, fdc;
|
|
|
|
TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames),
|
|
cNames);
|
|
|
|
/* init out parameters in case of failure */
|
|
for (i = 0; i < cNames; i++)
|
|
pMemId[i] = MEMBERID_NIL;
|
|
|
|
for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc) {
|
|
int j;
|
|
const TLBFuncDesc *pFDesc = &This->funcdescs[fdc];
|
|
if(!lstrcmpiW(*rgszNames, TLB_get_bstr(pFDesc->Name))) {
|
|
if(cNames) *pMemId=pFDesc->funcdesc.memid;
|
|
for(i=1; i < cNames; i++){
|
|
for(j=0; j<pFDesc->funcdesc.cParams; j++)
|
|
if(!lstrcmpiW(rgszNames[i],TLB_get_bstr(pFDesc->pParamDesc[j].Name)))
|
|
break;
|
|
if( j<pFDesc->funcdesc.cParams)
|
|
pMemId[i]=j;
|
|
else
|
|
ret=DISP_E_UNKNOWNNAME;
|
|
};
|
|
TRACE("-- 0x%08x\n", ret);
|
|
return ret;
|
|
}
|
|
}
|
|
pVDesc = TLB_get_vardesc_by_name(This->vardescs, This->typeattr.cVars, *rgszNames);
|
|
if(pVDesc){
|
|
if(cNames)
|
|
*pMemId = pVDesc->vardesc.memid;
|
|
return ret;
|
|
}
|
|
/* not found, see if it can be found in an inherited interface */
|
|
if(This->impltypes) {
|
|
/* recursive search */
|
|
ITypeInfo *pTInfo;
|
|
ret = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
|
|
if(SUCCEEDED(ret)){
|
|
ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId );
|
|
ITypeInfo_Release(pTInfo);
|
|
return ret;
|
|
}
|
|
WARN("Could not search inherited interface!\n");
|
|
} else
|
|
WARN("no names found\n");
|
|
return DISP_E_UNKNOWNNAME;
|
|
}
|
|
|
|
|
|
#ifdef __i386__
|
|
|
|
extern LONGLONG call_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
|
|
extern double call_double_method( void *func, int nb_args, const DWORD *args, int *stack_offset );
|
|
__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"
|
|
"movl %esp,%edi\n\t"
|
|
"shll $2,%edx\n\t"
|
|
"jz 1f\n\t"
|
|
"subl %edx,%edi\n\t"
|
|
"andl $~15,%edi\n\t"
|
|
"movl %edi,%esp\n\t"
|
|
"movl 12(%ebp),%ecx\n\t"
|
|
"movl 16(%ebp),%esi\n\t"
|
|
"cld\n\t"
|
|
"rep; movsl\n"
|
|
"1:\tcall *8(%ebp)\n\t"
|
|
"subl %esp,%edi\n\t"
|
|
"movl 20(%ebp),%ecx\n\t"
|
|
"movl %edi,(%ecx)\n\t"
|
|
"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" )
|
|
__ASM_GLOBAL_FUNC( call_double_method,
|
|
"jmp " __ASM_NAME("call_method") )
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
extern DWORD_PTR CDECL call_method( void *func, int nb_args, const DWORD_PTR *args );
|
|
extern double CDECL call_double_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"
|
|
"movq 0(%rsp),%xmm0\n\t"
|
|
"movq 8(%rsp),%xmm1\n\t"
|
|
"movq 16(%rsp),%xmm2\n\t"
|
|
"movq 24(%rsp),%xmm3\n\t"
|
|
"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")
|
|
__ASM_GLOBAL_FUNC( call_double_method,
|
|
"jmp " __ASM_NAME("call_method") )
|
|
|
|
#elif defined(__arm__)
|
|
|
|
extern LONGLONG CDECL call_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
|
|
extern float CDECL call_float_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
|
|
extern double CDECL call_double_method( void *func, int nb_stk_args, const DWORD *stk_args, const DWORD *reg_args );
|
|
__ASM_GLOBAL_FUNC( call_method,
|
|
/* r0 = *func
|
|
* r1 = nb_stk_args
|
|
* r2 = *stk_args (pointer to 'nb_stk_args' DWORD values to push on stack)
|
|
* r3 = *reg_args (pointer to 8, 64-bit d0-d7 (double) values OR as 16, 32-bit s0-s15 (float) values, followed by 4, 32-bit (DWORD) r0-r3 values)
|
|
*/
|
|
|
|
"push {fp, lr}\n\t" /* Save frame pointer and return address (stack still aligned to 8 bytes) */
|
|
"mov fp, sp\n\t" /* Save stack pointer as our frame for cleaning the stack on return */
|
|
|
|
"lsls r1, r1, #2\n\t" /* r1 = nb_stk_args * sizeof(DWORD) */
|
|
"beq 1f\n\t" /* Skip allocation if no stack args */
|
|
"add r2, r2, r1\n" /* Calculate ending address of incoming stack data */
|
|
"2:\tldr ip, [r2, #-4]!\n\t" /* Get next value */
|
|
"str ip, [sp, #-4]!\n\t" /* Push it on the stack */
|
|
"subs r1, r1, #4\n\t" /* Decrement count */
|
|
"bgt 2b\n\t" /* Loop till done */
|
|
|
|
"1:\n\t"
|
|
#ifndef __SOFTFP__
|
|
"vldm r3!, {s0-s15}\n\t" /* Load the s0-s15/d0-d7 arguments */
|
|
#endif
|
|
"mov ip, r0\n\t" /* Save the function call address to ip before we nuke r0 with arguments to pass */
|
|
"ldm r3, {r0-r3}\n\t" /* Load the r0-r3 arguments */
|
|
|
|
"blx ip\n\t" /* Call the target function */
|
|
|
|
"mov sp, fp\n\t" /* Clean the stack using fp */
|
|
"pop {fp, pc}\n\t" /* Restore fp and return */
|
|
)
|
|
__ASM_GLOBAL_FUNC( call_float_method,
|
|
"b " __ASM_NAME("call_method") )
|
|
__ASM_GLOBAL_FUNC( call_double_method,
|
|
"b " __ASM_NAME("call_method") )
|
|
|
|
#endif /* __arm__ */
|
|
|
|
static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ITypeInfo *tinfo2 = NULL;
|
|
TYPEATTR *tattr = NULL;
|
|
|
|
hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
|
|
if (hr)
|
|
{
|
|
ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED, "
|
|
"hr = 0x%08x\n",
|
|
tdesc->u.hreftype, hr);
|
|
return hr;
|
|
}
|
|
hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
|
|
if (hr)
|
|
{
|
|
ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08x\n", hr);
|
|
ITypeInfo_Release(tinfo2);
|
|
return hr;
|
|
}
|
|
|
|
switch (tattr->typekind)
|
|
{
|
|
case TKIND_ENUM:
|
|
*vt |= VT_I4;
|
|
break;
|
|
|
|
case TKIND_ALIAS:
|
|
hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
|
|
break;
|
|
|
|
case TKIND_INTERFACE:
|
|
if (tattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
|
|
*vt |= VT_DISPATCH;
|
|
else
|
|
*vt |= VT_UNKNOWN;
|
|
break;
|
|
|
|
case TKIND_DISPATCH:
|
|
*vt |= VT_DISPATCH;
|
|
break;
|
|
|
|
case TKIND_COCLASS:
|
|
*vt |= VT_DISPATCH;
|
|
break;
|
|
|
|
case TKIND_RECORD:
|
|
FIXME("TKIND_RECORD unhandled.\n");
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
|
|
case TKIND_UNION:
|
|
FIXME("TKIND_UNION unhandled.\n");
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
|
|
default:
|
|
FIXME("TKIND %d unhandled.\n",tattr->typekind);
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
}
|
|
ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
|
|
ITypeInfo_Release(tinfo2);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
/* enforce only one level of pointer indirection */
|
|
if (!(*vt & VT_BYREF) && !(*vt & VT_ARRAY) && (tdesc->vt == VT_PTR))
|
|
{
|
|
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;
|
|
const TYPEDESC *tdesc_userdefined = tdesc;
|
|
if (tdesc->vt == VT_PTR)
|
|
{
|
|
vt_userdefined = VT_BYREF;
|
|
tdesc_userdefined = tdesc->u.lptdesc;
|
|
}
|
|
hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
|
|
if ((hr == S_OK) &&
|
|
(((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
|
|
((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
|
|
{
|
|
*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;
|
|
case VT_VOID:
|
|
case VT_CARRAY:
|
|
case VT_PTR:
|
|
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);
|
|
break;
|
|
case VT_INT:
|
|
*vt |= VT_I4;
|
|
break;
|
|
case VT_UINT:
|
|
*vt |= VT_UI4;
|
|
break;
|
|
default:
|
|
*vt |= tdesc->vt;
|
|
break;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT get_iface_guid(ITypeInfo *tinfo, HREFTYPE href, GUID *guid)
|
|
{
|
|
ITypeInfo *tinfo2;
|
|
TYPEATTR *tattr;
|
|
HRESULT hres;
|
|
int flags, i;
|
|
|
|
hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
hres = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
|
|
if(FAILED(hres)) {
|
|
ITypeInfo_Release(tinfo2);
|
|
return hres;
|
|
}
|
|
|
|
switch(tattr->typekind) {
|
|
case TKIND_ALIAS:
|
|
hres = get_iface_guid(tinfo2, tattr->tdescAlias.u.hreftype, guid);
|
|
break;
|
|
|
|
case TKIND_INTERFACE:
|
|
case TKIND_DISPATCH:
|
|
*guid = tattr->guid;
|
|
break;
|
|
|
|
case TKIND_COCLASS:
|
|
for (i = 0; i < tattr->cImplTypes; i++)
|
|
{
|
|
ITypeInfo_GetImplTypeFlags(tinfo2, i, &flags);
|
|
if (flags & IMPLTYPEFLAG_FDEFAULT)
|
|
break;
|
|
}
|
|
|
|
if (i == tattr->cImplTypes)
|
|
i = 0;
|
|
|
|
hres = ITypeInfo_GetRefTypeOfImplType(tinfo2, i, &href);
|
|
if (SUCCEEDED(hres))
|
|
hres = get_iface_guid(tinfo2, href, guid);
|
|
break;
|
|
|
|
default:
|
|
ERR("Unexpected typekind %d\n", tattr->typekind);
|
|
hres = E_UNEXPECTED;
|
|
}
|
|
|
|
ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
|
|
ITypeInfo_Release(tinfo2);
|
|
return hres;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* DispCallFunc (OLEAUT32.@)
|
|
*
|
|
* Invokes a function of the specified calling convention, passing the
|
|
* 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
|
|
*
|
|
*/
|
|
HRESULT WINAPI
|
|
DispCallFunc(
|
|
void* pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals,
|
|
VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult)
|
|
{
|
|
#ifdef __i386__
|
|
int argspos = 0, stack_offset;
|
|
void *func;
|
|
UINT i;
|
|
DWORD *args;
|
|
|
|
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;
|
|
}
|
|
|
|
/* maximum size for an argument is sizeof(VARIANT) */
|
|
args = heap_alloc(sizeof(VARIANT) * cActuals + sizeof(DWORD) * 2 );
|
|
|
|
if (pvInstance)
|
|
{
|
|
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
|
func = vtable[oVft/sizeof(void *)];
|
|
args[argspos++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
|
|
}
|
|
else func = (void *)oVft;
|
|
|
|
switch (vtReturn)
|
|
{
|
|
case VT_DECIMAL:
|
|
case VT_VARIANT:
|
|
args[argspos++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
|
|
break;
|
|
case VT_HRESULT:
|
|
WARN("invalid return type %u\n", vtReturn);
|
|
heap_free( args );
|
|
return E_INVALIDARG;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < cActuals; i++)
|
|
{
|
|
VARIANT *arg = prgpvarg[i];
|
|
|
|
switch (prgvt[i])
|
|
{
|
|
case VT_EMPTY:
|
|
break;
|
|
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;
|
|
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
|
args[argspos++] = V_BOOL(arg);
|
|
break;
|
|
default:
|
|
args[argspos++] = V_UI4(arg);
|
|
break;
|
|
}
|
|
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
|
}
|
|
|
|
switch (vtReturn)
|
|
{
|
|
case VT_EMPTY:
|
|
case VT_DECIMAL:
|
|
case VT_VARIANT:
|
|
call_method( func, argspos, args, &stack_offset );
|
|
break;
|
|
case VT_R4:
|
|
V_R4(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
|
|
break;
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
V_R8(pvargResult) = call_double_method( func, argspos, args, &stack_offset );
|
|
break;
|
|
case VT_I8:
|
|
case VT_UI8:
|
|
case VT_CY:
|
|
V_UI8(pvargResult) = call_method( func, argspos, args, &stack_offset );
|
|
break;
|
|
default:
|
|
V_UI4(pvargResult) = call_method( func, argspos, args, &stack_offset );
|
|
break;
|
|
}
|
|
heap_free( args );
|
|
if (stack_offset && cc == CC_STDCALL)
|
|
{
|
|
WARN( "stack pointer off by %d\n", stack_offset );
|
|
return DISP_E_BADCALLEE;
|
|
}
|
|
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
|
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
|
return S_OK;
|
|
|
|
#elif defined(__x86_64__)
|
|
int argspos = 0;
|
|
UINT i;
|
|
DWORD_PTR *args;
|
|
void *func;
|
|
|
|
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;
|
|
}
|
|
|
|
/* maximum size for an argument is sizeof(DWORD_PTR) */
|
|
args = heap_alloc( sizeof(DWORD_PTR) * (cActuals + 2) );
|
|
|
|
if (pvInstance)
|
|
{
|
|
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
|
func = vtable[oVft/sizeof(void *)];
|
|
args[argspos++] = (DWORD_PTR)pvInstance; /* the This pointer is always the first parameter */
|
|
}
|
|
else func = (void *)oVft;
|
|
|
|
switch (vtReturn)
|
|
{
|
|
case VT_DECIMAL:
|
|
case VT_VARIANT:
|
|
args[argspos++] = (DWORD_PTR)pvargResult; /* arg 0 is a pointer to the result */
|
|
break;
|
|
case VT_HRESULT:
|
|
WARN("invalid return type %u\n", vtReturn);
|
|
heap_free( args );
|
|
return E_INVALIDARG;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < cActuals; i++)
|
|
{
|
|
VARIANT *arg = prgpvarg[i];
|
|
|
|
switch (prgvt[i])
|
|
{
|
|
case VT_DECIMAL:
|
|
case VT_VARIANT:
|
|
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);
|
|
break;
|
|
default:
|
|
args[argspos++] = V_UI8(arg);
|
|
break;
|
|
}
|
|
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
|
}
|
|
|
|
switch (vtReturn)
|
|
{
|
|
case VT_R4:
|
|
V_R4(pvargResult) = call_double_method( func, argspos, args );
|
|
break;
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
V_R8(pvargResult) = call_double_method( func, argspos, args );
|
|
break;
|
|
case VT_DECIMAL:
|
|
case VT_VARIANT:
|
|
call_method( func, argspos, args );
|
|
break;
|
|
default:
|
|
V_UI8(pvargResult) = call_method( func, argspos, args );
|
|
break;
|
|
}
|
|
heap_free( args );
|
|
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
|
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
|
return S_OK;
|
|
|
|
#elif defined(__arm__)
|
|
int argspos;
|
|
void *func;
|
|
UINT i;
|
|
DWORD *args;
|
|
struct {
|
|
#ifndef __SOFTFP__
|
|
union {
|
|
float s[16];
|
|
double d[8];
|
|
} sd;
|
|
#endif
|
|
DWORD r[4];
|
|
} regs;
|
|
int rcount; /* 32-bit register index count */
|
|
#ifndef __SOFTFP__
|
|
int scount = 0; /* single-precision float register index count */
|
|
int dcount = 0; /* double-precision float register index count */
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
|
|
argspos = 0;
|
|
rcount = 0;
|
|
|
|
if (pvInstance)
|
|
{
|
|
const FARPROC *vtable = *(FARPROC **)pvInstance;
|
|
func = vtable[oVft/sizeof(void *)];
|
|
regs.r[rcount++] = (DWORD)pvInstance; /* the This pointer is always the first parameter */
|
|
}
|
|
else func = (void *)oVft;
|
|
|
|
/* Determine if we need to pass a pointer for the return value as arg 0. If so, do that */
|
|
/* first as it will need to be in the 'r' registers: */
|
|
switch (vtReturn)
|
|
{
|
|
case VT_DECIMAL:
|
|
case VT_VARIANT:
|
|
regs.r[rcount++] = (DWORD)pvargResult; /* arg 0 is a pointer to the result */
|
|
break;
|
|
case VT_HRESULT:
|
|
WARN("invalid return type %u\n", vtReturn);
|
|
return E_INVALIDARG;
|
|
default: /* And all others are in 'r', 's', or 'd' registers or have no return value */
|
|
break;
|
|
}
|
|
|
|
/* maximum size for an argument is sizeof(VARIANT). Also allow for return pointer and stack alignment. */
|
|
args = heap_alloc( sizeof(VARIANT) * cActuals + sizeof(DWORD) * 4 );
|
|
|
|
for (i = 0; i < cActuals; i++)
|
|
{
|
|
VARIANT *arg = prgpvarg[i];
|
|
DWORD *pdwarg = (DWORD *)(arg); /* a reinterpret_cast of the variant, used for copying structures when they are split between registers and stack */
|
|
int ntemp; /* Used for counting words split between registers and stack */
|
|
|
|
switch (prgvt[i])
|
|
{
|
|
case VT_EMPTY:
|
|
break;
|
|
case VT_R8: /* these must be 8-byte aligned, and put in 'd' regs or stack, as they are double-floats */
|
|
case VT_DATE:
|
|
#ifndef __SOFTFP__
|
|
dcount = max( (scount + 1) / 2, dcount );
|
|
if (dcount < 8)
|
|
{
|
|
regs.sd.d[dcount++] = V_R8(arg);
|
|
}
|
|
else
|
|
{
|
|
argspos += (argspos % 2); /* align argspos to 8-bytes */
|
|
memcpy( &args[argspos], &V_R8(arg), sizeof(V_R8(arg)) );
|
|
argspos += sizeof(V_R8(arg)) / sizeof(DWORD);
|
|
}
|
|
break;
|
|
#endif
|
|
case VT_I8: /* these must be 8-byte aligned, and put in 'r' regs or stack, as they are long-longs */
|
|
case VT_UI8:
|
|
case VT_CY:
|
|
if (rcount < 3)
|
|
{
|
|
rcount += (rcount % 2); /* align rcount to 8-byte register pair */
|
|
memcpy( ®s.r[rcount], &V_UI8(arg), sizeof(V_UI8(arg)) );
|
|
rcount += sizeof(V_UI8(arg)) / sizeof(DWORD);
|
|
}
|
|
else
|
|
{
|
|
rcount = 4; /* Make sure we flag that all 'r' regs are full */
|
|
argspos += (argspos % 2); /* align argspos to 8-bytes */
|
|
memcpy( &args[argspos], &V_UI8(arg), sizeof(V_UI8(arg)) );
|
|
argspos += sizeof(V_UI8(arg)) / sizeof(DWORD);
|
|
}
|
|
break;
|
|
case VT_DECIMAL: /* these structures are 8-byte aligned, and put in 'r' regs or stack, can be split between the two */
|
|
case VT_VARIANT:
|
|
/* 8-byte align 'r' and/or stack: */
|
|
if (rcount < 3)
|
|
rcount += (rcount % 2);
|
|
else
|
|
{
|
|
rcount = 4;
|
|
argspos += (argspos % 2);
|
|
}
|
|
ntemp = sizeof(*arg) / sizeof(DWORD);
|
|
while (ntemp > 0)
|
|
{
|
|
if (rcount < 4)
|
|
regs.r[rcount++] = *pdwarg++;
|
|
else
|
|
args[argspos++] = *pdwarg++;
|
|
--ntemp;
|
|
}
|
|
break;
|
|
case VT_BOOL: /* VT_BOOL is 16-bit but BOOL is 32-bit, needs to be extended */
|
|
if (rcount < 4)
|
|
regs.r[rcount++] = V_BOOL(arg);
|
|
else
|
|
args[argspos++] = V_BOOL(arg);
|
|
break;
|
|
case VT_R4: /* these must be 4-byte aligned, and put in 's' regs or stack, as they are single-floats */
|
|
#ifndef __SOFTFP__
|
|
if (!(scount % 2)) scount = max( scount, dcount * 2 );
|
|
if (scount < 16)
|
|
regs.sd.s[scount++] = V_R4(arg);
|
|
else
|
|
args[argspos++] = V_UI4(arg);
|
|
break;
|
|
#endif
|
|
default:
|
|
if (rcount < 4)
|
|
regs.r[rcount++] = V_UI4(arg);
|
|
else
|
|
args[argspos++] = V_UI4(arg);
|
|
break;
|
|
}
|
|
TRACE("arg %u: type %s %s\n", i, debugstr_vt(prgvt[i]), debugstr_variant(arg));
|
|
}
|
|
|
|
argspos += (argspos % 2); /* Make sure stack function alignment is 8-byte */
|
|
|
|
switch (vtReturn)
|
|
{
|
|
case VT_EMPTY: /* EMPTY = no return value */
|
|
case VT_DECIMAL: /* DECIMAL and VARIANT already have a pointer argument passed (see above) */
|
|
case VT_VARIANT:
|
|
call_method( func, argspos, args, (DWORD*)®s );
|
|
break;
|
|
case VT_R4:
|
|
V_R4(pvargResult) = call_float_method( func, argspos, args, (DWORD*)®s );
|
|
break;
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
V_R8(pvargResult) = call_double_method( func, argspos, args, (DWORD*)®s );
|
|
break;
|
|
case VT_I8:
|
|
case VT_UI8:
|
|
case VT_CY:
|
|
V_UI8(pvargResult) = call_method( func, argspos, args, (DWORD*)®s );
|
|
break;
|
|
default:
|
|
V_UI4(pvargResult) = call_method( func, argspos, args, (DWORD*)®s );
|
|
break;
|
|
}
|
|
heap_free( args );
|
|
if (vtReturn != VT_VARIANT) V_VT(pvargResult) = vtReturn;
|
|
TRACE("retval: %s\n", debugstr_variant(pvargResult));
|
|
return S_OK;
|
|
|
|
#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
|
|
}
|
|
|
|
static inline BOOL func_restricted( const FUNCDESC *desc )
|
|
{
|
|
return (desc->wFuncFlags & FUNCFLAG_FRESTRICTED) && (desc->memid >= 0);
|
|
}
|
|
|
|
#define INVBUF_ELEMENT_SIZE \
|
|
(sizeof(VARIANTARG) + sizeof(VARIANTARG) + sizeof(VARIANTARG *) + sizeof(VARTYPE))
|
|
#define INVBUF_GET_ARG_ARRAY(buffer, params) (buffer)
|
|
#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)))
|
|
|
|
static HRESULT WINAPI ITypeInfo_fnInvoke(
|
|
ITypeInfo2 *iface,
|
|
VOID *pIUnk,
|
|
MEMBERID memid,
|
|
UINT16 wFlags,
|
|
DISPPARAMS *pDispParams,
|
|
VARIANT *pVarResult,
|
|
EXCEPINFO *pExcepInfo,
|
|
UINT *pArgErr)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
int i;
|
|
unsigned int var_index;
|
|
TYPEKIND type_kind;
|
|
HRESULT hres;
|
|
const TLBFuncDesc *pFuncInfo;
|
|
UINT fdc;
|
|
|
|
TRACE("(%p)(%p,id=%d,flags=0x%08x,%p,%p,%p,%p)\n",
|
|
This,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr
|
|
);
|
|
|
|
if( This->typeattr.wTypeFlags & TYPEFLAG_FRESTRICTED )
|
|
return DISP_E_MEMBERNOTFOUND;
|
|
|
|
if (!pDispParams)
|
|
{
|
|
ERR("NULL pDispParams not allowed\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
dump_DispParms(pDispParams);
|
|
|
|
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;
|
|
}
|
|
|
|
/* we do this instead of using GetFuncDesc since it will return a fake
|
|
* FUNCDESC for dispinterfaces and we want the real function description */
|
|
for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
|
|
pFuncInfo = &This->funcdescs[fdc];
|
|
if ((memid == pFuncInfo->funcdesc.memid) &&
|
|
(wFlags & pFuncInfo->funcdesc.invkind) &&
|
|
!func_restricted( &pFuncInfo->funcdesc ))
|
|
break;
|
|
}
|
|
|
|
if (fdc < This->typeattr.cFuncs) {
|
|
const FUNCDESC *func_desc = &pFuncInfo->funcdesc;
|
|
|
|
if (TRACE_ON(ole))
|
|
{
|
|
TRACE("invoking:\n");
|
|
dump_TLBFuncDescOne(pFuncInfo);
|
|
}
|
|
|
|
switch (func_desc->funckind) {
|
|
case FUNC_PUREVIRTUAL:
|
|
case FUNC_VIRTUAL: {
|
|
void *buffer = heap_alloc_zero(INVBUF_ELEMENT_SIZE * func_desc->cParams);
|
|
VARIANT varresult;
|
|
VARIANT retval; /* pointer for storing byref retvals in */
|
|
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);
|
|
UINT cNamedArgs = pDispParams->cNamedArgs;
|
|
DISPID *rgdispidNamedArgs = pDispParams->rgdispidNamedArgs;
|
|
UINT vargs_converted=0;
|
|
|
|
hres = S_OK;
|
|
|
|
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");
|
|
hres = DISP_E_PARAMNOTFOUND;
|
|
goto func_fail;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
for (i = 0; i < func_desc->cParams; i++)
|
|
{
|
|
TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
|
|
hres = typedescvt_to_variantvt((ITypeInfo *)iface, tdesc, &rgvt[i]);
|
|
if (FAILED(hres))
|
|
goto func_fail;
|
|
}
|
|
|
|
TRACE("changing args\n");
|
|
for (i = 0; i < func_desc->cParams; i++)
|
|
{
|
|
USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
|
|
TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc;
|
|
VARIANTARG *src_arg;
|
|
|
|
if (wParamFlags & PARAMFLAG_FLCID)
|
|
{
|
|
VARIANTARG *arg;
|
|
arg = prgpvarg[i] = &rgvarg[i];
|
|
V_VT(arg) = VT_I4;
|
|
V_I4(arg) = This->pTypeLib->lcid;
|
|
continue;
|
|
}
|
|
|
|
src_arg = NULL;
|
|
|
|
if (cNamedArgs)
|
|
{
|
|
USHORT j;
|
|
for (j = 0; j < cNamedArgs; j++)
|
|
if (rgdispidNamedArgs[j] == i || (i == func_desc->cParams-1 && rgdispidNamedArgs[j] == DISPID_PROPERTYPUT))
|
|
{
|
|
src_arg = &pDispParams->rgvarg[j];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!src_arg && vargs_converted + cNamedArgs < pDispParams->cArgs)
|
|
{
|
|
src_arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
|
|
vargs_converted++;
|
|
}
|
|
|
|
if (wParamFlags & PARAMFLAG_FRETVAL)
|
|
{
|
|
/* 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;
|
|
}
|
|
|
|
/* 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;
|
|
arg = prgpvarg[i] = &rgvarg[i];
|
|
memset(arg, 0, sizeof(*arg));
|
|
V_VT(arg) = rgvt[i];
|
|
memset(&retval, 0, sizeof(retval));
|
|
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;
|
|
}
|
|
}
|
|
else if (src_arg && !((wParamFlags & PARAMFLAG_FOPT) &&
|
|
V_VT(src_arg) == VT_ERROR && V_ERROR(src_arg) == DISP_E_PARAMNOTFOUND))
|
|
{
|
|
TRACE("%s\n", debugstr_variant(src_arg));
|
|
|
|
if(rgvt[i]!=V_VT(src_arg))
|
|
{
|
|
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) || rgvt[i] == (VT_VARIANT | VT_ARRAY | VT_BYREF)) && func_desc->cParamsOpt < 0)
|
|
{
|
|
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);
|
|
SafeArrayDestroy(a);
|
|
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);
|
|
SafeArrayDestroy(a);
|
|
break;
|
|
}
|
|
if (rgvt[i] & VT_BYREF)
|
|
V_BYREF(&rgvarg[i]) = &a;
|
|
else
|
|
V_ARRAY(&rgvarg[i]) = a;
|
|
V_VT(&rgvarg[i]) = rgvt[i];
|
|
}
|
|
else if ((rgvt[i] & VT_BYREF) && !V_ISBYREF(src_arg))
|
|
{
|
|
VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
|
|
if (wParamFlags & PARAMFLAG_FIN)
|
|
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];
|
|
}
|
|
else if ((rgvt[i] & VT_BYREF) && (rgvt[i] == V_VT(src_arg)))
|
|
{
|
|
V_BYREF(&rgvarg[i]) = V_BYREF(src_arg);
|
|
V_VT(&rgvarg[i]) = rgvt[i];
|
|
}
|
|
else
|
|
{
|
|
/* 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];
|
|
}
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
ERR("failed to convert param %d to %s from %s\n", i,
|
|
debugstr_vt(rgvt[i]), debugstr_variant(src_arg));
|
|
break;
|
|
}
|
|
prgpvarg[i] = &rgvarg[i];
|
|
}
|
|
else
|
|
{
|
|
prgpvarg[i] = src_arg;
|
|
}
|
|
|
|
if((tdesc->vt == VT_USERDEFINED || (tdesc->vt == VT_PTR && tdesc->u.lptdesc->vt == VT_USERDEFINED))
|
|
&& (V_VT(prgpvarg[i]) == VT_DISPATCH || V_VT(prgpvarg[i]) == VT_UNKNOWN)
|
|
&& V_UNKNOWN(prgpvarg[i])) {
|
|
IUnknown *userdefined_iface;
|
|
GUID guid;
|
|
|
|
if (tdesc->vt == VT_PTR)
|
|
tdesc = tdesc->u.lptdesc;
|
|
|
|
hres = get_iface_guid((ITypeInfo*)iface, tdesc->u.hreftype, &guid);
|
|
if(FAILED(hres))
|
|
break;
|
|
|
|
hres = IUnknown_QueryInterface(V_UNKNOWN(prgpvarg[i]), &guid, (void**)&userdefined_iface);
|
|
if(FAILED(hres)) {
|
|
ERR("argument does not support %s interface\n", debugstr_guid(&guid));
|
|
break;
|
|
}
|
|
|
|
IUnknown_Release(V_UNKNOWN(prgpvarg[i]));
|
|
V_UNKNOWN(prgpvarg[i]) = userdefined_iface;
|
|
}
|
|
}
|
|
else if (wParamFlags & PARAMFLAG_FOPT)
|
|
{
|
|
VARIANTARG *arg;
|
|
arg = prgpvarg[i] = &rgvarg[i];
|
|
if (wParamFlags & PARAMFLAG_FHASDEFAULT)
|
|
{
|
|
hres = VariantCopy(arg, &func_desc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
|
|
if (FAILED(hres))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = DISP_E_BADPARAMCOUNT;
|
|
break;
|
|
}
|
|
}
|
|
if (FAILED(hres)) goto func_fail; /* FIXME: we don't free changed types here */
|
|
|
|
/* 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 */
|
|
}
|
|
|
|
hres = DispCallFunc(pIUnk, func_desc->oVft & 0xFFFC, func_desc->callconv,
|
|
V_VT(&varresult), func_desc->cParams, rgvt,
|
|
prgpvarg, &varresult);
|
|
|
|
vargs_converted = 0;
|
|
|
|
for (i = 0; i < func_desc->cParams; i++)
|
|
{
|
|
USHORT wParamFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags;
|
|
VARIANTARG *missing_arg = INVBUF_GET_MISSING_ARG_ARRAY(buffer, func_desc->cParams);
|
|
|
|
if (wParamFlags & PARAMFLAG_FLCID)
|
|
continue;
|
|
else if (wParamFlags & PARAMFLAG_FRETVAL)
|
|
{
|
|
TRACE("[retval] value: %s\n", debugstr_variant(prgpvarg[i]));
|
|
|
|
if (pVarResult)
|
|
{
|
|
VariantInit(pVarResult);
|
|
/* deref return value */
|
|
hres = VariantCopyInd(pVarResult, prgpvarg[i]);
|
|
}
|
|
|
|
VARIANT_ClearInd(prgpvarg[i]);
|
|
}
|
|
else if (vargs_converted < pDispParams->cArgs)
|
|
{
|
|
VARIANTARG *arg = &pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted];
|
|
if (wParamFlags & PARAMFLAG_FOUT)
|
|
{
|
|
if ((rgvt[i] & VT_BYREF) && !(V_VT(arg) & VT_BYREF))
|
|
{
|
|
hres = VariantChangeType(arg, &rgvarg[i], 0, V_VT(arg));
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
ERR("failed to convert param %d to vt %d\n", i,
|
|
V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1 - vargs_converted]));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
VariantClear(&rgvarg[i]);
|
|
vargs_converted++;
|
|
}
|
|
else if (wParamFlags & PARAMFLAG_FOPT)
|
|
{
|
|
if (wParamFlags & PARAMFLAG_FHASDEFAULT)
|
|
VariantClear(&rgvarg[i]);
|
|
}
|
|
|
|
VariantClear(&missing_arg[i]);
|
|
}
|
|
|
|
if ((V_VT(&varresult) == VT_ERROR) && FAILED(V_ERROR(&varresult)))
|
|
{
|
|
WARN("invoked function failed with error 0x%08x\n", V_ERROR(&varresult));
|
|
hres = DISP_E_EXCEPTION;
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
if (V_VT(&varresult) != VT_ERROR)
|
|
{
|
|
TRACE("varresult value: %s\n", debugstr_variant(&varresult));
|
|
|
|
if (pVarResult)
|
|
{
|
|
VariantClear(pVarResult);
|
|
*pVarResult = varresult;
|
|
}
|
|
else
|
|
VariantClear(&varresult);
|
|
}
|
|
|
|
if (SUCCEEDED(hres) && pVarResult && (func_desc->cParams == 1) &&
|
|
(func_desc->invkind & INVOKE_PROPERTYGET) &&
|
|
(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(), wFlags,
|
|
pDispParams, pVarResult, pExcepInfo, pArgErr);
|
|
IDispatch_Release(pDispatch);
|
|
}
|
|
else
|
|
{
|
|
VariantClear(pVarResult);
|
|
hres = DISP_E_NOTACOLLECTION;
|
|
}
|
|
}
|
|
|
|
func_fail:
|
|
heap_free(buffer);
|
|
break;
|
|
}
|
|
case FUNC_DISPATCH: {
|
|
IDispatch *disp;
|
|
|
|
hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp);
|
|
if (SUCCEEDED(hres)) {
|
|
FIXME("Calling Invoke in IDispatch iface. untested!\n");
|
|
hres = IDispatch_Invoke(
|
|
disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,wFlags,pDispParams,
|
|
pVarResult,pExcepInfo,pArgErr
|
|
);
|
|
if (FAILED(hres))
|
|
FIXME("IDispatch::Invoke failed with %08x. (Could be not a real error?)\n", hres);
|
|
IDispatch_Release(disp);
|
|
} else
|
|
FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n");
|
|
break;
|
|
}
|
|
default:
|
|
FIXME("Unknown function invocation type %d\n", func_desc->funckind);
|
|
hres = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
TRACE("-- 0x%08x\n", hres);
|
|
return hres;
|
|
|
|
} 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;
|
|
}
|
|
|
|
/* not found, look for it in inherited interfaces */
|
|
ITypeInfo2_GetTypeKind(iface, &type_kind);
|
|
if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) {
|
|
if(This->impltypes) {
|
|
/* recursive search */
|
|
ITypeInfo *pTInfo;
|
|
hres = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pTInfo);
|
|
if(SUCCEEDED(hres)){
|
|
hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,wFlags,pDispParams,pVarResult,pExcepInfo,pArgErr);
|
|
ITypeInfo_Release(pTInfo);
|
|
return hres;
|
|
}
|
|
WARN("Could not search inherited interface!\n");
|
|
}
|
|
}
|
|
WARN("did not find member id %d, flags 0x%x!\n", memid, wFlags);
|
|
return DISP_E_MEMBERNOTFOUND;
|
|
}
|
|
|
|
/* ITypeInfo::GetDocumentation
|
|
*
|
|
* Retrieves the documentation string, the complete Help file name and path,
|
|
* and the context ID for the Help topic for a specified type description.
|
|
*
|
|
* (Can be tested by the Visual Basic Editor in Word for instance.)
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface,
|
|
MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString,
|
|
DWORD *pdwHelpContext, BSTR *pBstrHelpFile)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
const TLBFuncDesc *pFDesc;
|
|
const TLBVarDesc *pVDesc;
|
|
TRACE("(%p) memid %d Name(%p) DocString(%p)"
|
|
" HelpContext(%p) HelpFile(%p)\n",
|
|
This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
|
|
if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */
|
|
if(pBstrName)
|
|
*pBstrName=SysAllocString(TLB_get_bstr(This->Name));
|
|
if(pBstrDocString)
|
|
*pBstrDocString=SysAllocString(TLB_get_bstr(This->DocString));
|
|
if(pdwHelpContext)
|
|
*pdwHelpContext=This->dwHelpContext;
|
|
if(pBstrHelpFile)
|
|
*pBstrHelpFile=SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
|
|
return S_OK;
|
|
}else {/* for a member */
|
|
pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
|
|
if(pFDesc){
|
|
if(pBstrName)
|
|
*pBstrName = SysAllocString(TLB_get_bstr(pFDesc->Name));
|
|
if(pBstrDocString)
|
|
*pBstrDocString=SysAllocString(TLB_get_bstr(pFDesc->HelpString));
|
|
if(pdwHelpContext)
|
|
*pdwHelpContext=pFDesc->helpcontext;
|
|
if(pBstrHelpFile)
|
|
*pBstrHelpFile = SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
|
|
return S_OK;
|
|
}
|
|
pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
|
|
if(pVDesc){
|
|
if(pBstrName)
|
|
*pBstrName = SysAllocString(TLB_get_bstr(pVDesc->Name));
|
|
if(pBstrDocString)
|
|
*pBstrDocString=SysAllocString(TLB_get_bstr(pVDesc->HelpString));
|
|
if(pdwHelpContext)
|
|
*pdwHelpContext=pVDesc->HelpContext;
|
|
if(pBstrHelpFile)
|
|
*pBstrHelpFile = SysAllocString(TLB_get_bstr(This->pTypeLib->HelpFile));
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if(This->impltypes &&
|
|
(This->typeattr.typekind == TKIND_INTERFACE || This->typeattr.typekind == TKIND_DISPATCH)) {
|
|
/* recursive search */
|
|
ITypeInfo *pTInfo;
|
|
HRESULT result;
|
|
result = ITypeInfo2_GetRefTypeInfo(iface, This->impltypes[0].hRef, &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");
|
|
}
|
|
|
|
WARN("member %d not found\n", memid);
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
|
|
/* ITypeInfo::GetDllEntry
|
|
*
|
|
* Retrieves a description or specification of an entry point for a function
|
|
* in a DLL.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid,
|
|
INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName,
|
|
WORD *pwOrdinal)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
const TLBFuncDesc *pFDesc;
|
|
|
|
TRACE("(%p)->(memid %x, %d, %p, %p, %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
|
|
|
|
if (pBstrDllName) *pBstrDllName = NULL;
|
|
if (pBstrName) *pBstrName = NULL;
|
|
if (pwOrdinal) *pwOrdinal = 0;
|
|
|
|
if (This->typeattr.typekind != TKIND_MODULE)
|
|
return TYPE_E_BADMODULEKIND;
|
|
|
|
pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
|
|
if(pFDesc){
|
|
dump_TypeInfo(This);
|
|
if (TRACE_ON(ole))
|
|
dump_TLBFuncDescOne(pFDesc);
|
|
|
|
if (pBstrDllName)
|
|
*pBstrDllName = SysAllocString(TLB_get_bstr(This->DllName));
|
|
|
|
if (!IS_INTRESOURCE(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) {
|
|
if (pBstrName)
|
|
*pBstrName = SysAllocString(TLB_get_bstr(pFDesc->Entry));
|
|
if (pwOrdinal)
|
|
*pwOrdinal = -1;
|
|
return S_OK;
|
|
}
|
|
if (pBstrName)
|
|
*pBstrName = NULL;
|
|
if (pwOrdinal)
|
|
*pwOrdinal = LOWORD(pFDesc->Entry);
|
|
return S_OK;
|
|
}
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
|
|
/* 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 = impl_from_ITypeInfo(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, 0x%x\n", iface, *hRefType);
|
|
|
|
if (This->impltypes && (*hRefType & DISPATCH_HREF_MASK))
|
|
{
|
|
ITypeInfo *pSubTypeInfo;
|
|
|
|
hr = ITypeInfo_GetRefTypeInfo(iface, This->impltypes[0].hRef, &pSubTypeInfo);
|
|
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;
|
|
}
|
|
|
|
struct search_res_tlb_params
|
|
{
|
|
const GUID *guid;
|
|
ITypeLib *pTLib;
|
|
};
|
|
|
|
static BOOL CALLBACK search_res_tlb(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam)
|
|
{
|
|
struct search_res_tlb_params *params = (LPVOID)lParam;
|
|
static const WCHAR formatW[] = {'\\','%','d',0};
|
|
WCHAR szPath[MAX_PATH+1];
|
|
ITypeLib *pTLib = NULL;
|
|
HRESULT ret;
|
|
DWORD len;
|
|
|
|
if (IS_INTRESOURCE(lpszName) == FALSE)
|
|
return TRUE;
|
|
|
|
if (!(len = GetModuleFileNameW(hModule, szPath, MAX_PATH)))
|
|
return TRUE;
|
|
|
|
if (snprintfW(szPath + len, ARRAY_SIZE(szPath) - len, formatW, LOWORD(lpszName)) < 0)
|
|
return TRUE;
|
|
|
|
ret = LoadTypeLibEx(szPath, REGKIND_NONE, &pTLib);
|
|
if (SUCCEEDED(ret))
|
|
{
|
|
ITypeLibImpl *impl = impl_from_ITypeLib(pTLib);
|
|
if (IsEqualGUID(params->guid, impl->guid))
|
|
{
|
|
params->pTLib = pTLib;
|
|
return FALSE; /* stop enumeration */
|
|
}
|
|
ITypeLib_Release(pTLib);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* ITypeInfo::GetRefTypeInfo
|
|
*
|
|
* If a type description references other type descriptions, it retrieves
|
|
* the referenced type descriptions.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo(
|
|
ITypeInfo2 *iface,
|
|
HREFTYPE hRefType,
|
|
ITypeInfo **ppTInfo)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
HRESULT result = E_FAIL;
|
|
|
|
if(!ppTInfo)
|
|
return E_INVALIDARG;
|
|
|
|
if ((INT)hRefType < 0) {
|
|
ITypeInfoImpl *pTypeInfoImpl;
|
|
|
|
if (!(This->typeattr.wTypeFlags & TYPEFLAG_FDUAL) ||
|
|
!(This->typeattr.typekind == TKIND_INTERFACE ||
|
|
This->typeattr.typekind == TKIND_DISPATCH))
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
/* when we meet a DUAL typeinfo, we must create the alternate
|
|
* version of it.
|
|
*/
|
|
pTypeInfoImpl = ITypeInfoImpl_Constructor();
|
|
|
|
*pTypeInfoImpl = *This;
|
|
pTypeInfoImpl->ref = 0;
|
|
list_init(&pTypeInfoImpl->custdata_list);
|
|
|
|
if (This->typeattr.typekind == TKIND_INTERFACE)
|
|
pTypeInfoImpl->typeattr.typekind = TKIND_DISPATCH;
|
|
else
|
|
pTypeInfoImpl->typeattr.typekind = TKIND_INTERFACE;
|
|
|
|
*ppTInfo = (ITypeInfo *)&pTypeInfoImpl->ITypeInfo2_iface;
|
|
/* 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
|
|
* not free its data structures when it is destroyed */
|
|
pTypeInfoImpl->not_attached_to_typelib = TRUE;
|
|
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
|
|
result = S_OK;
|
|
} else if ((hRefType & DISPATCH_HREF_MASK) &&
|
|
(This->typeattr.typekind == TKIND_DISPATCH))
|
|
{
|
|
HREFTYPE href_dispatch = hRefType;
|
|
result = ITypeInfoImpl_GetDispatchRefTypeInfo((ITypeInfo *)iface, &href_dispatch, ppTInfo);
|
|
} else {
|
|
TLBRefType *ref_type;
|
|
ITypeLib *pTLib = NULL;
|
|
UINT i;
|
|
|
|
if(!(hRefType & 0x1)){
|
|
for(i = 0; i < This->pTypeLib->TypeInfoCount; ++i)
|
|
{
|
|
if (This->pTypeLib->typeinfos[i]->hreftype == (hRefType&(~0x3)))
|
|
{
|
|
result = S_OK;
|
|
*ppTInfo = (ITypeInfo*)&This->pTypeLib->typeinfos[i]->ITypeInfo2_iface;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry)
|
|
{
|
|
if(ref_type->reference == (hRefType & (~0x3)))
|
|
break;
|
|
}
|
|
if(&ref_type->entry == &This->pTypeLib->ref_list)
|
|
{
|
|
FIXME("Can't find pRefType for ref %x\n", hRefType);
|
|
goto end;
|
|
}
|
|
|
|
if(ref_type->pImpTLInfo == TLB_REF_INTERNAL) {
|
|
UINT Index;
|
|
TRACE("internal reference\n");
|
|
result = ITypeInfo2_GetContainingTypeLib(iface, &pTLib, &Index);
|
|
} else {
|
|
if(ref_type->pImpTLInfo->pImpTypeLib) {
|
|
TRACE("typeinfo in imported typelib that is already loaded\n");
|
|
pTLib = (ITypeLib*)&ref_type->pImpTLInfo->pImpTypeLib->ITypeLib2_iface;
|
|
ITypeLib_AddRef(pTLib);
|
|
result = S_OK;
|
|
} else {
|
|
static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0};
|
|
struct search_res_tlb_params params;
|
|
BSTR libnam;
|
|
|
|
TRACE("typeinfo in imported typelib that isn't already loaded\n");
|
|
|
|
/* Search in resource table */
|
|
params.guid = TLB_get_guid_null(ref_type->pImpTLInfo->guid);
|
|
params.pTLib = NULL;
|
|
EnumResourceNamesW(NULL, TYPELIBW, search_res_tlb, (LONG_PTR)¶ms);
|
|
pTLib = params.pTLib;
|
|
result = S_OK;
|
|
|
|
if (!pTLib)
|
|
{
|
|
/* Search on disk */
|
|
result = query_typelib_path(TLB_get_guid_null(ref_type->pImpTLInfo->guid),
|
|
ref_type->pImpTLInfo->wVersionMajor,
|
|
ref_type->pImpTLInfo->wVersionMinor,
|
|
This->pTypeLib->syskind,
|
|
ref_type->pImpTLInfo->lcid, &libnam, TRUE);
|
|
if (FAILED(result))
|
|
libnam = SysAllocString(ref_type->pImpTLInfo->name);
|
|
|
|
result = LoadTypeLib(libnam, &pTLib);
|
|
SysFreeString(libnam);
|
|
}
|
|
|
|
if(SUCCEEDED(result)) {
|
|
ref_type->pImpTLInfo->pImpTypeLib = impl_from_ITypeLib(pTLib);
|
|
ITypeLib_AddRef(pTLib);
|
|
}
|
|
}
|
|
}
|
|
if(SUCCEEDED(result)) {
|
|
if(ref_type->index == TLB_REF_USE_GUID)
|
|
result = ITypeLib_GetTypeInfoOfGuid(pTLib, TLB_get_guid_null(ref_type->guid), ppTInfo);
|
|
else
|
|
result = ITypeLib_GetTypeInfo(pTLib, ref_type->index, ppTInfo);
|
|
}
|
|
if (pTLib != NULL)
|
|
ITypeLib_Release(pTLib);
|
|
}
|
|
|
|
end:
|
|
TRACE("(%p) hreftype 0x%04x loaded %s (%p)\n", This, hRefType,
|
|
SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo);
|
|
return result;
|
|
}
|
|
|
|
/* ITypeInfo::AddressOfMember
|
|
*
|
|
* Retrieves the addresses of static functions or variables, such as those
|
|
* defined in a DLL.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface,
|
|
MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
HRESULT hr;
|
|
BSTR dll, entry;
|
|
WORD ordinal;
|
|
HMODULE module;
|
|
|
|
TRACE("(%p)->(0x%x, 0x%x, %p)\n", This, memid, invKind, ppv);
|
|
|
|
hr = ITypeInfo2_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);
|
|
SysFreeString(entry);
|
|
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);
|
|
entryA = heap_alloc(len);
|
|
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));
|
|
|
|
heap_free(entryA);
|
|
}
|
|
else
|
|
{
|
|
*ppv = GetProcAddress(module, MAKEINTRESOURCEA(ordinal));
|
|
if (!*ppv)
|
|
ERR("function not found %d\n", ordinal);
|
|
}
|
|
|
|
SysFreeString(dll);
|
|
SysFreeString(entry);
|
|
|
|
if (!*ppv)
|
|
return TYPE_E_DLLFUNCTIONNOTFOUND;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo::CreateInstance
|
|
*
|
|
* Creates a new instance of a type that describes a component object class
|
|
* (coclass).
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface,
|
|
IUnknown *pOuterUnk, REFIID riid, VOID **ppvObj)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
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 = ITypeInfo2_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);
|
|
TRACE("GetActiveObject rets %08x\n", hr);
|
|
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:
|
|
ITypeInfo2_ReleaseTypeAttr(iface, pTA);
|
|
return hr;
|
|
}
|
|
|
|
/* ITypeInfo::GetMops
|
|
*
|
|
* Retrieves marshalling information.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid,
|
|
BSTR *pBstrMops)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
FIXME("(%p %d) stub!\n", This, memid);
|
|
*pBstrMops = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo::GetContainingTypeLib
|
|
*
|
|
* Retrieves the containing type library and the index of the type description
|
|
* within that type library.
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface,
|
|
ITypeLib * *ppTLib, UINT *pIndex)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
|
|
/* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
|
|
if (pIndex) {
|
|
*pIndex=This->index;
|
|
TRACE("returning pIndex=%d\n", *pIndex);
|
|
}
|
|
|
|
if (ppTLib) {
|
|
*ppTLib = (ITypeLib *)&This->pTypeLib->ITypeLib2_iface;
|
|
ITypeLib_AddRef(*ppTLib);
|
|
TRACE("returning ppTLib=%p\n", *ppTLib);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo::ReleaseTypeAttr
|
|
*
|
|
* Releases a TYPEATTR previously returned by Get
|
|
*
|
|
*/
|
|
static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface,
|
|
TYPEATTR* pTypeAttr)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TRACE("(%p)->(%p)\n", This, pTypeAttr);
|
|
heap_free(pTypeAttr);
|
|
}
|
|
|
|
/* ITypeInfo::ReleaseFuncDesc
|
|
*
|
|
* Releases a FUNCDESC previously returned by GetFuncDesc. *
|
|
*/
|
|
static void WINAPI ITypeInfo_fnReleaseFuncDesc(
|
|
ITypeInfo2 *iface,
|
|
FUNCDESC *pFuncDesc)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
SHORT i;
|
|
|
|
TRACE("(%p)->(%p)\n", This, pFuncDesc);
|
|
|
|
for (i = 0; i < pFuncDesc->cParams; i++)
|
|
TLB_FreeElemDesc(&pFuncDesc->lprgelemdescParam[i]);
|
|
TLB_FreeElemDesc(&pFuncDesc->elemdescFunc);
|
|
|
|
SysFreeString((BSTR)pFuncDesc);
|
|
}
|
|
|
|
/* ITypeInfo::ReleaseVarDesc
|
|
*
|
|
* Releases a VARDESC previously returned by GetVarDesc.
|
|
*/
|
|
static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface,
|
|
VARDESC *pVarDesc)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TRACE("(%p)->(%p)\n", This, pVarDesc);
|
|
|
|
TLB_FreeVarDesc(pVarDesc);
|
|
}
|
|
|
|
/* ITypeInfo2::GetTypeKind
|
|
*
|
|
* Returns the TYPEKIND enumeration quickly, without doing any allocations.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface,
|
|
TYPEKIND *pTypeKind)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
*pTypeKind = This->typeattr.typekind;
|
|
TRACE("(%p) type 0x%0x\n", This,*pTypeKind);
|
|
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
|
|
* attribute).
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
*pTypeFlags=This->typeattr.wTypeFlags;
|
|
TRACE("(%p) flags 0x%x\n", This,*pTypeFlags);
|
|
return S_OK;
|
|
}
|
|
|
|
/* 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).
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface,
|
|
MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
UINT fdc;
|
|
HRESULT result;
|
|
|
|
for (fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
|
|
const TLBFuncDesc *pFuncInfo = &This->funcdescs[fdc];
|
|
if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind))
|
|
break;
|
|
}
|
|
if(fdc < This->typeattr.cFuncs) {
|
|
*pFuncIndex = fdc;
|
|
result = S_OK;
|
|
} else
|
|
result = TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
TRACE("(%p) memid 0x%08x invKind 0x%04x -> %s\n", This,
|
|
memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED");
|
|
return result;
|
|
}
|
|
|
|
/* TypeInfo2::GetVarIndexOfMemId
|
|
*
|
|
* 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).
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface,
|
|
MEMBERID memid, UINT *pVarIndex)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBVarDesc *pVarInfo;
|
|
|
|
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;
|
|
}
|
|
|
|
/* ITypeInfo2::GetCustData
|
|
*
|
|
* Gets the custom data
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetCustData(
|
|
ITypeInfo2 * iface,
|
|
REFGUID guid,
|
|
VARIANT *pVarVal)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBCustData *pCData;
|
|
|
|
TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
|
|
|
|
if(!guid || !pVarVal)
|
|
return E_INVALIDARG;
|
|
|
|
pCData = TLB_get_custdata_by_guid(This->pcustdata_list, guid);
|
|
|
|
VariantInit( pVarVal);
|
|
if (pCData)
|
|
VariantCopy( pVarVal, &pCData->data);
|
|
else
|
|
VariantClear( pVarVal );
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo2::GetFuncCustData
|
|
*
|
|
* Gets the custom data
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData(
|
|
ITypeInfo2 * iface,
|
|
UINT index,
|
|
REFGUID guid,
|
|
VARIANT *pVarVal)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBCustData *pCData;
|
|
TLBFuncDesc *pFDesc = &This->funcdescs[index];
|
|
|
|
TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
|
|
|
|
if(index >= This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
pCData = TLB_get_custdata_by_guid(&pFDesc->custdata_list, guid);
|
|
if(!pCData)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
VariantInit(pVarVal);
|
|
VariantCopy(pVarVal, &pCData->data);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo2::GetParamCustData
|
|
*
|
|
* Gets the custom data
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetParamCustData(
|
|
ITypeInfo2 * iface,
|
|
UINT indexFunc,
|
|
UINT indexParam,
|
|
REFGUID guid,
|
|
VARIANT *pVarVal)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBCustData *pCData;
|
|
TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
|
|
|
|
TRACE("%p %u %u %s %p\n", This, indexFunc, indexParam,
|
|
debugstr_guid(guid), pVarVal);
|
|
|
|
if(indexFunc >= This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
if(indexParam >= pFDesc->funcdesc.cParams)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
pCData = TLB_get_custdata_by_guid(&pFDesc->pParamDesc[indexParam].custdata_list, guid);
|
|
if(!pCData)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
VariantInit(pVarVal);
|
|
VariantCopy(pVarVal, &pCData->data);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo2::GetVarCustData
|
|
*
|
|
* Gets the custom data
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetVarCustData(
|
|
ITypeInfo2 * iface,
|
|
UINT index,
|
|
REFGUID guid,
|
|
VARIANT *pVarVal)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBCustData *pCData;
|
|
TLBVarDesc *pVDesc = &This->vardescs[index];
|
|
|
|
TRACE("%p %s %p\n", This, debugstr_guid(guid), pVarVal);
|
|
|
|
if(index >= This->typeattr.cVars)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
pCData = TLB_get_custdata_by_guid(&pVDesc->custdata_list, guid);
|
|
if(!pCData)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
VariantInit(pVarVal);
|
|
VariantCopy(pVarVal, &pCData->data);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo2::GetImplCustData
|
|
*
|
|
* Gets the custom data
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData(
|
|
ITypeInfo2 * iface,
|
|
UINT index,
|
|
REFGUID guid,
|
|
VARIANT *pVarVal)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBCustData *pCData;
|
|
TLBImplType *pRDesc = &This->impltypes[index];
|
|
|
|
TRACE("%p %u %s %p\n", This, index, debugstr_guid(guid), pVarVal);
|
|
|
|
if(index >= This->typeattr.cImplTypes)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
pCData = TLB_get_custdata_by_guid(&pRDesc->custdata_list, guid);
|
|
if(!pCData)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
VariantInit(pVarVal);
|
|
VariantCopy(pVarVal, &pCData->data);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/* ITypeInfo2::GetDocumentation2
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2(
|
|
ITypeInfo2 * iface,
|
|
MEMBERID memid,
|
|
LCID lcid,
|
|
BSTR *pbstrHelpString,
|
|
DWORD *pdwHelpStringContext,
|
|
BSTR *pbstrHelpStringDll)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
const TLBFuncDesc *pFDesc;
|
|
const TLBVarDesc *pVDesc;
|
|
TRACE("(%p) memid %d lcid(0x%x) HelpString(%p) "
|
|
"HelpStringContext(%p) HelpStringDll(%p)\n",
|
|
This, memid, lcid, pbstrHelpString, pdwHelpStringContext,
|
|
pbstrHelpStringDll );
|
|
/* 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)
|
|
*pbstrHelpString=SysAllocString(TLB_get_bstr(This->Name));
|
|
if(pdwHelpStringContext)
|
|
*pdwHelpStringContext=This->dwHelpStringContext;
|
|
if(pbstrHelpStringDll)
|
|
*pbstrHelpStringDll=
|
|
SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
|
|
return S_OK;
|
|
}else {/* for a member */
|
|
pFDesc = TLB_get_funcdesc_by_memberid(This->funcdescs, This->typeattr.cFuncs, memid);
|
|
if(pFDesc){
|
|
if(pbstrHelpString)
|
|
*pbstrHelpString=SysAllocString(TLB_get_bstr(pFDesc->HelpString));
|
|
if(pdwHelpStringContext)
|
|
*pdwHelpStringContext=pFDesc->HelpStringContext;
|
|
if(pbstrHelpStringDll)
|
|
*pbstrHelpStringDll=
|
|
SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
|
|
return S_OK;
|
|
}
|
|
pVDesc = TLB_get_vardesc_by_memberid(This->vardescs, This->typeattr.cVars, memid);
|
|
if(pVDesc){
|
|
if(pbstrHelpString)
|
|
*pbstrHelpString=SysAllocString(TLB_get_bstr(pVDesc->HelpString));
|
|
if(pdwHelpStringContext)
|
|
*pdwHelpStringContext=pVDesc->HelpStringContext;
|
|
if(pbstrHelpStringDll)
|
|
*pbstrHelpStringDll=
|
|
SysAllocString(TLB_get_bstr(This->pTypeLib->HelpStringDll));/* FIXME */
|
|
return S_OK;
|
|
}
|
|
}
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
}
|
|
|
|
/* ITypeInfo2::GetAllCustData
|
|
*
|
|
* Gets all custom data items for the Type info.
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetAllCustData(
|
|
ITypeInfo2 * iface,
|
|
CUSTDATA *pCustData)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
|
|
TRACE("%p %p\n", This, pCustData);
|
|
|
|
return TLB_copy_all_custdata(This->pcustdata_list, pCustData);
|
|
}
|
|
|
|
/* ITypeInfo2::GetAllFuncCustData
|
|
*
|
|
* Gets all custom data items for the specified Function
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData(
|
|
ITypeInfo2 * iface,
|
|
UINT index,
|
|
CUSTDATA *pCustData)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBFuncDesc *pFDesc = &This->funcdescs[index];
|
|
|
|
TRACE("%p %u %p\n", This, index, pCustData);
|
|
|
|
if(index >= This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
return TLB_copy_all_custdata(&pFDesc->custdata_list, pCustData);
|
|
}
|
|
|
|
/* ITypeInfo2::GetAllParamCustData
|
|
*
|
|
* Gets all custom data items for the Functions
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface,
|
|
UINT indexFunc, UINT indexParam, CUSTDATA *pCustData)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBFuncDesc *pFDesc = &This->funcdescs[indexFunc];
|
|
|
|
TRACE("%p %u %u %p\n", This, indexFunc, indexParam, pCustData);
|
|
|
|
if(indexFunc >= This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
if(indexParam >= pFDesc->funcdesc.cParams)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
return TLB_copy_all_custdata(&pFDesc->pParamDesc[indexParam].custdata_list, pCustData);
|
|
}
|
|
|
|
/* ITypeInfo2::GetAllVarCustData
|
|
*
|
|
* Gets all custom data items for the specified Variable
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface,
|
|
UINT index, CUSTDATA *pCustData)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBVarDesc * pVDesc = &This->vardescs[index];
|
|
|
|
TRACE("%p %u %p\n", This, index, pCustData);
|
|
|
|
if(index >= This->typeattr.cVars)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
return TLB_copy_all_custdata(&pVDesc->custdata_list, pCustData);
|
|
}
|
|
|
|
/* ITypeInfo2::GetAllImplCustData
|
|
*
|
|
* Gets all custom data items for the specified implementation type
|
|
*
|
|
*/
|
|
static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData(
|
|
ITypeInfo2 * iface,
|
|
UINT index,
|
|
CUSTDATA *pCustData)
|
|
{
|
|
ITypeInfoImpl *This = impl_from_ITypeInfo2(iface);
|
|
TLBImplType *pRDesc = &This->impltypes[index];
|
|
|
|
TRACE("%p %u %p\n", This, index, pCustData);
|
|
|
|
if(index >= This->typeattr.cImplTypes)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
return TLB_copy_all_custdata(&pRDesc->custdata_list, pCustData);
|
|
}
|
|
|
|
static const ITypeInfo2Vtbl tinfvt =
|
|
{
|
|
|
|
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,
|
|
};
|
|
|
|
/******************************************************************************
|
|
* 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 */
|
|
{
|
|
ITypeInfoImpl *pTIClass, *pTIIface;
|
|
ITypeLibImpl *pTypeLibImpl;
|
|
unsigned int param, func;
|
|
TLBFuncDesc *pFuncDesc;
|
|
TLBRefType *ref;
|
|
|
|
TRACE("\n");
|
|
pTypeLibImpl = TypeLibImpl_Constructor();
|
|
if (!pTypeLibImpl) return E_FAIL;
|
|
|
|
pTypeLibImpl->TypeInfoCount = 2;
|
|
pTypeLibImpl->typeinfos = heap_alloc_zero(pTypeLibImpl->TypeInfoCount * sizeof(ITypeInfoImpl*));
|
|
|
|
pTIIface = pTypeLibImpl->typeinfos[0] = ITypeInfoImpl_Constructor();
|
|
pTIIface->pTypeLib = pTypeLibImpl;
|
|
pTIIface->index = 0;
|
|
pTIIface->Name = NULL;
|
|
pTIIface->dwHelpContext = -1;
|
|
pTIIface->guid = NULL;
|
|
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;
|
|
pTIIface->hreftype = 0;
|
|
|
|
pTIIface->funcdescs = TLBFuncDesc_Alloc(pidata->cMembers);
|
|
pFuncDesc = pTIIface->funcdescs;
|
|
for(func = 0; func < pidata->cMembers; func++) {
|
|
METHODDATA *md = pidata->pmethdata + func;
|
|
pFuncDesc->Name = TLB_append_str(&pTypeLibImpl->name_list, 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));
|
|
pFuncDesc->pParamDesc = TLBParDesc_Constructor(md->cArgs);
|
|
for(param = 0; param < md->cArgs; param++) {
|
|
pFuncDesc->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt;
|
|
pFuncDesc->pParamDesc[param].Name = TLB_append_str(&pTypeLibImpl->name_list, md->ppdata[param].szName);
|
|
}
|
|
pFuncDesc->helpcontext = 0;
|
|
pFuncDesc->HelpStringContext = 0;
|
|
pFuncDesc->HelpString = NULL;
|
|
pFuncDesc->Entry = NULL;
|
|
list_init(&pFuncDesc->custdata_list);
|
|
pTIIface->typeattr.cFuncs++;
|
|
++pFuncDesc;
|
|
}
|
|
|
|
dump_TypeInfo(pTIIface);
|
|
|
|
pTIClass = pTypeLibImpl->typeinfos[1] = ITypeInfoImpl_Constructor();
|
|
pTIClass->pTypeLib = pTypeLibImpl;
|
|
pTIClass->index = 1;
|
|
pTIClass->Name = NULL;
|
|
pTIClass->dwHelpContext = -1;
|
|
pTIClass->guid = NULL;
|
|
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;
|
|
pTIClass->hreftype = sizeof(MSFT_TypeInfoBase);
|
|
|
|
pTIClass->impltypes = TLBImplType_Alloc(1);
|
|
|
|
ref = heap_alloc_zero(sizeof(*ref));
|
|
ref->pImpTLInfo = TLB_REF_INTERNAL;
|
|
list_add_head(&pTypeLibImpl->ref_list, &ref->entry);
|
|
|
|
dump_TypeInfo(pTIClass);
|
|
|
|
*pptinfo = (ITypeInfo *)&pTIClass->ITypeInfo2_iface;
|
|
|
|
ITypeInfo_AddRef(*pptinfo);
|
|
ITypeLib2_Release(&pTypeLibImpl->ITypeLib2_iface);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
|
|
|
|
return ITypeInfo2_QueryInterface(&This->ITypeInfo2_iface, riid, ppv);
|
|
}
|
|
|
|
static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
|
|
|
|
return ITypeInfo2_AddRef(&This->ITypeInfo2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
|
|
|
|
return ITypeInfo2_Release(&This->ITypeInfo2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI ITypeComp_fnBind(
|
|
ITypeComp * iface,
|
|
OLECHAR * szName,
|
|
ULONG lHash,
|
|
WORD wFlags,
|
|
ITypeInfo ** ppTInfo,
|
|
DESCKIND * pDescKind,
|
|
BINDPTR * pBindPtr)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ITypeComp(iface);
|
|
const TLBFuncDesc *pFDesc;
|
|
const TLBVarDesc *pVDesc;
|
|
HRESULT hr = DISP_E_MEMBERNOTFOUND;
|
|
UINT fdc;
|
|
|
|
TRACE("(%p)->(%s, %x, 0x%x, %p, %p, %p)\n", This, debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr);
|
|
|
|
*pDescKind = DESCKIND_NONE;
|
|
pBindPtr->lpfuncdesc = NULL;
|
|
*ppTInfo = NULL;
|
|
|
|
for(fdc = 0; fdc < This->typeattr.cFuncs; ++fdc){
|
|
pFDesc = &This->funcdescs[fdc];
|
|
if (!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szName)) {
|
|
if (!wFlags || (pFDesc->funcdesc.invkind & wFlags))
|
|
break;
|
|
else
|
|
/* name found, but wrong flags */
|
|
hr = TYPE_E_TYPEMISMATCH;
|
|
}
|
|
}
|
|
|
|
if (fdc < This->typeattr.cFuncs)
|
|
{
|
|
HRESULT hr = TLB_AllocAndInitFuncDesc(
|
|
&pFDesc->funcdesc,
|
|
&pBindPtr->lpfuncdesc,
|
|
This->typeattr.typekind == TKIND_DISPATCH);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
*pDescKind = DESCKIND_FUNCDESC;
|
|
*ppTInfo = (ITypeInfo *)&This->ITypeInfo2_iface;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
return S_OK;
|
|
} else {
|
|
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->ITypeInfo2_iface;
|
|
ITypeInfo_AddRef(*ppTInfo);
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (hr == DISP_E_MEMBERNOTFOUND && This->impltypes) {
|
|
/* recursive search */
|
|
ITypeInfo *pTInfo;
|
|
ITypeComp *pTComp;
|
|
HRESULT hr;
|
|
hr=ITypeInfo2_GetRefTypeInfo(&This->ITypeInfo2_iface, This->impltypes[0].hRef, &pTInfo);
|
|
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);
|
|
if (SUCCEEDED(hr) && *pDescKind == DESCKIND_FUNCDESC &&
|
|
This->typeattr.typekind == TKIND_DISPATCH)
|
|
{
|
|
FUNCDESC *tmp = pBindPtr->lpfuncdesc;
|
|
hr = TLB_AllocAndInitFuncDesc(tmp, &pBindPtr->lpfuncdesc, TRUE);
|
|
SysFreeString((BSTR)tmp);
|
|
}
|
|
return hr;
|
|
}
|
|
WARN("Could not search inherited interface!\n");
|
|
}
|
|
if (hr == DISP_E_MEMBERNOTFOUND)
|
|
hr = S_OK;
|
|
TRACE("did not find member with name %s, flags 0x%x\n", debugstr_w(szName), wFlags);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI ITypeComp_fnBindType(
|
|
ITypeComp * iface,
|
|
OLECHAR * szName,
|
|
ULONG lHash,
|
|
ITypeInfo ** ppTInfo,
|
|
ITypeComp ** ppTComp)
|
|
{
|
|
TRACE("(%s, %x, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp);
|
|
|
|
/* strange behaviour (does nothing) but like the
|
|
* original */
|
|
|
|
if (!ppTInfo || !ppTComp)
|
|
return E_POINTER;
|
|
|
|
*ppTInfo = NULL;
|
|
*ppTComp = NULL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const ITypeCompVtbl tcompvt =
|
|
{
|
|
|
|
ITypeComp_fnQueryInterface,
|
|
ITypeComp_fnAddRef,
|
|
ITypeComp_fnRelease,
|
|
|
|
ITypeComp_fnBind,
|
|
ITypeComp_fnBindType
|
|
};
|
|
|
|
HRESULT WINAPI CreateTypeLib2(SYSKIND syskind, LPCOLESTR szFile,
|
|
ICreateTypeLib2** ppctlib)
|
|
{
|
|
ITypeLibImpl *This;
|
|
HRESULT hres;
|
|
|
|
TRACE("(%d,%s,%p)\n", syskind, debugstr_w(szFile), ppctlib);
|
|
|
|
if (!szFile) return E_INVALIDARG;
|
|
|
|
This = TypeLibImpl_Constructor();
|
|
if (!This)
|
|
return E_OUTOFMEMORY;
|
|
|
|
This->lcid = GetSystemDefaultLCID();
|
|
This->syskind = syskind;
|
|
This->ptr_size = get_ptr_size(syskind);
|
|
|
|
This->path = heap_alloc((lstrlenW(szFile) + 1) * sizeof(WCHAR));
|
|
if (!This->path) {
|
|
ITypeLib2_Release(&This->ITypeLib2_iface);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
lstrcpyW(This->path, szFile);
|
|
|
|
hres = ITypeLib2_QueryInterface(&This->ITypeLib2_iface, &IID_ICreateTypeLib2, (LPVOID*)ppctlib);
|
|
ITypeLib2_Release(&This->ITypeLib2_iface);
|
|
return hres;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnQueryInterface(ICreateTypeLib2 *iface,
|
|
REFIID riid, void **object)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
return ITypeLib2_QueryInterface(&This->ITypeLib2_iface, riid, object);
|
|
}
|
|
|
|
static ULONG WINAPI ICreateTypeLib2_fnAddRef(ICreateTypeLib2 *iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
return ITypeLib2_AddRef(&This->ITypeLib2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
return ITypeLib2_Release(&This->ITypeLib2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnCreateTypeInfo(ICreateTypeLib2 *iface,
|
|
LPOLESTR name, TYPEKIND kind, ICreateTypeInfo **ctinfo)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
ITypeInfoImpl *info;
|
|
HRESULT hres;
|
|
|
|
TRACE("%p %s %d %p\n", This, wine_dbgstr_w(name), kind, ctinfo);
|
|
|
|
if (!ctinfo || !name)
|
|
return E_INVALIDARG;
|
|
|
|
info = TLB_get_typeinfo_by_name(This->typeinfos, This->TypeInfoCount, name);
|
|
if (info)
|
|
return TYPE_E_NAMECONFLICT;
|
|
|
|
if (This->typeinfos)
|
|
This->typeinfos = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->typeinfos,
|
|
sizeof(ITypeInfoImpl*) * (This->TypeInfoCount + 1));
|
|
else
|
|
This->typeinfos = heap_alloc_zero(sizeof(ITypeInfoImpl*));
|
|
|
|
info = This->typeinfos[This->TypeInfoCount] = ITypeInfoImpl_Constructor();
|
|
|
|
info->pTypeLib = This;
|
|
info->Name = TLB_append_str(&This->name_list, name);
|
|
info->index = This->TypeInfoCount;
|
|
info->typeattr.typekind = kind;
|
|
info->typeattr.cbAlignment = 4;
|
|
|
|
switch (info->typeattr.typekind) {
|
|
case TKIND_ENUM:
|
|
case TKIND_INTERFACE:
|
|
case TKIND_DISPATCH:
|
|
case TKIND_COCLASS:
|
|
info->typeattr.cbSizeInstance = This->ptr_size;
|
|
break;
|
|
case TKIND_RECORD:
|
|
case TKIND_UNION:
|
|
info->typeattr.cbSizeInstance = 0;
|
|
break;
|
|
case TKIND_MODULE:
|
|
info->typeattr.cbSizeInstance = 2;
|
|
break;
|
|
case TKIND_ALIAS:
|
|
info->typeattr.cbSizeInstance = -0x75;
|
|
break;
|
|
default:
|
|
FIXME("unrecognized typekind %d\n", info->typeattr.typekind);
|
|
info->typeattr.cbSizeInstance = 0xdeadbeef;
|
|
break;
|
|
}
|
|
|
|
hres = ITypeInfo2_QueryInterface(&info->ITypeInfo2_iface,
|
|
&IID_ICreateTypeInfo, (void **)ctinfo);
|
|
if (FAILED(hres)) {
|
|
ITypeInfo2_Release(&info->ITypeInfo2_iface);
|
|
return hres;
|
|
}
|
|
|
|
info->hreftype = info->index * sizeof(MSFT_TypeInfoBase);
|
|
|
|
++This->TypeInfoCount;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetName(ICreateTypeLib2 *iface,
|
|
LPOLESTR name)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %s\n", This, wine_dbgstr_w(name));
|
|
|
|
if (!name)
|
|
return E_INVALIDARG;
|
|
|
|
This->Name = TLB_append_str(&This->name_list, name);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetVersion(ICreateTypeLib2 *iface,
|
|
WORD majorVerNum, WORD minorVerNum)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %d %d\n", This, majorVerNum, minorVerNum);
|
|
|
|
This->ver_major = majorVerNum;
|
|
This->ver_minor = minorVerNum;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetGuid(ICreateTypeLib2 *iface,
|
|
REFGUID guid)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %s\n", This, debugstr_guid(guid));
|
|
|
|
This->guid = TLB_append_guid(&This->guid_list, guid, -2);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetDocString(ICreateTypeLib2 *iface,
|
|
LPOLESTR doc)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %s\n", This, wine_dbgstr_w(doc));
|
|
|
|
if (!doc)
|
|
return E_INVALIDARG;
|
|
|
|
This->DocString = TLB_append_str(&This->string_list, doc);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetHelpFileName(ICreateTypeLib2 *iface,
|
|
LPOLESTR helpFileName)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %s\n", This, wine_dbgstr_w(helpFileName));
|
|
|
|
if (!helpFileName)
|
|
return E_INVALIDARG;
|
|
|
|
This->HelpFile = TLB_append_str(&This->string_list, helpFileName);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetHelpContext(ICreateTypeLib2 *iface,
|
|
DWORD helpContext)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %d\n", This, helpContext);
|
|
|
|
This->dwHelpContext = helpContext;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetLcid(ICreateTypeLib2 *iface,
|
|
LCID lcid)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %x\n", This, lcid);
|
|
|
|
This->set_lcid = lcid;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetLibFlags(ICreateTypeLib2 *iface,
|
|
UINT libFlags)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
|
|
TRACE("%p %x\n", This, libFlags);
|
|
|
|
This->libflags = libFlags;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
typedef struct tagWMSFT_SegContents {
|
|
DWORD len;
|
|
void *data;
|
|
} WMSFT_SegContents;
|
|
|
|
typedef struct tagWMSFT_TLBFile {
|
|
MSFT_Header header;
|
|
WMSFT_SegContents typeinfo_seg;
|
|
WMSFT_SegContents impfile_seg;
|
|
WMSFT_SegContents impinfo_seg;
|
|
WMSFT_SegContents ref_seg;
|
|
WMSFT_SegContents guidhash_seg;
|
|
WMSFT_SegContents guid_seg;
|
|
WMSFT_SegContents namehash_seg;
|
|
WMSFT_SegContents name_seg;
|
|
WMSFT_SegContents string_seg;
|
|
WMSFT_SegContents typdesc_seg;
|
|
WMSFT_SegContents arraydesc_seg;
|
|
WMSFT_SegContents custdata_seg;
|
|
WMSFT_SegContents cdguids_seg;
|
|
MSFT_SegDir segdir;
|
|
WMSFT_SegContents aux_seg;
|
|
} WMSFT_TLBFile;
|
|
|
|
static HRESULT WMSFT_compile_strings(ITypeLibImpl *This,
|
|
WMSFT_TLBFile *file)
|
|
{
|
|
TLBString *str;
|
|
UINT last_offs;
|
|
char *data;
|
|
|
|
file->string_seg.len = 0;
|
|
LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
|
|
int size;
|
|
|
|
size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str), NULL, 0, NULL, NULL);
|
|
if (size == 0)
|
|
return E_UNEXPECTED;
|
|
|
|
size += sizeof(INT16);
|
|
if (size % 4)
|
|
size = (size + 4) & ~0x3;
|
|
if (size < 8)
|
|
size = 8;
|
|
|
|
file->string_seg.len += size;
|
|
|
|
/* temporarily use str->offset to store the length of the aligned,
|
|
* converted string */
|
|
str->offset = size;
|
|
}
|
|
|
|
file->string_seg.data = data = heap_alloc(file->string_seg.len);
|
|
|
|
last_offs = 0;
|
|
LIST_FOR_EACH_ENTRY(str, &This->string_list, TLBString, entry) {
|
|
int size;
|
|
|
|
size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str),
|
|
data + sizeof(INT16), file->string_seg.len - last_offs - sizeof(INT16), NULL, NULL);
|
|
if (size == 0) {
|
|
heap_free(file->string_seg.data);
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
*((INT16*)data) = size;
|
|
|
|
memset(data + sizeof(INT16) + size, 0x57, str->offset - size - sizeof(INT16));
|
|
|
|
size = str->offset;
|
|
data += size;
|
|
str->offset = last_offs;
|
|
last_offs += size;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WMSFT_compile_names(ITypeLibImpl *This,
|
|
WMSFT_TLBFile *file)
|
|
{
|
|
TLBString *str;
|
|
UINT last_offs;
|
|
char *data;
|
|
MSFT_NameIntro *last_intro = NULL;
|
|
|
|
file->header.nametablecount = 0;
|
|
file->header.nametablechars = 0;
|
|
|
|
file->name_seg.len = 0;
|
|
LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
|
|
int size;
|
|
|
|
size = strlenW(str->str);
|
|
file->header.nametablechars += size;
|
|
file->header.nametablecount++;
|
|
|
|
size = WideCharToMultiByte(CP_ACP, 0, str->str, size, NULL, 0, NULL, NULL);
|
|
if (size == 0)
|
|
return E_UNEXPECTED;
|
|
|
|
size += sizeof(MSFT_NameIntro);
|
|
if (size % 4)
|
|
size = (size + 4) & ~0x3;
|
|
if (size < 8)
|
|
size = 8;
|
|
|
|
file->name_seg.len += size;
|
|
|
|
/* temporarily use str->offset to store the length of the aligned,
|
|
* converted string */
|
|
str->offset = size;
|
|
}
|
|
|
|
/* Allocate bigger buffer so we can temporarily NULL terminate the name */
|
|
file->name_seg.data = data = heap_alloc(file->name_seg.len+1);
|
|
|
|
last_offs = 0;
|
|
LIST_FOR_EACH_ENTRY(str, &This->name_list, TLBString, entry) {
|
|
int size, hash;
|
|
MSFT_NameIntro *intro = (MSFT_NameIntro*)data;
|
|
|
|
size = WideCharToMultiByte(CP_ACP, 0, str->str, strlenW(str->str),
|
|
data + sizeof(MSFT_NameIntro),
|
|
file->name_seg.len - last_offs - sizeof(MSFT_NameIntro), NULL, NULL);
|
|
if (size == 0) {
|
|
heap_free(file->name_seg.data);
|
|
return E_UNEXPECTED;
|
|
}
|
|
data[sizeof(MSFT_NameIntro) + size] = '\0';
|
|
|
|
intro->hreftype = -1; /* TODO? */
|
|
intro->namelen = size & 0xFF;
|
|
/* TODO: namelen & 0xFF00 == ??? maybe HREF type indicator? */
|
|
hash = LHashValOfNameSysA(This->syskind, This->lcid, data + sizeof(MSFT_NameIntro));
|
|
intro->namelen |= hash << 16;
|
|
intro->next_hash = ((DWORD*)file->namehash_seg.data)[hash & 0x7f];
|
|
((DWORD*)file->namehash_seg.data)[hash & 0x7f] = last_offs;
|
|
|
|
memset(data + sizeof(MSFT_NameIntro) + size, 0x57,
|
|
str->offset - size - sizeof(MSFT_NameIntro));
|
|
|
|
/* update str->offset to actual value to use in other
|
|
* compilation functions that require positions within
|
|
* the string table */
|
|
last_intro = intro;
|
|
size = str->offset;
|
|
data += size;
|
|
str->offset = last_offs;
|
|
last_offs += size;
|
|
}
|
|
|
|
if(last_intro)
|
|
last_intro->hreftype = 0; /* last one is 0? */
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static inline int hash_guid(GUID *guid)
|
|
{
|
|
int i, hash = 0;
|
|
|
|
for (i = 0; i < 8; i ++)
|
|
hash ^= ((const short *)guid)[i];
|
|
|
|
return hash & 0x1f;
|
|
}
|
|
|
|
static HRESULT WMSFT_compile_guids(ITypeLibImpl *This, WMSFT_TLBFile *file)
|
|
{
|
|
TLBGuid *guid;
|
|
MSFT_GuidEntry *entry;
|
|
DWORD offs;
|
|
int hash_key, *guidhashtab;
|
|
|
|
file->guid_seg.len = sizeof(MSFT_GuidEntry) * list_count(&This->guid_list);
|
|
file->guid_seg.data = heap_alloc(file->guid_seg.len);
|
|
|
|
entry = file->guid_seg.data;
|
|
offs = 0;
|
|
guidhashtab = file->guidhash_seg.data;
|
|
LIST_FOR_EACH_ENTRY(guid, &This->guid_list, TLBGuid, entry){
|
|
memcpy(&entry->guid, &guid->guid, sizeof(GUID));
|
|
entry->hreftype = guid->hreftype;
|
|
|
|
hash_key = hash_guid(&guid->guid);
|
|
entry->next_hash = guidhashtab[hash_key];
|
|
guidhashtab[hash_key] = offs;
|
|
|
|
guid->offset = offs;
|
|
offs += sizeof(MSFT_GuidEntry);
|
|
++entry;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static DWORD WMSFT_encode_variant(VARIANT *value, WMSFT_TLBFile *file)
|
|
{
|
|
VARIANT v = *value;
|
|
VARTYPE arg_type = V_VT(value);
|
|
int mask = 0;
|
|
HRESULT hres;
|
|
DWORD ret = file->custdata_seg.len;
|
|
|
|
if(arg_type == VT_INT)
|
|
arg_type = VT_I4;
|
|
if(arg_type == VT_UINT)
|
|
arg_type = VT_UI4;
|
|
|
|
v = *value;
|
|
if(V_VT(value) != arg_type) {
|
|
hres = VariantChangeType(&v, value, 0, arg_type);
|
|
if(FAILED(hres)){
|
|
ERR("VariantChangeType failed: %08x\n", hres);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Check if default value can be stored in-place */
|
|
switch(arg_type){
|
|
case VT_I4:
|
|
case VT_UI4:
|
|
mask = 0x3ffffff;
|
|
if(V_UI4(&v) > 0x3ffffff)
|
|
break;
|
|
/* fall through */
|
|
case VT_I1:
|
|
case VT_UI1:
|
|
case VT_BOOL:
|
|
if(!mask)
|
|
mask = 0xff;
|
|
/* fall through */
|
|
case VT_I2:
|
|
case VT_UI2:
|
|
if(!mask)
|
|
mask = 0xffff;
|
|
return ((0x80 + 0x4 * V_VT(value)) << 24) | (V_UI4(&v) & mask);
|
|
}
|
|
|
|
/* have to allocate space in custdata_seg */
|
|
switch(arg_type) {
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_UI4:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
case VT_HRESULT:
|
|
case VT_PTR: {
|
|
/* Construct the data to be allocated */
|
|
int *data;
|
|
|
|
if(file->custdata_seg.data){
|
|
file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + sizeof(int) * 2);
|
|
data = (int *)(((char *)file->custdata_seg.data) + file->custdata_seg.len);
|
|
file->custdata_seg.len += sizeof(int) * 2;
|
|
}else{
|
|
file->custdata_seg.len = sizeof(int) * 2;
|
|
data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
|
|
}
|
|
|
|
data[0] = V_VT(value) + (V_UI4(&v) << 16);
|
|
data[1] = (V_UI4(&v) >> 16) + 0x57570000;
|
|
|
|
/* TODO: Check if the encoded data is already present in custdata_seg */
|
|
|
|
return ret;
|
|
}
|
|
|
|
case VT_BSTR: {
|
|
int i, len = (6+SysStringLen(V_BSTR(&v))+3) & ~0x3;
|
|
char *data;
|
|
|
|
if(file->custdata_seg.data){
|
|
file->custdata_seg.data = heap_realloc(file->custdata_seg.data, file->custdata_seg.len + len);
|
|
data = ((char *)file->custdata_seg.data) + file->custdata_seg.len;
|
|
file->custdata_seg.len += len;
|
|
}else{
|
|
file->custdata_seg.len = len;
|
|
data = file->custdata_seg.data = heap_alloc(file->custdata_seg.len);
|
|
}
|
|
|
|
*((unsigned short *)data) = V_VT(value);
|
|
*((unsigned int *)(data+2)) = SysStringLen(V_BSTR(&v));
|
|
for(i=0; i<SysStringLen(V_BSTR(&v)); i++) {
|
|
if(V_BSTR(&v)[i] <= 0x7f)
|
|
data[i+6] = V_BSTR(&v)[i];
|
|
else
|
|
data[i+6] = '?';
|
|
}
|
|
WideCharToMultiByte(CP_ACP, 0, V_BSTR(&v), SysStringLen(V_BSTR(&v)), &data[6], len-6, NULL, NULL);
|
|
for(i=6+SysStringLen(V_BSTR(&v)); i<len; i++)
|
|
data[i] = 0x57;
|
|
|
|
/* TODO: Check if the encoded data is already present in custdata_seg */
|
|
|
|
return ret;
|
|
}
|
|
default:
|
|
FIXME("Argument type not yet handled\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size);
|
|
|
|
static DWORD WMSFT_append_arraydesc(ARRAYDESC *desc, WMSFT_TLBFile *file)
|
|
{
|
|
DWORD offs = file->arraydesc_seg.len;
|
|
DWORD *encoded;
|
|
USHORT i;
|
|
|
|
/* TODO: we should check for duplicates, but that's harder because each
|
|
* chunk is variable length (really we should store TYPEDESC and ARRAYDESC
|
|
* at the library-level) */
|
|
|
|
file->arraydesc_seg.len += (2 + desc->cDims * 2) * sizeof(DWORD);
|
|
if(!file->arraydesc_seg.data)
|
|
file->arraydesc_seg.data = heap_alloc(file->arraydesc_seg.len);
|
|
else
|
|
file->arraydesc_seg.data = heap_realloc(file->arraydesc_seg.data, file->arraydesc_seg.len);
|
|
encoded = (DWORD*)((char *)file->arraydesc_seg.data + offs);
|
|
|
|
encoded[0] = WMSFT_append_typedesc(&desc->tdescElem, file, NULL, NULL);
|
|
encoded[1] = desc->cDims | ((desc->cDims * 2 * sizeof(DWORD)) << 16);
|
|
for(i = 0; i < desc->cDims; ++i){
|
|
encoded[2 + i * 2] = desc->rgbounds[i].cElements;
|
|
encoded[2 + i * 2 + 1] = desc->rgbounds[i].lLbound;
|
|
}
|
|
|
|
return offs;
|
|
}
|
|
|
|
static DWORD WMSFT_append_typedesc(TYPEDESC *desc, WMSFT_TLBFile *file, DWORD *out_mix, INT16 *out_size)
|
|
{
|
|
DWORD junk;
|
|
INT16 junk2;
|
|
DWORD offs = 0;
|
|
DWORD encoded[2];
|
|
VARTYPE vt, subtype;
|
|
char *data;
|
|
|
|
if(!desc)
|
|
return -1;
|
|
|
|
if(!out_mix)
|
|
out_mix = &junk;
|
|
if(!out_size)
|
|
out_size = &junk2;
|
|
|
|
vt = desc->vt & VT_TYPEMASK;
|
|
|
|
if(vt == VT_PTR || vt == VT_SAFEARRAY){
|
|
DWORD mix;
|
|
encoded[1] = WMSFT_append_typedesc(desc->u.lptdesc, file, &mix, out_size);
|
|
encoded[0] = desc->vt | ((mix | VT_BYREF) << 16);
|
|
*out_mix = 0x7FFF;
|
|
*out_size += 2 * sizeof(DWORD);
|
|
}else if(vt == VT_CARRAY){
|
|
encoded[0] = desc->vt | (0x7FFE << 16);
|
|
encoded[1] = WMSFT_append_arraydesc(desc->u.lpadesc, file);
|
|
*out_mix = 0x7FFE;
|
|
}else if(vt == VT_USERDEFINED){
|
|
encoded[0] = desc->vt | (0x7FFF << 16);
|
|
encoded[1] = desc->u.hreftype;
|
|
*out_mix = 0x7FFF; /* FIXME: Should get TYPEKIND of the hreftype, e.g. TKIND_ENUM => VT_I4 */
|
|
}else{
|
|
TRACE("Mixing in-place, VT: 0x%x\n", desc->vt);
|
|
|
|
switch(vt){
|
|
case VT_INT:
|
|
subtype = VT_I4;
|
|
break;
|
|
case VT_UINT:
|
|
subtype = VT_UI4;
|
|
break;
|
|
case VT_VOID:
|
|
subtype = VT_EMPTY;
|
|
break;
|
|
default:
|
|
subtype = vt;
|
|
break;
|
|
}
|
|
|
|
*out_mix = subtype;
|
|
return 0x80000000 | (subtype << 16) | desc->vt;
|
|
}
|
|
|
|
data = file->typdesc_seg.data;
|
|
while(offs < file->typdesc_seg.len){
|
|
if(!memcmp(&data[offs], encoded, sizeof(encoded)))
|
|
return offs;
|
|
offs += sizeof(encoded);
|
|
}
|
|
|
|
file->typdesc_seg.len += sizeof(encoded);
|
|
if(!file->typdesc_seg.data)
|
|
data = file->typdesc_seg.data = heap_alloc(file->typdesc_seg.len);
|
|
else
|
|
data = file->typdesc_seg.data = heap_realloc(file->typdesc_seg.data, file->typdesc_seg.len);
|
|
|
|
memcpy(&data[offs], encoded, sizeof(encoded));
|
|
|
|
return offs;
|
|
}
|
|
|
|
static DWORD WMSFT_compile_custdata(struct list *custdata_list, WMSFT_TLBFile *file)
|
|
{
|
|
WMSFT_SegContents *cdguids_seg = &file->cdguids_seg;
|
|
DWORD ret = cdguids_seg->len, offs;
|
|
MSFT_CDGuid *cdguid;
|
|
TLBCustData *cd;
|
|
|
|
if(list_empty(custdata_list))
|
|
return -1;
|
|
|
|
cdguids_seg->len += sizeof(MSFT_CDGuid) * list_count(custdata_list);
|
|
if(!cdguids_seg->data){
|
|
cdguid = cdguids_seg->data = heap_alloc(cdguids_seg->len);
|
|
}else {
|
|
cdguids_seg->data = heap_realloc(cdguids_seg->data, cdguids_seg->len);
|
|
cdguid = (MSFT_CDGuid*)((char*)cdguids_seg->data + ret);
|
|
}
|
|
|
|
offs = ret + sizeof(MSFT_CDGuid);
|
|
LIST_FOR_EACH_ENTRY(cd, custdata_list, TLBCustData, entry){
|
|
cdguid->GuidOffset = cd->guid->offset;
|
|
cdguid->DataOffset = WMSFT_encode_variant(&cd->data, file);
|
|
cdguid->next = offs;
|
|
offs += sizeof(MSFT_CDGuid);
|
|
++cdguid;
|
|
}
|
|
|
|
--cdguid;
|
|
cdguid->next = -1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static DWORD WMSFT_compile_typeinfo_aux(ITypeInfoImpl *info,
|
|
WMSFT_TLBFile *file)
|
|
{
|
|
WMSFT_SegContents *aux_seg = &file->aux_seg;
|
|
DWORD ret = aux_seg->len, i, j, recorded_size = 0, extra_size = 0;
|
|
MSFT_VarRecord *varrecord;
|
|
MSFT_FuncRecord *funcrecord;
|
|
MEMBERID *memid;
|
|
DWORD *name, *offsets, offs;
|
|
|
|
for(i = 0; i < info->typeattr.cFuncs; ++i){
|
|
TLBFuncDesc *desc = &info->funcdescs[i];
|
|
|
|
recorded_size += 6 * sizeof(INT); /* mandatory fields */
|
|
|
|
/* optional fields */
|
|
/* TODO: oArgCustData - FuncSetCustData not impl yet */
|
|
if(!list_empty(&desc->custdata_list))
|
|
recorded_size += 7 * sizeof(INT);
|
|
else if(desc->HelpStringContext != 0)
|
|
recorded_size += 6 * sizeof(INT);
|
|
/* res9? resA? */
|
|
else if(desc->Entry)
|
|
recorded_size += 3 * sizeof(INT);
|
|
else if(desc->HelpString)
|
|
recorded_size += 2 * sizeof(INT);
|
|
else if(desc->helpcontext)
|
|
recorded_size += sizeof(INT);
|
|
|
|
recorded_size += desc->funcdesc.cParams * sizeof(MSFT_ParameterInfo);
|
|
|
|
for(j = 0; j < desc->funcdesc.cParams; ++j){
|
|
if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
|
|
recorded_size += desc->funcdesc.cParams * sizeof(INT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
extra_size += 2 * sizeof(INT); /* memberid, name offs */
|
|
}
|
|
|
|
for(i = 0; i < info->typeattr.cVars; ++i){
|
|
TLBVarDesc *desc = &info->vardescs[i];
|
|
|
|
recorded_size += 5 * sizeof(INT); /* mandatory fields */
|
|
|
|
/* optional fields */
|
|
if(desc->HelpStringContext != 0)
|
|
recorded_size += 5 * sizeof(INT);
|
|
else if(!list_empty(&desc->custdata_list))
|
|
recorded_size += 4 * sizeof(INT);
|
|
/* res9? */
|
|
else if(desc->HelpString)
|
|
recorded_size += 2 * sizeof(INT);
|
|
else if(desc->HelpContext != 0)
|
|
recorded_size += sizeof(INT);
|
|
|
|
extra_size += 2 * sizeof(INT); /* memberid, name offs */
|
|
}
|
|
|
|
if(!recorded_size && !extra_size)
|
|
return ret;
|
|
|
|
extra_size += sizeof(INT); /* total aux size for this typeinfo */
|
|
|
|
aux_seg->len += recorded_size + extra_size;
|
|
|
|
aux_seg->len += sizeof(INT) * (info->typeattr.cVars + info->typeattr.cFuncs); /* offsets at the end */
|
|
|
|
if(aux_seg->data)
|
|
aux_seg->data = heap_realloc(aux_seg->data, aux_seg->len);
|
|
else
|
|
aux_seg->data = heap_alloc(aux_seg->len);
|
|
|
|
*((DWORD*)((char *)aux_seg->data + ret)) = recorded_size;
|
|
|
|
offsets = (DWORD*)((char *)aux_seg->data + ret + recorded_size + extra_size);
|
|
offs = 0;
|
|
|
|
funcrecord = (MSFT_FuncRecord*)(((char *)aux_seg->data) + ret + sizeof(INT));
|
|
for(i = 0; i < info->typeattr.cFuncs; ++i){
|
|
TLBFuncDesc *desc = &info->funcdescs[i];
|
|
DWORD size = 6 * sizeof(INT), paramdefault_size = 0, *paramdefault;
|
|
|
|
funcrecord->funcdescsize = sizeof(desc->funcdesc) + desc->funcdesc.cParams * sizeof(ELEMDESC);
|
|
funcrecord->DataType = WMSFT_append_typedesc(&desc->funcdesc.elemdescFunc.tdesc, file, NULL, &funcrecord->funcdescsize);
|
|
funcrecord->Flags = desc->funcdesc.wFuncFlags;
|
|
funcrecord->VtableOffset = desc->funcdesc.oVft;
|
|
|
|
/* FKCCIC:
|
|
* XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
|
|
* ^^^funckind
|
|
* ^^^ ^invkind
|
|
* ^has_cust_data
|
|
* ^^^^callconv
|
|
* ^has_param_defaults
|
|
* ^oEntry_is_intresource
|
|
*/
|
|
funcrecord->FKCCIC =
|
|
desc->funcdesc.funckind |
|
|
(desc->funcdesc.invkind << 3) |
|
|
(list_empty(&desc->custdata_list) ? 0 : 0x80) |
|
|
(desc->funcdesc.callconv << 8);
|
|
|
|
if(desc->Entry && desc->Entry != (TLBString*)-1 && IS_INTRESOURCE(desc->Entry))
|
|
funcrecord->FKCCIC |= 0x2000;
|
|
|
|
for(j = 0; j < desc->funcdesc.cParams; ++j){
|
|
if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT){
|
|
paramdefault_size = sizeof(INT) * desc->funcdesc.cParams;
|
|
funcrecord->funcdescsize += sizeof(PARAMDESCEX);
|
|
}
|
|
}
|
|
if(paramdefault_size > 0)
|
|
funcrecord->FKCCIC |= 0x1000;
|
|
|
|
funcrecord->nrargs = desc->funcdesc.cParams;
|
|
funcrecord->nroargs = desc->funcdesc.cParamsOpt;
|
|
|
|
/* optional fields */
|
|
/* res9? resA? */
|
|
if(!list_empty(&desc->custdata_list)){
|
|
size += 7 * sizeof(INT);
|
|
funcrecord->HelpContext = desc->helpcontext;
|
|
if(desc->HelpString)
|
|
funcrecord->oHelpString = desc->HelpString->offset;
|
|
else
|
|
funcrecord->oHelpString = -1;
|
|
if(!desc->Entry)
|
|
funcrecord->oEntry = -1;
|
|
else if(IS_INTRESOURCE(desc->Entry))
|
|
funcrecord->oEntry = LOWORD(desc->Entry);
|
|
else
|
|
funcrecord->oEntry = desc->Entry->offset;
|
|
funcrecord->res9 = -1;
|
|
funcrecord->resA = -1;
|
|
funcrecord->HelpStringContext = desc->HelpStringContext;
|
|
funcrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
|
|
}else if(desc->HelpStringContext != 0){
|
|
size += 6 * sizeof(INT);
|
|
funcrecord->HelpContext = desc->helpcontext;
|
|
if(desc->HelpString)
|
|
funcrecord->oHelpString = desc->HelpString->offset;
|
|
else
|
|
funcrecord->oHelpString = -1;
|
|
if(!desc->Entry)
|
|
funcrecord->oEntry = -1;
|
|
else if(IS_INTRESOURCE(desc->Entry))
|
|
funcrecord->oEntry = LOWORD(desc->Entry);
|
|
else
|
|
funcrecord->oEntry = desc->Entry->offset;
|
|
funcrecord->res9 = -1;
|
|
funcrecord->resA = -1;
|
|
funcrecord->HelpStringContext = desc->HelpStringContext;
|
|
}else if(desc->Entry){
|
|
size += 3 * sizeof(INT);
|
|
funcrecord->HelpContext = desc->helpcontext;
|
|
if(desc->HelpString)
|
|
funcrecord->oHelpString = desc->HelpString->offset;
|
|
else
|
|
funcrecord->oHelpString = -1;
|
|
if(!desc->Entry)
|
|
funcrecord->oEntry = -1;
|
|
else if(IS_INTRESOURCE(desc->Entry))
|
|
funcrecord->oEntry = LOWORD(desc->Entry);
|
|
else
|
|
funcrecord->oEntry = desc->Entry->offset;
|
|
}else if(desc->HelpString){
|
|
size += 2 * sizeof(INT);
|
|
funcrecord->HelpContext = desc->helpcontext;
|
|
funcrecord->oHelpString = desc->HelpString->offset;
|
|
}else if(desc->helpcontext){
|
|
size += sizeof(INT);
|
|
funcrecord->HelpContext = desc->helpcontext;
|
|
}
|
|
|
|
paramdefault = (DWORD*)((char *)funcrecord + size);
|
|
size += paramdefault_size;
|
|
|
|
for(j = 0; j < desc->funcdesc.cParams; ++j){
|
|
MSFT_ParameterInfo *info = (MSFT_ParameterInfo*)(((char *)funcrecord) + size);
|
|
|
|
info->DataType = WMSFT_append_typedesc(&desc->funcdesc.lprgelemdescParam[j].tdesc, file, NULL, &funcrecord->funcdescsize);
|
|
if(desc->pParamDesc[j].Name)
|
|
info->oName = desc->pParamDesc[j].Name->offset;
|
|
else
|
|
info->oName = -1;
|
|
info->Flags = desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags;
|
|
|
|
if(paramdefault_size){
|
|
if(desc->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
|
|
*paramdefault = WMSFT_encode_variant(&desc->funcdesc.lprgelemdescParam[j].u.paramdesc.pparamdescex->varDefaultValue, file);
|
|
else if(paramdefault_size)
|
|
*paramdefault = -1;
|
|
++paramdefault;
|
|
}
|
|
|
|
size += sizeof(MSFT_ParameterInfo);
|
|
}
|
|
|
|
funcrecord->Info = size | (i << 16); /* is it just the index? */
|
|
|
|
*offsets = offs;
|
|
offs += size;
|
|
++offsets;
|
|
|
|
funcrecord = (MSFT_FuncRecord*)(((char*)funcrecord) + size);
|
|
}
|
|
|
|
varrecord = (MSFT_VarRecord*)funcrecord;
|
|
for(i = 0; i < info->typeattr.cVars; ++i){
|
|
TLBVarDesc *desc = &info->vardescs[i];
|
|
DWORD size = 5 * sizeof(INT);
|
|
|
|
varrecord->vardescsize = sizeof(desc->vardesc);
|
|
varrecord->DataType = WMSFT_append_typedesc(&desc->vardesc.elemdescVar.tdesc, file, NULL, &varrecord->vardescsize);
|
|
varrecord->Flags = desc->vardesc.wVarFlags;
|
|
varrecord->VarKind = desc->vardesc.varkind;
|
|
|
|
if(desc->vardesc.varkind == VAR_CONST){
|
|
varrecord->vardescsize += sizeof(VARIANT);
|
|
varrecord->OffsValue = WMSFT_encode_variant(desc->vardesc.u.lpvarValue, file);
|
|
}else
|
|
varrecord->OffsValue = desc->vardesc.u.oInst;
|
|
|
|
/* res9? */
|
|
if(desc->HelpStringContext != 0){
|
|
size += 5 * sizeof(INT);
|
|
varrecord->HelpContext = desc->HelpContext;
|
|
if(desc->HelpString)
|
|
varrecord->HelpString = desc->HelpString->offset;
|
|
else
|
|
varrecord->HelpString = -1;
|
|
varrecord->res9 = -1;
|
|
varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
|
|
varrecord->HelpStringContext = desc->HelpStringContext;
|
|
}else if(!list_empty(&desc->custdata_list)){
|
|
size += 4 * sizeof(INT);
|
|
varrecord->HelpContext = desc->HelpContext;
|
|
if(desc->HelpString)
|
|
varrecord->HelpString = desc->HelpString->offset;
|
|
else
|
|
varrecord->HelpString = -1;
|
|
varrecord->res9 = -1;
|
|
varrecord->oCustData = WMSFT_compile_custdata(&desc->custdata_list, file);
|
|
}else if(desc->HelpString){
|
|
size += 2 * sizeof(INT);
|
|
varrecord->HelpContext = desc->HelpContext;
|
|
if(desc->HelpString)
|
|
varrecord->HelpString = desc->HelpString->offset;
|
|
else
|
|
varrecord->HelpString = -1;
|
|
}else if(desc->HelpContext != 0){
|
|
size += sizeof(INT);
|
|
varrecord->HelpContext = desc->HelpContext;
|
|
}
|
|
|
|
varrecord->Info = size | (i << 16);
|
|
|
|
*offsets = offs;
|
|
offs += size;
|
|
++offsets;
|
|
|
|
varrecord = (MSFT_VarRecord*)(((char*)varrecord) + size);
|
|
}
|
|
|
|
memid = (MEMBERID*)varrecord;
|
|
for(i = 0; i < info->typeattr.cFuncs; ++i){
|
|
TLBFuncDesc *desc = &info->funcdescs[i];
|
|
*memid = desc->funcdesc.memid;
|
|
++memid;
|
|
}
|
|
for(i = 0; i < info->typeattr.cVars; ++i){
|
|
TLBVarDesc *desc = &info->vardescs[i];
|
|
*memid = desc->vardesc.memid;
|
|
++memid;
|
|
}
|
|
|
|
name = (UINT*)memid;
|
|
for(i = 0; i < info->typeattr.cFuncs; ++i){
|
|
TLBFuncDesc *desc = &info->funcdescs[i];
|
|
if(desc->Name)
|
|
*name = desc->Name->offset;
|
|
else
|
|
*name = -1;
|
|
++name;
|
|
}
|
|
for(i = 0; i < info->typeattr.cVars; ++i){
|
|
TLBVarDesc *desc = &info->vardescs[i];
|
|
if(desc->Name)
|
|
*name = desc->Name->offset;
|
|
else
|
|
*name = -1;
|
|
++name;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
typedef struct tagWMSFT_RefChunk {
|
|
DWORD href;
|
|
DWORD res04;
|
|
DWORD res08;
|
|
DWORD next;
|
|
} WMSFT_RefChunk;
|
|
|
|
static DWORD WMSFT_compile_typeinfo_ref(ITypeInfoImpl *info, WMSFT_TLBFile *file)
|
|
{
|
|
DWORD offs = file->ref_seg.len, i;
|
|
WMSFT_RefChunk *chunk;
|
|
|
|
file->ref_seg.len += info->typeattr.cImplTypes * sizeof(WMSFT_RefChunk);
|
|
if(!file->ref_seg.data)
|
|
file->ref_seg.data = heap_alloc(file->ref_seg.len);
|
|
else
|
|
file->ref_seg.data = heap_realloc(file->ref_seg.data, file->ref_seg.len);
|
|
|
|
chunk = (WMSFT_RefChunk*)((char*)file->ref_seg.data + offs);
|
|
|
|
for(i = 0; i < info->typeattr.cImplTypes; ++i){
|
|
chunk->href = info->impltypes[i].hRef;
|
|
chunk->res04 = info->impltypes[i].implflags;
|
|
chunk->res08 = -1;
|
|
if(i < info->typeattr.cImplTypes - 1)
|
|
chunk->next = offs + sizeof(WMSFT_RefChunk) * (i + 1);
|
|
else
|
|
chunk->next = -1;
|
|
++chunk;
|
|
}
|
|
|
|
return offs;
|
|
}
|
|
|
|
static DWORD WMSFT_compile_typeinfo(ITypeInfoImpl *info, INT16 index, WMSFT_TLBFile *file, char *data)
|
|
{
|
|
DWORD size;
|
|
|
|
size = sizeof(MSFT_TypeInfoBase);
|
|
|
|
if(data){
|
|
MSFT_TypeInfoBase *base = (MSFT_TypeInfoBase*)data;
|
|
if(info->typeattr.wTypeFlags & TYPEFLAG_FDUAL)
|
|
base->typekind = TKIND_DISPATCH;
|
|
else
|
|
base->typekind = info->typeattr.typekind;
|
|
base->typekind |= index << 16; /* TODO: There are some other flags here */
|
|
base->typekind |= (info->typeattr.cbAlignment << 11) | (info->typeattr.cbAlignment << 6);
|
|
base->memoffset = WMSFT_compile_typeinfo_aux(info, file);
|
|
base->res2 = 0;
|
|
base->res3 = 0;
|
|
base->res4 = 3;
|
|
base->res5 = 0;
|
|
base->cElement = (info->typeattr.cVars << 16) | info->typeattr.cFuncs;
|
|
base->res7 = 0;
|
|
base->res8 = 0;
|
|
base->res9 = 0;
|
|
base->resA = 0;
|
|
if(info->guid)
|
|
base->posguid = info->guid->offset;
|
|
else
|
|
base->posguid = -1;
|
|
base->flags = info->typeattr.wTypeFlags;
|
|
if(info->Name) {
|
|
base->NameOffset = info->Name->offset;
|
|
|
|
((unsigned char*)file->name_seg.data)[info->Name->offset+9] = 0x38;
|
|
*(HREFTYPE*)((unsigned char*)file->name_seg.data+info->Name->offset) = info->hreftype;
|
|
}else {
|
|
base->NameOffset = -1;
|
|
}
|
|
base->version = (info->typeattr.wMinorVerNum << 16) | info->typeattr.wMajorVerNum;
|
|
if(info->DocString)
|
|
base->docstringoffs = info->DocString->offset;
|
|
else
|
|
base->docstringoffs = -1;
|
|
base->helpstringcontext = info->dwHelpStringContext;
|
|
base->helpcontext = info->dwHelpContext;
|
|
base->oCustData = WMSFT_compile_custdata(info->pcustdata_list, file);
|
|
base->cImplTypes = info->typeattr.cImplTypes;
|
|
base->cbSizeVft = info->typeattr.cbSizeVft;
|
|
base->size = info->typeattr.cbSizeInstance;
|
|
if(info->typeattr.typekind == TKIND_COCLASS){
|
|
base->datatype1 = WMSFT_compile_typeinfo_ref(info, file);
|
|
}else if(info->typeattr.typekind == TKIND_ALIAS){
|
|
base->datatype1 = WMSFT_append_typedesc(info->tdescAlias, file, NULL, NULL);
|
|
}else if(info->typeattr.typekind == TKIND_MODULE){
|
|
if(info->DllName)
|
|
base->datatype1 = info->DllName->offset;
|
|
else
|
|
base->datatype1 = -1;
|
|
}else{
|
|
if(info->typeattr.cImplTypes > 0)
|
|
base->datatype1 = info->impltypes[0].hRef;
|
|
else
|
|
base->datatype1 = -1;
|
|
}
|
|
base->datatype2 = index; /* FIXME: i think there's more here */
|
|
base->res18 = 0;
|
|
base->res19 = -1;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
static void WMSFT_compile_typeinfo_seg(ITypeLibImpl *This, WMSFT_TLBFile *file, DWORD *junk)
|
|
{
|
|
UINT i;
|
|
|
|
file->typeinfo_seg.len = 0;
|
|
for(i = 0; i < This->TypeInfoCount; ++i){
|
|
ITypeInfoImpl *info = This->typeinfos[i];
|
|
*junk = file->typeinfo_seg.len;
|
|
++junk;
|
|
file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, NULL, NULL);
|
|
}
|
|
|
|
file->typeinfo_seg.data = heap_alloc(file->typeinfo_seg.len);
|
|
memset(file->typeinfo_seg.data, 0x96, file->typeinfo_seg.len);
|
|
|
|
file->aux_seg.len = 0;
|
|
file->aux_seg.data = NULL;
|
|
|
|
file->typeinfo_seg.len = 0;
|
|
for(i = 0; i < This->TypeInfoCount; ++i){
|
|
ITypeInfoImpl *info = This->typeinfos[i];
|
|
file->typeinfo_seg.len += WMSFT_compile_typeinfo(info, i, file,
|
|
((char *)file->typeinfo_seg.data) + file->typeinfo_seg.len);
|
|
}
|
|
}
|
|
|
|
typedef struct tagWMSFT_ImpFile {
|
|
INT guid_offs;
|
|
LCID lcid;
|
|
DWORD version;
|
|
} WMSFT_ImpFile;
|
|
|
|
static void WMSFT_compile_impfile(ITypeLibImpl *This, WMSFT_TLBFile *file)
|
|
{
|
|
TLBImpLib *implib;
|
|
WMSFT_ImpFile *impfile;
|
|
char *data;
|
|
DWORD last_offs = 0;
|
|
|
|
file->impfile_seg.len = 0;
|
|
LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
|
|
int size = 0;
|
|
|
|
if(implib->name){
|
|
WCHAR *path = strrchrW(implib->name, '\\');
|
|
if(path)
|
|
++path;
|
|
else
|
|
path = implib->name;
|
|
size = WideCharToMultiByte(CP_ACP, 0, path, strlenW(path), NULL, 0, NULL, NULL);
|
|
if (size == 0)
|
|
ERR("failed to convert wide string: %s\n", debugstr_w(path));
|
|
}
|
|
|
|
size += sizeof(INT16);
|
|
if (size % 4)
|
|
size = (size + 4) & ~0x3;
|
|
if (size < 8)
|
|
size = 8;
|
|
|
|
file->impfile_seg.len += sizeof(WMSFT_ImpFile) + size;
|
|
}
|
|
|
|
data = file->impfile_seg.data = heap_alloc(file->impfile_seg.len);
|
|
|
|
LIST_FOR_EACH_ENTRY(implib, &This->implib_list, TLBImpLib, entry){
|
|
int strlen = 0, size;
|
|
|
|
impfile = (WMSFT_ImpFile*)data;
|
|
impfile->guid_offs = implib->guid->offset;
|
|
impfile->lcid = implib->lcid;
|
|
impfile->version = (implib->wVersionMinor << 16) | implib->wVersionMajor;
|
|
|
|
data += sizeof(WMSFT_ImpFile);
|
|
|
|
if(implib->name){
|
|
WCHAR *path= strrchrW(implib->name, '\\');
|
|
if(path)
|
|
++path;
|
|
else
|
|
path = implib->name;
|
|
strlen = WideCharToMultiByte(CP_ACP, 0, path, strlenW(path),
|
|
data + sizeof(INT16), file->impfile_seg.len - last_offs - sizeof(INT16), NULL, NULL);
|
|
if (strlen == 0)
|
|
ERR("failed to convert wide string: %s\n", debugstr_w(path));
|
|
}
|
|
|
|
*((INT16*)data) = (strlen << 2) | 1; /* FIXME: is that a flag, or what? */
|
|
|
|
size = strlen + sizeof(INT16);
|
|
if (size % 4)
|
|
size = (size + 4) & ~0x3;
|
|
if (size < 8)
|
|
size = 8;
|
|
memset(data + sizeof(INT16) + strlen, 0x57, size - strlen - sizeof(INT16));
|
|
|
|
data += size;
|
|
implib->offset = last_offs;
|
|
last_offs += size + sizeof(WMSFT_ImpFile);
|
|
}
|
|
}
|
|
|
|
static void WMSFT_compile_impinfo(ITypeLibImpl *This, WMSFT_TLBFile *file)
|
|
{
|
|
MSFT_ImpInfo *info;
|
|
TLBRefType *ref_type;
|
|
UINT i = 0;
|
|
|
|
WMSFT_compile_impfile(This, file);
|
|
|
|
file->impinfo_seg.len = sizeof(MSFT_ImpInfo) * list_count(&This->ref_list);
|
|
info = file->impinfo_seg.data = heap_alloc(file->impinfo_seg.len);
|
|
|
|
LIST_FOR_EACH_ENTRY(ref_type, &This->ref_list, TLBRefType, entry){
|
|
info->flags = i | ((ref_type->tkind & 0xFF) << 24);
|
|
if(ref_type->index == TLB_REF_USE_GUID){
|
|
info->flags |= MSFT_IMPINFO_OFFSET_IS_GUID;
|
|
info->oGuid = ref_type->guid->offset;
|
|
}else
|
|
info->oGuid = ref_type->index;
|
|
info->oImpFile = ref_type->pImpTLInfo->offset;
|
|
++i;
|
|
++info;
|
|
}
|
|
}
|
|
|
|
static void WMSFT_compile_guidhash(ITypeLibImpl *This, WMSFT_TLBFile *file)
|
|
{
|
|
file->guidhash_seg.len = 0x80;
|
|
file->guidhash_seg.data = heap_alloc(file->guidhash_seg.len);
|
|
memset(file->guidhash_seg.data, 0xFF, file->guidhash_seg.len);
|
|
}
|
|
|
|
static void WMSFT_compile_namehash(ITypeLibImpl *This, WMSFT_TLBFile *file)
|
|
{
|
|
file->namehash_seg.len = 0x200;
|
|
file->namehash_seg.data = heap_alloc(file->namehash_seg.len);
|
|
memset(file->namehash_seg.data, 0xFF, file->namehash_seg.len);
|
|
}
|
|
|
|
static void tmp_fill_segdir_seg(MSFT_pSeg *segdir, WMSFT_SegContents *contents, DWORD *running_offset)
|
|
{
|
|
if(contents && contents->len){
|
|
segdir->offset = *running_offset;
|
|
segdir->length = contents->len;
|
|
*running_offset += segdir->length;
|
|
}else{
|
|
segdir->offset = -1;
|
|
segdir->length = 0;
|
|
}
|
|
|
|
/* TODO: do these ever change? */
|
|
segdir->res08 = -1;
|
|
segdir->res0c = 0xf;
|
|
}
|
|
|
|
static void WMSFT_write_segment(HANDLE outfile, WMSFT_SegContents *segment)
|
|
{
|
|
DWORD written;
|
|
if(segment)
|
|
WriteFile(outfile, segment->data, segment->len, &written, NULL);
|
|
}
|
|
|
|
static HRESULT WMSFT_fixup_typeinfos(ITypeLibImpl *This, WMSFT_TLBFile *file,
|
|
DWORD file_len)
|
|
{
|
|
DWORD i;
|
|
MSFT_TypeInfoBase *base = (MSFT_TypeInfoBase *)file->typeinfo_seg.data;
|
|
|
|
for(i = 0; i < This->TypeInfoCount; ++i){
|
|
base->memoffset += file_len;
|
|
++base;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static void WMSFT_free_file(WMSFT_TLBFile *file)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, file->typeinfo_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->guidhash_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->guid_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->ref_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->impinfo_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->impfile_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->namehash_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->name_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->string_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->typdesc_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->arraydesc_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->custdata_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->cdguids_seg.data);
|
|
HeapFree(GetProcessHeap(), 0, file->aux_seg.data);
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 *iface)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
WMSFT_TLBFile file;
|
|
DWORD written, junk_size, junk_offs, running_offset;
|
|
BOOL br;
|
|
HANDLE outfile;
|
|
HRESULT hres;
|
|
DWORD *junk;
|
|
UINT i;
|
|
|
|
TRACE("%p\n", This);
|
|
|
|
for(i = 0; i < This->TypeInfoCount; ++i)
|
|
if(This->typeinfos[i]->needs_layout)
|
|
ICreateTypeInfo2_LayOut(&This->typeinfos[i]->ICreateTypeInfo2_iface);
|
|
|
|
memset(&file, 0, sizeof(file));
|
|
|
|
file.header.magic1 = 0x5446534D;
|
|
file.header.magic2 = 0x00010002;
|
|
file.header.lcid = This->set_lcid ? This->set_lcid : MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
|
file.header.lcid2 = This->set_lcid;
|
|
file.header.varflags = 0x40 | This->syskind;
|
|
if (This->HelpFile)
|
|
file.header.varflags |= 0x10;
|
|
if (This->HelpStringDll)
|
|
file.header.varflags |= HELPDLLFLAG;
|
|
file.header.version = (This->ver_minor << 16) | This->ver_major;
|
|
file.header.flags = This->libflags;
|
|
file.header.helpstringcontext = 0; /* TODO - SetHelpStringContext not implemented yet */
|
|
file.header.helpcontext = This->dwHelpContext;
|
|
file.header.res44 = 0x20;
|
|
file.header.res48 = 0x80;
|
|
file.header.dispatchpos = This->dispatch_href;
|
|
|
|
WMSFT_compile_namehash(This, &file);
|
|
/* do name and string compilation to get offsets for other compilations */
|
|
hres = WMSFT_compile_names(This, &file);
|
|
if (FAILED(hres)){
|
|
WMSFT_free_file(&file);
|
|
return hres;
|
|
}
|
|
|
|
hres = WMSFT_compile_strings(This, &file);
|
|
if (FAILED(hres)){
|
|
WMSFT_free_file(&file);
|
|
return hres;
|
|
}
|
|
|
|
WMSFT_compile_guidhash(This, &file);
|
|
hres = WMSFT_compile_guids(This, &file);
|
|
if (FAILED(hres)){
|
|
WMSFT_free_file(&file);
|
|
return hres;
|
|
}
|
|
|
|
if(This->HelpFile)
|
|
file.header.helpfile = This->HelpFile->offset;
|
|
else
|
|
file.header.helpfile = -1;
|
|
|
|
if(This->DocString)
|
|
file.header.helpstring = This->DocString->offset;
|
|
else
|
|
file.header.helpstring = -1;
|
|
|
|
/* do some more segment compilation */
|
|
file.header.nimpinfos = list_count(&This->ref_list);
|
|
file.header.nrtypeinfos = This->TypeInfoCount;
|
|
|
|
if(This->Name)
|
|
file.header.NameOffset = This->Name->offset;
|
|
else
|
|
file.header.NameOffset = -1;
|
|
|
|
file.header.CustomDataOffset = WMSFT_compile_custdata(&This->custdata_list, &file);
|
|
|
|
if(This->guid)
|
|
file.header.posguid = This->guid->offset;
|
|
else
|
|
file.header.posguid = -1;
|
|
|
|
junk_size = file.header.nrtypeinfos * sizeof(DWORD);
|
|
if(file.header.varflags & HELPDLLFLAG)
|
|
junk_size += sizeof(DWORD);
|
|
if(junk_size){
|
|
junk = heap_alloc_zero(junk_size);
|
|
if(file.header.varflags & HELPDLLFLAG){
|
|
*junk = This->HelpStringDll->offset;
|
|
junk_offs = 1;
|
|
}else
|
|
junk_offs = 0;
|
|
}else{
|
|
junk = NULL;
|
|
junk_offs = 0;
|
|
}
|
|
|
|
WMSFT_compile_typeinfo_seg(This, &file, junk + junk_offs);
|
|
WMSFT_compile_impinfo(This, &file);
|
|
|
|
running_offset = 0;
|
|
|
|
TRACE("header at: 0x%x\n", running_offset);
|
|
running_offset += sizeof(file.header);
|
|
|
|
TRACE("junk at: 0x%x\n", running_offset);
|
|
running_offset += junk_size;
|
|
|
|
TRACE("segdir at: 0x%x\n", running_offset);
|
|
running_offset += sizeof(file.segdir);
|
|
|
|
TRACE("typeinfo at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pTypeInfoTab, &file.typeinfo_seg, &running_offset);
|
|
|
|
TRACE("guidhashtab at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pGuidHashTab, &file.guidhash_seg, &running_offset);
|
|
|
|
TRACE("guidtab at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pGuidTab, &file.guid_seg, &running_offset);
|
|
|
|
TRACE("reftab at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pRefTab, &file.ref_seg, &running_offset);
|
|
|
|
TRACE("impinfo at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pImpInfo, &file.impinfo_seg, &running_offset);
|
|
|
|
TRACE("impfiles at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pImpFiles, &file.impfile_seg, &running_offset);
|
|
|
|
TRACE("namehashtab at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pNameHashTab, &file.namehash_seg, &running_offset);
|
|
|
|
TRACE("nametab at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pNametab, &file.name_seg, &running_offset);
|
|
|
|
TRACE("stringtab at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pStringtab, &file.string_seg, &running_offset);
|
|
|
|
TRACE("typdesc at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pTypdescTab, &file.typdesc_seg, &running_offset);
|
|
|
|
TRACE("arraydescriptions at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pArrayDescriptions, &file.arraydesc_seg, &running_offset);
|
|
|
|
TRACE("custdata at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pCustData, &file.custdata_seg, &running_offset);
|
|
|
|
TRACE("cdguids at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.pCDGuids, &file.cdguids_seg, &running_offset);
|
|
|
|
TRACE("res0e at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.res0e, NULL, &running_offset);
|
|
|
|
TRACE("res0f at: 0x%x\n", running_offset);
|
|
tmp_fill_segdir_seg(&file.segdir.res0f, NULL, &running_offset);
|
|
|
|
TRACE("aux_seg at: 0x%x\n", running_offset);
|
|
|
|
WMSFT_fixup_typeinfos(This, &file, running_offset);
|
|
|
|
outfile = CreateFileW(This->path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, 0);
|
|
if (outfile == INVALID_HANDLE_VALUE){
|
|
WMSFT_free_file(&file);
|
|
heap_free(junk);
|
|
return TYPE_E_IOERROR;
|
|
}
|
|
|
|
br = WriteFile(outfile, &file.header, sizeof(file.header), &written, NULL);
|
|
if (!br) {
|
|
WMSFT_free_file(&file);
|
|
CloseHandle(outfile);
|
|
heap_free(junk);
|
|
return TYPE_E_IOERROR;
|
|
}
|
|
|
|
br = WriteFile(outfile, junk, junk_size, &written, NULL);
|
|
heap_free(junk);
|
|
if (!br) {
|
|
WMSFT_free_file(&file);
|
|
CloseHandle(outfile);
|
|
return TYPE_E_IOERROR;
|
|
}
|
|
|
|
br = WriteFile(outfile, &file.segdir, sizeof(file.segdir), &written, NULL);
|
|
if (!br) {
|
|
WMSFT_free_file(&file);
|
|
CloseHandle(outfile);
|
|
return TYPE_E_IOERROR;
|
|
}
|
|
|
|
WMSFT_write_segment(outfile, &file.typeinfo_seg);
|
|
WMSFT_write_segment(outfile, &file.guidhash_seg);
|
|
WMSFT_write_segment(outfile, &file.guid_seg);
|
|
WMSFT_write_segment(outfile, &file.ref_seg);
|
|
WMSFT_write_segment(outfile, &file.impinfo_seg);
|
|
WMSFT_write_segment(outfile, &file.impfile_seg);
|
|
WMSFT_write_segment(outfile, &file.namehash_seg);
|
|
WMSFT_write_segment(outfile, &file.name_seg);
|
|
WMSFT_write_segment(outfile, &file.string_seg);
|
|
WMSFT_write_segment(outfile, &file.typdesc_seg);
|
|
WMSFT_write_segment(outfile, &file.arraydesc_seg);
|
|
WMSFT_write_segment(outfile, &file.custdata_seg);
|
|
WMSFT_write_segment(outfile, &file.cdguids_seg);
|
|
WMSFT_write_segment(outfile, &file.aux_seg);
|
|
|
|
WMSFT_free_file(&file);
|
|
|
|
CloseHandle(outfile);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnDeleteTypeInfo(ICreateTypeLib2 *iface,
|
|
LPOLESTR name)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
FIXME("%p %s - stub\n", This, wine_dbgstr_w(name));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetCustData(ICreateTypeLib2 *iface,
|
|
REFGUID guid, VARIANT *varVal)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
TLBGuid *tlbguid;
|
|
|
|
TRACE("%p %s %p\n", This, debugstr_guid(guid), varVal);
|
|
|
|
if (!guid || !varVal)
|
|
return E_INVALIDARG;
|
|
|
|
tlbguid = TLB_append_guid(&This->guid_list, guid, -1);
|
|
|
|
return TLB_set_custdata(&This->custdata_list, tlbguid, varVal);
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringContext(ICreateTypeLib2 *iface,
|
|
ULONG helpStringContext)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
FIXME("%p %u - stub\n", This, helpStringContext);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringDll(ICreateTypeLib2 *iface,
|
|
LPOLESTR filename)
|
|
{
|
|
ITypeLibImpl *This = impl_from_ICreateTypeLib2(iface);
|
|
TRACE("%p %s\n", This, wine_dbgstr_w(filename));
|
|
|
|
if (!filename)
|
|
return E_INVALIDARG;
|
|
|
|
This->HelpStringDll = TLB_append_str(&This->string_list, filename);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const ICreateTypeLib2Vtbl CreateTypeLib2Vtbl = {
|
|
ICreateTypeLib2_fnQueryInterface,
|
|
ICreateTypeLib2_fnAddRef,
|
|
ICreateTypeLib2_fnRelease,
|
|
ICreateTypeLib2_fnCreateTypeInfo,
|
|
ICreateTypeLib2_fnSetName,
|
|
ICreateTypeLib2_fnSetVersion,
|
|
ICreateTypeLib2_fnSetGuid,
|
|
ICreateTypeLib2_fnSetDocString,
|
|
ICreateTypeLib2_fnSetHelpFileName,
|
|
ICreateTypeLib2_fnSetHelpContext,
|
|
ICreateTypeLib2_fnSetLcid,
|
|
ICreateTypeLib2_fnSetLibFlags,
|
|
ICreateTypeLib2_fnSaveAllChanges,
|
|
ICreateTypeLib2_fnDeleteTypeInfo,
|
|
ICreateTypeLib2_fnSetCustData,
|
|
ICreateTypeLib2_fnSetHelpStringContext,
|
|
ICreateTypeLib2_fnSetHelpStringDll
|
|
};
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnQueryInterface(ICreateTypeInfo2 *iface,
|
|
REFIID riid, void **object)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
return ITypeInfo2_QueryInterface(&This->ITypeInfo2_iface, riid, object);
|
|
}
|
|
|
|
static ULONG WINAPI ICreateTypeInfo2_fnAddRef(ICreateTypeInfo2 *iface)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
return ITypeInfo2_AddRef(&This->ITypeInfo2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI ICreateTypeInfo2_fnRelease(ICreateTypeInfo2 *iface)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
return ITypeInfo2_Release(&This->ITypeInfo2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetGuid(ICreateTypeInfo2 *iface,
|
|
REFGUID guid)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %s\n", This, debugstr_guid(guid));
|
|
|
|
This->guid = TLB_append_guid(&This->pTypeLib->guid_list, guid, This->hreftype);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeFlags(ICreateTypeInfo2 *iface,
|
|
UINT typeFlags)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
WORD old_flags;
|
|
HRESULT hres;
|
|
|
|
TRACE("%p %x\n", This, typeFlags);
|
|
|
|
if (typeFlags & TYPEFLAG_FDUAL) {
|
|
static const WCHAR stdole2tlb[] = { 's','t','d','o','l','e','2','.','t','l','b',0 };
|
|
ITypeLib *stdole;
|
|
ITypeInfo *dispatch;
|
|
HREFTYPE hreftype;
|
|
HRESULT hres;
|
|
|
|
hres = LoadTypeLib(stdole2tlb, &stdole);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
hres = ITypeLib_GetTypeInfoOfGuid(stdole, &IID_IDispatch, &dispatch);
|
|
ITypeLib_Release(stdole);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
hres = ICreateTypeInfo2_AddRefTypeInfo(iface, dispatch, &hreftype);
|
|
ITypeInfo_Release(dispatch);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
}
|
|
|
|
old_flags = This->typeattr.wTypeFlags;
|
|
This->typeattr.wTypeFlags = typeFlags;
|
|
|
|
hres = ICreateTypeInfo2_LayOut(iface);
|
|
if (FAILED(hres)) {
|
|
This->typeattr.wTypeFlags = old_flags;
|
|
return hres;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetDocString(ICreateTypeInfo2 *iface,
|
|
LPOLESTR doc)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %s\n", This, wine_dbgstr_w(doc));
|
|
|
|
if (!doc)
|
|
return E_INVALIDARG;
|
|
|
|
This->DocString = TLB_append_str(&This->pTypeLib->string_list, doc);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpContext(ICreateTypeInfo2 *iface,
|
|
DWORD helpContext)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %d\n", This, helpContext);
|
|
|
|
This->dwHelpContext = helpContext;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetVersion(ICreateTypeInfo2 *iface,
|
|
WORD majorVerNum, WORD minorVerNum)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %d %d\n", This, majorVerNum, minorVerNum);
|
|
|
|
This->typeattr.wMajorVerNum = majorVerNum;
|
|
This->typeattr.wMinorVerNum = minorVerNum;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnAddRefTypeInfo(ICreateTypeInfo2 *iface,
|
|
ITypeInfo *typeInfo, HREFTYPE *refType)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
UINT index;
|
|
ITypeLib *container;
|
|
TLBRefType *ref_type;
|
|
TLBImpLib *implib;
|
|
TYPEATTR *typeattr;
|
|
TLIBATTR *libattr;
|
|
HRESULT hres;
|
|
|
|
TRACE("%p %p %p\n", This, typeInfo, refType);
|
|
|
|
if (!typeInfo || !refType)
|
|
return E_INVALIDARG;
|
|
|
|
hres = ITypeInfo_GetContainingTypeLib(typeInfo, &container, &index);
|
|
if (FAILED(hres))
|
|
return hres;
|
|
|
|
if (container == (ITypeLib*)&This->pTypeLib->ITypeLib2_iface) {
|
|
ITypeInfoImpl *target = impl_from_ITypeInfo(typeInfo);
|
|
|
|
ITypeLib_Release(container);
|
|
|
|
*refType = target->hreftype;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
hres = ITypeLib_GetLibAttr(container, &libattr);
|
|
if (FAILED(hres)) {
|
|
ITypeLib_Release(container);
|
|
return hres;
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY(implib, &This->pTypeLib->implib_list, TLBImpLib, entry){
|
|
if(IsEqualGUID(&implib->guid->guid, &libattr->guid) &&
|
|
implib->lcid == libattr->lcid &&
|
|
implib->wVersionMajor == libattr->wMajorVerNum &&
|
|
implib->wVersionMinor == libattr->wMinorVerNum)
|
|
break;
|
|
}
|
|
|
|
if(&implib->entry == &This->pTypeLib->implib_list){
|
|
implib = heap_alloc_zero(sizeof(TLBImpLib));
|
|
|
|
if((ITypeLib2Vtbl*)container->lpVtbl == &tlbvt){
|
|
const ITypeLibImpl *our_container = impl_from_ITypeLib2((ITypeLib2*)container);
|
|
implib->name = SysAllocString(our_container->path);
|
|
}else{
|
|
hres = QueryPathOfRegTypeLib(&libattr->guid, libattr->wMajorVerNum,
|
|
libattr->wMinorVerNum, libattr->lcid, &implib->name);
|
|
if(FAILED(hres)){
|
|
implib->name = NULL;
|
|
TRACE("QueryPathOfRegTypeLib failed, no name stored: %08x\n", hres);
|
|
}
|
|
}
|
|
|
|
implib->guid = TLB_append_guid(&This->pTypeLib->guid_list, &libattr->guid, 2);
|
|
implib->lcid = libattr->lcid;
|
|
implib->wVersionMajor = libattr->wMajorVerNum;
|
|
implib->wVersionMinor = libattr->wMinorVerNum;
|
|
|
|
list_add_tail(&This->pTypeLib->implib_list, &implib->entry);
|
|
}
|
|
|
|
ITypeLib_ReleaseTLibAttr(container, libattr);
|
|
ITypeLib_Release(container);
|
|
|
|
hres = ITypeInfo_GetTypeAttr(typeInfo, &typeattr);
|
|
if (FAILED(hres))
|
|
return hres;
|
|
|
|
index = 0;
|
|
LIST_FOR_EACH_ENTRY(ref_type, &This->pTypeLib->ref_list, TLBRefType, entry){
|
|
if(ref_type->index == TLB_REF_USE_GUID &&
|
|
IsEqualGUID(&ref_type->guid->guid, &typeattr->guid) &&
|
|
ref_type->tkind == typeattr->typekind)
|
|
break;
|
|
++index;
|
|
}
|
|
|
|
if(&ref_type->entry == &This->pTypeLib->ref_list){
|
|
ref_type = heap_alloc_zero(sizeof(TLBRefType));
|
|
|
|
ref_type->tkind = typeattr->typekind;
|
|
ref_type->pImpTLInfo = implib;
|
|
ref_type->reference = index * sizeof(MSFT_ImpInfo);
|
|
|
|
ref_type->index = TLB_REF_USE_GUID;
|
|
|
|
ref_type->guid = TLB_append_guid(&This->pTypeLib->guid_list, &typeattr->guid, ref_type->reference+1);
|
|
|
|
list_add_tail(&This->pTypeLib->ref_list, &ref_type->entry);
|
|
}
|
|
|
|
ITypeInfo_ReleaseTypeAttr(typeInfo, typeattr);
|
|
|
|
*refType = ref_type->reference | 0x1;
|
|
|
|
if(IsEqualGUID(&ref_type->guid->guid, &IID_IDispatch))
|
|
This->pTypeLib->dispatch_href = *refType;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnAddFuncDesc(ICreateTypeInfo2 *iface,
|
|
UINT index, FUNCDESC *funcDesc)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBFuncDesc tmp_func_desc, *func_desc;
|
|
int buf_size, i;
|
|
char *buffer;
|
|
HRESULT hres;
|
|
|
|
TRACE("%p %u %p\n", This, index, funcDesc);
|
|
|
|
if (!funcDesc || funcDesc->oVft & 3)
|
|
return E_INVALIDARG;
|
|
|
|
switch (This->typeattr.typekind) {
|
|
case TKIND_MODULE:
|
|
if (funcDesc->funckind != FUNC_STATIC)
|
|
return TYPE_E_BADMODULEKIND;
|
|
break;
|
|
case TKIND_DISPATCH:
|
|
if (funcDesc->funckind != FUNC_DISPATCH)
|
|
return TYPE_E_BADMODULEKIND;
|
|
break;
|
|
default:
|
|
if (funcDesc->funckind != FUNC_PUREVIRTUAL)
|
|
return TYPE_E_BADMODULEKIND;
|
|
}
|
|
|
|
if (index > This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
if (funcDesc->invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF) &&
|
|
!funcDesc->cParams)
|
|
return TYPE_E_INCONSISTENTPROPFUNCS;
|
|
|
|
#ifdef _WIN64
|
|
if(This->pTypeLib->syskind == SYS_WIN64 &&
|
|
funcDesc->oVft % 8 != 0)
|
|
return E_INVALIDARG;
|
|
#endif
|
|
|
|
memset(&tmp_func_desc, 0, sizeof(tmp_func_desc));
|
|
TLBFuncDesc_Constructor(&tmp_func_desc);
|
|
|
|
tmp_func_desc.funcdesc = *funcDesc;
|
|
|
|
if (tmp_func_desc.funcdesc.oVft != 0)
|
|
tmp_func_desc.funcdesc.oVft |= 1;
|
|
|
|
if (funcDesc->cScodes && funcDesc->lprgscode) {
|
|
tmp_func_desc.funcdesc.lprgscode = heap_alloc(sizeof(SCODE) * funcDesc->cScodes);
|
|
memcpy(tmp_func_desc.funcdesc.lprgscode, funcDesc->lprgscode, sizeof(SCODE) * funcDesc->cScodes);
|
|
} else {
|
|
tmp_func_desc.funcdesc.lprgscode = NULL;
|
|
tmp_func_desc.funcdesc.cScodes = 0;
|
|
}
|
|
|
|
buf_size = TLB_SizeElemDesc(&funcDesc->elemdescFunc);
|
|
for (i = 0; i < funcDesc->cParams; ++i) {
|
|
buf_size += sizeof(ELEMDESC);
|
|
buf_size += TLB_SizeElemDesc(funcDesc->lprgelemdescParam + i);
|
|
}
|
|
tmp_func_desc.funcdesc.lprgelemdescParam = heap_alloc(buf_size);
|
|
buffer = (char*)(tmp_func_desc.funcdesc.lprgelemdescParam + funcDesc->cParams);
|
|
|
|
hres = TLB_CopyElemDesc(&funcDesc->elemdescFunc, &tmp_func_desc.funcdesc.elemdescFunc, &buffer);
|
|
if (FAILED(hres)) {
|
|
heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
|
|
heap_free(tmp_func_desc.funcdesc.lprgscode);
|
|
return hres;
|
|
}
|
|
|
|
for (i = 0; i < funcDesc->cParams; ++i) {
|
|
hres = TLB_CopyElemDesc(funcDesc->lprgelemdescParam + i,
|
|
tmp_func_desc.funcdesc.lprgelemdescParam + i, &buffer);
|
|
if (FAILED(hres)) {
|
|
heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
|
|
heap_free(tmp_func_desc.funcdesc.lprgscode);
|
|
return hres;
|
|
}
|
|
if (tmp_func_desc.funcdesc.lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT &&
|
|
tmp_func_desc.funcdesc.lprgelemdescParam[i].tdesc.vt != VT_VARIANT &&
|
|
tmp_func_desc.funcdesc.lprgelemdescParam[i].tdesc.vt != VT_USERDEFINED){
|
|
hres = TLB_SanitizeVariant(&tmp_func_desc.funcdesc.lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
|
|
if (FAILED(hres)) {
|
|
heap_free(tmp_func_desc.funcdesc.lprgelemdescParam);
|
|
heap_free(tmp_func_desc.funcdesc.lprgscode);
|
|
return hres;
|
|
}
|
|
}
|
|
}
|
|
|
|
tmp_func_desc.pParamDesc = TLBParDesc_Constructor(funcDesc->cParams);
|
|
|
|
if (This->funcdescs) {
|
|
This->funcdescs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->funcdescs,
|
|
sizeof(TLBFuncDesc) * (This->typeattr.cFuncs + 1));
|
|
|
|
if (index < This->typeattr.cFuncs) {
|
|
memmove(This->funcdescs + index + 1, This->funcdescs + index,
|
|
(This->typeattr.cFuncs - index) * sizeof(TLBFuncDesc));
|
|
func_desc = This->funcdescs + index;
|
|
} else
|
|
func_desc = This->funcdescs + This->typeattr.cFuncs;
|
|
|
|
/* move custdata lists to the new memory location */
|
|
for(i = 0; i < This->typeattr.cFuncs + 1; ++i){
|
|
if(index != i){
|
|
TLBFuncDesc *fd = &This->funcdescs[i];
|
|
if(fd->custdata_list.prev == fd->custdata_list.next)
|
|
list_init(&fd->custdata_list);
|
|
else{
|
|
fd->custdata_list.prev->next = &fd->custdata_list;
|
|
fd->custdata_list.next->prev = &fd->custdata_list;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
func_desc = This->funcdescs = heap_alloc(sizeof(TLBFuncDesc));
|
|
|
|
memcpy(func_desc, &tmp_func_desc, sizeof(tmp_func_desc));
|
|
list_init(&func_desc->custdata_list);
|
|
|
|
++This->typeattr.cFuncs;
|
|
|
|
This->needs_layout = TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnAddImplType(ICreateTypeInfo2 *iface,
|
|
UINT index, HREFTYPE refType)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBImplType *impl_type;
|
|
HRESULT hres;
|
|
|
|
TRACE("%p %u %d\n", This, index, refType);
|
|
|
|
switch(This->typeattr.typekind){
|
|
case TKIND_COCLASS: {
|
|
if (index == -1) {
|
|
FIXME("Unhandled index: -1\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
if(index != This->typeattr.cImplTypes)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
break;
|
|
}
|
|
case TKIND_INTERFACE:
|
|
case TKIND_DISPATCH:
|
|
if (index != 0 || This->typeattr.cImplTypes)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
break;
|
|
default:
|
|
FIXME("Unimplemented typekind: %d\n", This->typeattr.typekind);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
if (This->impltypes){
|
|
UINT i;
|
|
|
|
This->impltypes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->impltypes,
|
|
sizeof(TLBImplType) * (This->typeattr.cImplTypes + 1));
|
|
|
|
if (index < This->typeattr.cImplTypes) {
|
|
memmove(This->impltypes + index + 1, This->impltypes + index,
|
|
(This->typeattr.cImplTypes - index) * sizeof(TLBImplType));
|
|
impl_type = This->impltypes + index;
|
|
} else
|
|
impl_type = This->impltypes + This->typeattr.cImplTypes;
|
|
|
|
/* move custdata lists to the new memory location */
|
|
for(i = 0; i < This->typeattr.cImplTypes + 1; ++i){
|
|
if(index != i){
|
|
TLBImplType *it = &This->impltypes[i];
|
|
if(it->custdata_list.prev == it->custdata_list.next)
|
|
list_init(&it->custdata_list);
|
|
else{
|
|
it->custdata_list.prev->next = &it->custdata_list;
|
|
it->custdata_list.next->prev = &it->custdata_list;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
impl_type = This->impltypes = heap_alloc(sizeof(TLBImplType));
|
|
|
|
memset(impl_type, 0, sizeof(TLBImplType));
|
|
TLBImplType_Constructor(impl_type);
|
|
impl_type->hRef = refType;
|
|
|
|
++This->typeattr.cImplTypes;
|
|
|
|
if((refType & (~0x3)) == (This->pTypeLib->dispatch_href & (~0x3)))
|
|
This->typeattr.wTypeFlags |= TYPEFLAG_FDISPATCHABLE;
|
|
|
|
hres = ICreateTypeInfo2_LayOut(iface);
|
|
if (FAILED(hres))
|
|
return hres;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeFlags(ICreateTypeInfo2 *iface,
|
|
UINT index, INT implTypeFlags)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBImplType *impl_type = &This->impltypes[index];
|
|
|
|
TRACE("%p %u %x\n", This, index, implTypeFlags);
|
|
|
|
if (This->typeattr.typekind != TKIND_COCLASS)
|
|
return TYPE_E_BADMODULEKIND;
|
|
|
|
if (index >= This->typeattr.cImplTypes)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
impl_type->implflags = implTypeFlags;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetAlignment(ICreateTypeInfo2 *iface,
|
|
WORD alignment)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %d\n", This, alignment);
|
|
|
|
This->typeattr.cbAlignment = alignment;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetSchema(ICreateTypeInfo2 *iface,
|
|
LPOLESTR schema)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %s\n", This, wine_dbgstr_w(schema));
|
|
|
|
if (!schema)
|
|
return E_INVALIDARG;
|
|
|
|
This->Schema = TLB_append_str(&This->pTypeLib->string_list, schema);
|
|
|
|
This->typeattr.lpstrSchema = This->Schema->str;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnAddVarDesc(ICreateTypeInfo2 *iface,
|
|
UINT index, VARDESC *varDesc)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBVarDesc *var_desc;
|
|
|
|
TRACE("%p %u %p\n", This, index, varDesc);
|
|
|
|
if (This->vardescs){
|
|
UINT i;
|
|
|
|
This->vardescs = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->vardescs,
|
|
sizeof(TLBVarDesc) * (This->typeattr.cVars + 1));
|
|
|
|
if (index < This->typeattr.cVars) {
|
|
memmove(This->vardescs + index + 1, This->vardescs + index,
|
|
(This->typeattr.cVars - index) * sizeof(TLBVarDesc));
|
|
var_desc = This->vardescs + index;
|
|
} else
|
|
var_desc = This->vardescs + This->typeattr.cVars;
|
|
|
|
/* move custdata lists to the new memory location */
|
|
for(i = 0; i < This->typeattr.cVars + 1; ++i){
|
|
if(index != i){
|
|
TLBVarDesc *var = &This->vardescs[i];
|
|
if(var->custdata_list.prev == var->custdata_list.next)
|
|
list_init(&var->custdata_list);
|
|
else{
|
|
var->custdata_list.prev->next = &var->custdata_list;
|
|
var->custdata_list.next->prev = &var->custdata_list;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
var_desc = This->vardescs = heap_alloc_zero(sizeof(TLBVarDesc));
|
|
|
|
TLBVarDesc_Constructor(var_desc);
|
|
TLB_AllocAndInitVarDesc(varDesc, &var_desc->vardesc_create);
|
|
var_desc->vardesc = *var_desc->vardesc_create;
|
|
|
|
++This->typeattr.cVars;
|
|
|
|
This->needs_layout = TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncAndParamNames(ICreateTypeInfo2 *iface,
|
|
UINT index, LPOLESTR *names, UINT numNames)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBFuncDesc *func_desc = &This->funcdescs[index];
|
|
int i;
|
|
|
|
TRACE("%p %u %p %u\n", This, index, names, numNames);
|
|
|
|
if (!names)
|
|
return E_INVALIDARG;
|
|
|
|
if (index >= This->typeattr.cFuncs || numNames == 0)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
if (func_desc->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF)){
|
|
if(numNames > func_desc->funcdesc.cParams)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
} else
|
|
if(numNames > func_desc->funcdesc.cParams + 1)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
for(i = 0; i < This->typeattr.cFuncs; ++i) {
|
|
TLBFuncDesc *iter = &This->funcdescs[i];
|
|
if (iter->Name && !strcmpW(TLB_get_bstr(iter->Name), *names)) {
|
|
if (iter->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF | INVOKE_PROPERTYGET) &&
|
|
func_desc->funcdesc.invkind & (INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF | INVOKE_PROPERTYGET) &&
|
|
func_desc->funcdesc.invkind != iter->funcdesc.invkind)
|
|
continue;
|
|
return TYPE_E_AMBIGUOUSNAME;
|
|
}
|
|
}
|
|
|
|
func_desc->Name = TLB_append_str(&This->pTypeLib->name_list, *names);
|
|
|
|
for (i = 1; i < numNames; ++i) {
|
|
TLBParDesc *par_desc = func_desc->pParamDesc + i - 1;
|
|
par_desc->Name = TLB_append_str(&This->pTypeLib->name_list, *(names + i));
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetVarName(ICreateTypeInfo2 *iface,
|
|
UINT index, LPOLESTR name)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %u %s\n", This, index, wine_dbgstr_w(name));
|
|
|
|
if(!name)
|
|
return E_INVALIDARG;
|
|
|
|
if(index >= This->typeattr.cVars)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
This->vardescs[index].Name = TLB_append_str(&This->pTypeLib->name_list, name);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeDescAlias(ICreateTypeInfo2 *iface,
|
|
TYPEDESC *tdescAlias)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("%p %p\n", This, tdescAlias);
|
|
|
|
if(!tdescAlias)
|
|
return E_INVALIDARG;
|
|
|
|
if(This->typeattr.typekind != TKIND_ALIAS)
|
|
return TYPE_E_BADMODULEKIND;
|
|
|
|
hr = TLB_size_instance(This, This->pTypeLib->syskind, tdescAlias, &This->typeattr.cbSizeInstance, &This->typeattr.cbAlignment);
|
|
if(FAILED(hr))
|
|
return hr;
|
|
|
|
heap_free(This->tdescAlias);
|
|
This->tdescAlias = heap_alloc(TLB_SizeTypeDesc(tdescAlias, TRUE));
|
|
TLB_CopyTypeDesc(NULL, tdescAlias, This->tdescAlias);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnDefineFuncAsDllEntry(ICreateTypeInfo2 *iface,
|
|
UINT index, LPOLESTR dllName, LPOLESTR procName)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %s %s - stub\n", This, index, wine_dbgstr_w(dllName), wine_dbgstr_w(procName));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncDocString(ICreateTypeInfo2 *iface,
|
|
UINT index, LPOLESTR docString)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBFuncDesc *func_desc = &This->funcdescs[index];
|
|
|
|
TRACE("%p %u %s\n", This, index, wine_dbgstr_w(docString));
|
|
|
|
if(!docString)
|
|
return E_INVALIDARG;
|
|
|
|
if(index >= This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
func_desc->HelpString = TLB_append_str(&This->pTypeLib->string_list, docString);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetVarDocString(ICreateTypeInfo2 *iface,
|
|
UINT index, LPOLESTR docString)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBVarDesc *var_desc = &This->vardescs[index];
|
|
|
|
TRACE("%p %u %s\n", This, index, wine_dbgstr_w(docString));
|
|
|
|
if(!docString)
|
|
return E_INVALIDARG;
|
|
|
|
if(index >= This->typeattr.cVars)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
var_desc->HelpString = TLB_append_str(&This->pTypeLib->string_list, docString);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpContext(ICreateTypeInfo2 *iface,
|
|
UINT index, DWORD helpContext)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBFuncDesc *func_desc = &This->funcdescs[index];
|
|
|
|
TRACE("%p %u %d\n", This, index, helpContext);
|
|
|
|
if(index >= This->typeattr.cFuncs)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
func_desc->helpcontext = helpContext;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpContext(ICreateTypeInfo2 *iface,
|
|
UINT index, DWORD helpContext)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
TLBVarDesc *var_desc = &This->vardescs[index];
|
|
|
|
TRACE("%p %u %d\n", This, index, helpContext);
|
|
|
|
if(index >= This->typeattr.cVars)
|
|
return TYPE_E_ELEMENTNOTFOUND;
|
|
|
|
var_desc->HelpContext = helpContext;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetMops(ICreateTypeInfo2 *iface,
|
|
UINT index, BSTR bstrMops)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %s - stub\n", This, index, wine_dbgstr_w(bstrMops));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeIdldesc(ICreateTypeInfo2 *iface,
|
|
IDLDESC *idlDesc)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %p\n", This, idlDesc);
|
|
|
|
if (!idlDesc)
|
|
return E_INVALIDARG;
|
|
|
|
This->typeattr.idldescType.dwReserved = idlDesc->dwReserved;
|
|
This->typeattr.idldescType.wIDLFlags = idlDesc->wIDLFlags;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnLayOut(ICreateTypeInfo2 *iface)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
ITypeInfo *tinfo;
|
|
TLBFuncDesc *func_desc;
|
|
UINT user_vft = 0, i, depth = 0;
|
|
HRESULT hres = S_OK;
|
|
|
|
TRACE("%p\n", This);
|
|
|
|
This->needs_layout = FALSE;
|
|
|
|
hres = ICreateTypeInfo2_QueryInterface(iface, &IID_ITypeInfo, (LPVOID*)&tinfo);
|
|
if (FAILED(hres))
|
|
return hres;
|
|
|
|
if (This->typeattr.typekind == TKIND_INTERFACE) {
|
|
ITypeInfo *inh;
|
|
TYPEATTR *attr;
|
|
HREFTYPE inh_href;
|
|
|
|
hres = ITypeInfo_GetRefTypeOfImplType(tinfo, 0, &inh_href);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
hres = ITypeInfo_GetRefTypeInfo(tinfo, inh_href, &inh);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
hres = ITypeInfo_GetTypeAttr(inh, &attr);
|
|
if (FAILED(hres)) {
|
|
ITypeInfo_Release(inh);
|
|
ITypeInfo_Release(tinfo);
|
|
return hres;
|
|
}
|
|
This->typeattr.cbSizeVft = attr->cbSizeVft;
|
|
ITypeInfo_ReleaseTypeAttr(inh, attr);
|
|
|
|
do{
|
|
++depth;
|
|
hres = ITypeInfo_GetRefTypeOfImplType(inh, 0, &inh_href);
|
|
if(SUCCEEDED(hres)){
|
|
ITypeInfo *next;
|
|
hres = ITypeInfo_GetRefTypeInfo(inh, inh_href, &next);
|
|
if(SUCCEEDED(hres)){
|
|
ITypeInfo_Release(inh);
|
|
inh = next;
|
|
}
|
|
}
|
|
}while(SUCCEEDED(hres));
|
|
hres = S_OK;
|
|
|
|
ITypeInfo_Release(inh);
|
|
} else if (hres == TYPE_E_ELEMENTNOTFOUND) {
|
|
This->typeattr.cbSizeVft = 0;
|
|
hres = S_OK;
|
|
} else {
|
|
ITypeInfo_Release(tinfo);
|
|
return hres;
|
|
}
|
|
} else if (hres == TYPE_E_ELEMENTNOTFOUND) {
|
|
This->typeattr.cbSizeVft = 0;
|
|
hres = S_OK;
|
|
} else {
|
|
ITypeInfo_Release(tinfo);
|
|
return hres;
|
|
}
|
|
} else if (This->typeattr.typekind == TKIND_DISPATCH)
|
|
This->typeattr.cbSizeVft = 7 * This->pTypeLib->ptr_size;
|
|
else
|
|
This->typeattr.cbSizeVft = 0;
|
|
|
|
func_desc = This->funcdescs;
|
|
i = 0;
|
|
while (i < This->typeattr.cFuncs) {
|
|
if (!(func_desc->funcdesc.oVft & 0x1))
|
|
func_desc->funcdesc.oVft = This->typeattr.cbSizeVft;
|
|
|
|
if ((func_desc->funcdesc.oVft & 0xFFFC) > user_vft)
|
|
user_vft = func_desc->funcdesc.oVft & 0xFFFC;
|
|
|
|
This->typeattr.cbSizeVft += This->pTypeLib->ptr_size;
|
|
|
|
if (func_desc->funcdesc.memid == MEMBERID_NIL) {
|
|
TLBFuncDesc *iter;
|
|
UINT j = 0;
|
|
BOOL reset = FALSE;
|
|
|
|
func_desc->funcdesc.memid = 0x60000000 + (depth << 16) + i;
|
|
|
|
iter = This->funcdescs;
|
|
while (j < This->typeattr.cFuncs) {
|
|
if (iter != func_desc && iter->funcdesc.memid == func_desc->funcdesc.memid) {
|
|
if (!reset) {
|
|
func_desc->funcdesc.memid = 0x60000000 + (depth << 16) + This->typeattr.cFuncs;
|
|
reset = TRUE;
|
|
} else
|
|
++func_desc->funcdesc.memid;
|
|
iter = This->funcdescs;
|
|
j = 0;
|
|
} else {
|
|
++iter;
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
|
|
++func_desc;
|
|
++i;
|
|
}
|
|
|
|
if (user_vft > This->typeattr.cbSizeVft)
|
|
This->typeattr.cbSizeVft = user_vft + This->pTypeLib->ptr_size;
|
|
|
|
for(i = 0; i < This->typeattr.cVars; ++i){
|
|
TLBVarDesc *var_desc = &This->vardescs[i];
|
|
if(var_desc->vardesc.memid == MEMBERID_NIL){
|
|
UINT j = 0;
|
|
BOOL reset = FALSE;
|
|
TLBVarDesc *iter;
|
|
|
|
var_desc->vardesc.memid = 0x40000000 + (depth << 16) + i;
|
|
|
|
iter = This->vardescs;
|
|
while (j < This->typeattr.cVars) {
|
|
if (iter != var_desc && iter->vardesc.memid == var_desc->vardesc.memid) {
|
|
if (!reset) {
|
|
var_desc->vardesc.memid = 0x40000000 + (depth << 16) + This->typeattr.cVars;
|
|
reset = TRUE;
|
|
} else
|
|
++var_desc->vardesc.memid;
|
|
iter = This->vardescs;
|
|
j = 0;
|
|
} else {
|
|
++iter;
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ITypeInfo_Release(tinfo);
|
|
return hres;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDesc(ICreateTypeInfo2 *iface,
|
|
UINT index)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u - stub\n", This, index);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDescByMemId(ICreateTypeInfo2 *iface,
|
|
MEMBERID memid, INVOKEKIND invKind)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %x %d - stub\n", This, memid, invKind);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDesc(ICreateTypeInfo2 *iface,
|
|
UINT index)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u - stub\n", This, index);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDescByMemId(ICreateTypeInfo2 *iface,
|
|
MEMBERID memid)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %x - stub\n", This, memid);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnDeleteImplType(ICreateTypeInfo2 *iface,
|
|
UINT index)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u - stub\n", This, index);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetCustData(ICreateTypeInfo2 *iface,
|
|
REFGUID guid, VARIANT *varVal)
|
|
{
|
|
TLBGuid *tlbguid;
|
|
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %s %p\n", This, debugstr_guid(guid), varVal);
|
|
|
|
if (!guid || !varVal)
|
|
return E_INVALIDARG;
|
|
|
|
tlbguid = TLB_append_guid(&This->pTypeLib->guid_list, guid, -1);
|
|
|
|
return TLB_set_custdata(This->pcustdata_list, tlbguid, varVal);
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncCustData(ICreateTypeInfo2 *iface,
|
|
UINT index, REFGUID guid, VARIANT *varVal)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetParamCustData(ICreateTypeInfo2 *iface,
|
|
UINT funcIndex, UINT paramIndex, REFGUID guid, VARIANT *varVal)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %u %s %p - stub\n", This, funcIndex, paramIndex, debugstr_guid(guid), varVal);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetVarCustData(ICreateTypeInfo2 *iface,
|
|
UINT index, REFGUID guid, VARIANT *varVal)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeCustData(ICreateTypeInfo2 *iface,
|
|
UINT index, REFGUID guid, VARIANT *varVal)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %s %p - stub\n", This, index, debugstr_guid(guid), varVal);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpStringContext(ICreateTypeInfo2 *iface,
|
|
ULONG helpStringContext)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %u\n", This, helpStringContext);
|
|
|
|
This->dwHelpStringContext = helpStringContext;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpStringContext(ICreateTypeInfo2 *iface,
|
|
UINT index, ULONG helpStringContext)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %u - stub\n", This, index, helpStringContext);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpStringContext(ICreateTypeInfo2 *iface,
|
|
UINT index, ULONG helpStringContext)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p %u %u - stub\n", This, index, helpStringContext);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnInvalidate(ICreateTypeInfo2 *iface)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
FIXME("%p - stub\n", This);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICreateTypeInfo2_fnSetName(ICreateTypeInfo2 *iface,
|
|
LPOLESTR name)
|
|
{
|
|
ITypeInfoImpl *This = info_impl_from_ICreateTypeInfo2(iface);
|
|
|
|
TRACE("%p %s\n", This, wine_dbgstr_w(name));
|
|
|
|
if (!name)
|
|
return E_INVALIDARG;
|
|
|
|
This->Name = TLB_append_str(&This->pTypeLib->name_list, name);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const ICreateTypeInfo2Vtbl CreateTypeInfo2Vtbl = {
|
|
ICreateTypeInfo2_fnQueryInterface,
|
|
ICreateTypeInfo2_fnAddRef,
|
|
ICreateTypeInfo2_fnRelease,
|
|
ICreateTypeInfo2_fnSetGuid,
|
|
ICreateTypeInfo2_fnSetTypeFlags,
|
|
ICreateTypeInfo2_fnSetDocString,
|
|
ICreateTypeInfo2_fnSetHelpContext,
|
|
ICreateTypeInfo2_fnSetVersion,
|
|
ICreateTypeInfo2_fnAddRefTypeInfo,
|
|
ICreateTypeInfo2_fnAddFuncDesc,
|
|
ICreateTypeInfo2_fnAddImplType,
|
|
ICreateTypeInfo2_fnSetImplTypeFlags,
|
|
ICreateTypeInfo2_fnSetAlignment,
|
|
ICreateTypeInfo2_fnSetSchema,
|
|
ICreateTypeInfo2_fnAddVarDesc,
|
|
ICreateTypeInfo2_fnSetFuncAndParamNames,
|
|
ICreateTypeInfo2_fnSetVarName,
|
|
ICreateTypeInfo2_fnSetTypeDescAlias,
|
|
ICreateTypeInfo2_fnDefineFuncAsDllEntry,
|
|
ICreateTypeInfo2_fnSetFuncDocString,
|
|
ICreateTypeInfo2_fnSetVarDocString,
|
|
ICreateTypeInfo2_fnSetFuncHelpContext,
|
|
ICreateTypeInfo2_fnSetVarHelpContext,
|
|
ICreateTypeInfo2_fnSetMops,
|
|
ICreateTypeInfo2_fnSetTypeIdldesc,
|
|
ICreateTypeInfo2_fnLayOut,
|
|
ICreateTypeInfo2_fnDeleteFuncDesc,
|
|
ICreateTypeInfo2_fnDeleteFuncDescByMemId,
|
|
ICreateTypeInfo2_fnDeleteVarDesc,
|
|
ICreateTypeInfo2_fnDeleteVarDescByMemId,
|
|
ICreateTypeInfo2_fnDeleteImplType,
|
|
ICreateTypeInfo2_fnSetCustData,
|
|
ICreateTypeInfo2_fnSetFuncCustData,
|
|
ICreateTypeInfo2_fnSetParamCustData,
|
|
ICreateTypeInfo2_fnSetVarCustData,
|
|
ICreateTypeInfo2_fnSetImplTypeCustData,
|
|
ICreateTypeInfo2_fnSetHelpStringContext,
|
|
ICreateTypeInfo2_fnSetFuncHelpStringContext,
|
|
ICreateTypeInfo2_fnSetVarHelpStringContext,
|
|
ICreateTypeInfo2_fnInvalidate,
|
|
ICreateTypeInfo2_fnSetName
|
|
};
|
|
|
|
/******************************************************************************
|
|
* ClearCustData (OLEAUT32.171)
|
|
*
|
|
* Clear a custom data type's data.
|
|
*
|
|
* PARAMS
|
|
* lpCust [I] The custom data type instance
|
|
*
|
|
* RETURNS
|
|
* Nothing.
|
|
*/
|
|
void WINAPI ClearCustData(CUSTDATA *lpCust)
|
|
{
|
|
if (lpCust && lpCust->cCustData)
|
|
{
|
|
if (lpCust->prgCustData)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < lpCust->cCustData; i++)
|
|
VariantClear(&lpCust->prgCustData[i].varValue);
|
|
|
|
CoTaskMemFree(lpCust->prgCustData);
|
|
lpCust->prgCustData = NULL;
|
|
}
|
|
lpCust->cCustData = 0;
|
|
}
|
|
}
|