2012-03-14 09:44:12 +01:00
|
|
|
/*
|
|
|
|
* IAssemblyName implementation
|
|
|
|
*
|
|
|
|
* Copyright 2012 Hans Leidekker 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "ole2.h"
|
|
|
|
#include "winsxs.h"
|
|
|
|
|
|
|
|
#include "wine/debug.h"
|
2012-03-28 15:33:30 +02:00
|
|
|
#include "sxs_private.h"
|
2012-03-14 09:44:12 +01:00
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(sxs);
|
|
|
|
|
|
|
|
struct name
|
|
|
|
{
|
|
|
|
IAssemblyName IAssemblyName_iface;
|
|
|
|
LONG refs;
|
2012-03-28 15:33:30 +02:00
|
|
|
WCHAR *name;
|
|
|
|
WCHAR *arch;
|
|
|
|
WCHAR *token;
|
|
|
|
WCHAR *type;
|
|
|
|
WCHAR *version;
|
2012-03-14 09:44:12 +01:00
|
|
|
};
|
|
|
|
|
2012-03-28 15:33:30 +02:00
|
|
|
static const WCHAR archW[] = {'p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e',0};
|
|
|
|
static const WCHAR tokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
|
|
|
|
static const WCHAR typeW[] = {'t','y','p','e',0};
|
|
|
|
static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
|
|
|
|
|
2012-03-14 09:44:12 +01:00
|
|
|
static inline struct name *impl_from_IAssemblyName( IAssemblyName *iface )
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD( iface, struct name, IAssemblyName_iface );
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_QueryInterface(
|
|
|
|
IAssemblyName *iface,
|
|
|
|
REFIID riid,
|
|
|
|
void **obj )
|
|
|
|
{
|
|
|
|
struct name *name = impl_from_IAssemblyName( iface );
|
|
|
|
|
|
|
|
TRACE("%p, %s, %p\n", name, debugstr_guid(riid), obj);
|
|
|
|
|
|
|
|
*obj = NULL;
|
|
|
|
|
|
|
|
if (IsEqualIID( riid, &IID_IUnknown ) ||
|
|
|
|
IsEqualIID( riid, &IID_IAssemblyName ))
|
|
|
|
{
|
2012-07-31 12:25:08 +02:00
|
|
|
IAssemblyName_AddRef( iface );
|
2012-03-14 09:44:12 +01:00
|
|
|
*obj = name;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI name_AddRef(
|
|
|
|
IAssemblyName *iface )
|
|
|
|
{
|
|
|
|
struct name *name = impl_from_IAssemblyName( iface );
|
|
|
|
return InterlockedIncrement( &name->refs );
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI name_Release( IAssemblyName *iface )
|
|
|
|
{
|
|
|
|
struct name *name = impl_from_IAssemblyName( iface );
|
|
|
|
ULONG refs = InterlockedDecrement( &name->refs );
|
|
|
|
|
|
|
|
if (!refs)
|
|
|
|
{
|
|
|
|
TRACE("destroying %p\n", name);
|
2012-03-28 15:33:30 +02:00
|
|
|
HeapFree( GetProcessHeap(), 0, name->name );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->arch );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->token );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->type );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->version );
|
2012-03-14 09:44:12 +01:00
|
|
|
HeapFree( GetProcessHeap(), 0, name );
|
|
|
|
}
|
|
|
|
return refs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_SetProperty(
|
|
|
|
IAssemblyName *iface,
|
|
|
|
DWORD id,
|
|
|
|
LPVOID property,
|
|
|
|
DWORD size )
|
|
|
|
{
|
|
|
|
FIXME("%p, %d, %p, %d\n", iface, id, property, size);
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_GetProperty(
|
|
|
|
IAssemblyName *iface,
|
|
|
|
DWORD id,
|
|
|
|
LPVOID buffer,
|
|
|
|
LPDWORD buflen )
|
|
|
|
{
|
|
|
|
FIXME("%p, %d, %p, %p\n", iface, id, buffer, buflen);
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_Finalize(
|
|
|
|
IAssemblyName *iface )
|
|
|
|
{
|
|
|
|
FIXME("%p\n", iface);
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_GetDisplayName(
|
|
|
|
IAssemblyName *iface,
|
|
|
|
LPOLESTR buffer,
|
|
|
|
LPDWORD buflen,
|
|
|
|
DWORD flags )
|
|
|
|
{
|
2012-03-28 15:33:30 +02:00
|
|
|
static const WCHAR fmtW[] = {',','%','s','=','\"','%','s','\"',0};
|
|
|
|
struct name *name = impl_from_IAssemblyName( iface );
|
|
|
|
WCHAR version[30];
|
|
|
|
unsigned int len;
|
|
|
|
|
|
|
|
TRACE("%p, %p, %p, 0x%08x\n", iface, buffer, buflen, flags);
|
|
|
|
|
|
|
|
if (!buflen || flags) return E_INVALIDARG;
|
|
|
|
|
2019-06-21 08:50:39 +02:00
|
|
|
len = lstrlenW( name->name ) + 1;
|
|
|
|
if (name->arch) len += lstrlenW( archW ) + lstrlenW( name->arch ) + 4;
|
|
|
|
if (name->token) len += lstrlenW( tokenW ) + lstrlenW( name->token ) + 4;
|
|
|
|
if (name->type) len += lstrlenW( typeW ) + lstrlenW( name->type ) + 4;
|
|
|
|
if (name->version) len += lstrlenW( versionW ) + lstrlenW( version ) + 4;
|
2012-03-28 15:33:30 +02:00
|
|
|
if (len > *buflen)
|
|
|
|
{
|
|
|
|
*buflen = len;
|
|
|
|
return HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
|
|
|
|
}
|
2019-06-21 08:50:39 +02:00
|
|
|
lstrcpyW( buffer, name->name );
|
|
|
|
len = lstrlenW( buffer );
|
|
|
|
if (name->arch) len += swprintf( buffer + len, *buflen - len, fmtW, archW, name->arch );
|
|
|
|
if (name->token) len += swprintf( buffer + len, *buflen - len, fmtW, tokenW, name->token );
|
|
|
|
if (name->type) len += swprintf( buffer + len, *buflen - len, fmtW, typeW, name->type );
|
|
|
|
if (name->version) len += swprintf( buffer + len, *buflen - len, fmtW, versionW, name->version );
|
2012-03-28 15:33:30 +02:00
|
|
|
return S_OK;
|
2012-03-14 09:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_Reserved(
|
|
|
|
IAssemblyName *iface,
|
|
|
|
REFIID riid,
|
|
|
|
IUnknown *pUnkReserved1,
|
|
|
|
IUnknown *pUnkReserved2,
|
|
|
|
LPCOLESTR szReserved,
|
|
|
|
LONGLONG llReserved,
|
|
|
|
LPVOID pvReserved,
|
|
|
|
DWORD cbReserved,
|
|
|
|
LPVOID *ppReserved )
|
|
|
|
{
|
2017-08-22 23:50:03 +02:00
|
|
|
FIXME("%p, %s, %p, %p, %s, %s, %p, %d, %p\n", iface,
|
2012-03-14 09:44:12 +01:00
|
|
|
debugstr_guid(riid), pUnkReserved1, pUnkReserved2,
|
2017-08-22 23:50:03 +02:00
|
|
|
debugstr_w(szReserved), wine_dbgstr_longlong(llReserved),
|
2012-03-14 09:44:12 +01:00
|
|
|
pvReserved, cbReserved, ppReserved);
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2012-03-28 15:33:30 +02:00
|
|
|
const WCHAR *get_name_attribute( IAssemblyName *iface, enum name_attr_id id )
|
|
|
|
{
|
|
|
|
struct name *name = impl_from_IAssemblyName( iface );
|
|
|
|
|
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case NAME_ATTR_ID_NAME: return name->name;
|
|
|
|
case NAME_ATTR_ID_ARCH: return name->arch;
|
|
|
|
case NAME_ATTR_ID_TOKEN: return name->token;
|
|
|
|
case NAME_ATTR_ID_TYPE: return name->type;
|
|
|
|
case NAME_ATTR_ID_VERSION: return name->version;
|
|
|
|
default:
|
|
|
|
ERR("unhandled name attribute %u\n", id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-14 09:44:12 +01:00
|
|
|
static HRESULT WINAPI name_GetName(
|
|
|
|
IAssemblyName *iface,
|
|
|
|
LPDWORD buflen,
|
|
|
|
WCHAR *buffer )
|
|
|
|
{
|
2012-03-28 15:33:30 +02:00
|
|
|
const WCHAR *name;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
TRACE("%p, %p, %p\n", iface, buflen, buffer);
|
|
|
|
|
|
|
|
if (!buflen || !buffer) return E_INVALIDARG;
|
|
|
|
|
|
|
|
name = get_name_attribute( iface, NAME_ATTR_ID_NAME );
|
2019-06-21 08:50:39 +02:00
|
|
|
len = lstrlenW( name ) + 1;
|
2012-03-28 15:33:30 +02:00
|
|
|
if (len > *buflen)
|
|
|
|
{
|
|
|
|
*buflen = len;
|
|
|
|
return HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
|
|
|
|
}
|
2019-06-21 08:50:39 +02:00
|
|
|
lstrcpyW( buffer, name );
|
2012-03-28 15:33:30 +02:00
|
|
|
*buflen = len + 3;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT parse_version( WCHAR *version, DWORD *high, DWORD *low )
|
|
|
|
{
|
|
|
|
WORD ver[4];
|
|
|
|
WCHAR *p, *q;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
memset( ver, 0, sizeof(ver) );
|
|
|
|
for (i = 0, p = version; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (!*p) break;
|
2019-06-21 08:50:39 +02:00
|
|
|
q = wcschr( p, '.' );
|
2012-03-28 15:33:30 +02:00
|
|
|
if (q) *q = 0;
|
2019-06-21 08:50:39 +02:00
|
|
|
ver[i] = wcstol( p, NULL, 10 );
|
2012-03-28 15:33:30 +02:00
|
|
|
if (!q && i < 3) break;
|
|
|
|
p = q + 1;
|
|
|
|
}
|
|
|
|
*high = (ver[0] << 16) + ver[1];
|
|
|
|
*low = (ver[2] << 16) + ver[3];
|
|
|
|
return S_OK;
|
2012-03-14 09:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_GetVersion(
|
|
|
|
IAssemblyName *iface,
|
2012-03-28 15:33:30 +02:00
|
|
|
LPDWORD high,
|
2012-03-14 09:44:12 +01:00
|
|
|
LPDWORD low )
|
|
|
|
{
|
2012-03-28 15:33:30 +02:00
|
|
|
struct name *name = impl_from_IAssemblyName( iface );
|
|
|
|
WCHAR *version;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
TRACE("%p, %p, %p\n", iface, high, low);
|
|
|
|
|
|
|
|
if (!name->version) return HRESULT_FROM_WIN32( ERROR_NOT_FOUND );
|
|
|
|
if (!(version = strdupW( name->version ))) return E_OUTOFMEMORY;
|
|
|
|
hr = parse_version( version, high, low );
|
|
|
|
HeapFree( GetProcessHeap(), 0, version );
|
|
|
|
return hr;
|
2012-03-14 09:44:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_IsEqual(
|
|
|
|
IAssemblyName *name1,
|
|
|
|
IAssemblyName *name2,
|
|
|
|
DWORD flags )
|
|
|
|
{
|
|
|
|
FIXME("%p, %p, 0x%08x\n", name1, name2, flags);
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI name_Clone(
|
|
|
|
IAssemblyName *iface,
|
|
|
|
IAssemblyName **name )
|
|
|
|
{
|
|
|
|
FIXME("%p, %p\n", iface, name);
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const IAssemblyNameVtbl name_vtbl =
|
|
|
|
{
|
|
|
|
name_QueryInterface,
|
|
|
|
name_AddRef,
|
|
|
|
name_Release,
|
|
|
|
name_SetProperty,
|
|
|
|
name_GetProperty,
|
|
|
|
name_Finalize,
|
|
|
|
name_GetDisplayName,
|
|
|
|
name_Reserved,
|
|
|
|
name_GetName,
|
|
|
|
name_GetVersion,
|
|
|
|
name_IsEqual,
|
|
|
|
name_Clone
|
|
|
|
};
|
|
|
|
|
2012-03-28 15:33:30 +02:00
|
|
|
static WCHAR *parse_value( const WCHAR *str, unsigned int *len )
|
|
|
|
{
|
|
|
|
WCHAR *ret;
|
|
|
|
const WCHAR *p = str;
|
|
|
|
|
|
|
|
if (*p++ != '\"') return NULL;
|
|
|
|
while (*p && *p != '\"') p++;
|
|
|
|
if (!*p) return NULL;
|
|
|
|
|
|
|
|
*len = p - str;
|
|
|
|
if (!(ret = HeapAlloc( GetProcessHeap(), 0, *len * sizeof(WCHAR) ))) return NULL;
|
|
|
|
memcpy( ret, str + 1, (*len - 1) * sizeof(WCHAR) );
|
|
|
|
ret[*len - 1] = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT parse_displayname( struct name *name, const WCHAR *displayname )
|
|
|
|
{
|
|
|
|
const WCHAR *p, *q;
|
|
|
|
unsigned int len;
|
|
|
|
|
|
|
|
p = q = displayname;
|
|
|
|
while (*q && *q != ',') q++;
|
|
|
|
len = q - p;
|
|
|
|
if (!(name->name = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
|
|
|
|
memcpy( name->name, p, len * sizeof(WCHAR) );
|
|
|
|
name->name[len] = 0;
|
|
|
|
if (!*q) return S_OK;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
p = ++q;
|
|
|
|
while (*q && *q != '=') q++;
|
|
|
|
if (!*q) return E_INVALIDARG;
|
|
|
|
len = q - p;
|
2018-07-18 23:01:33 +02:00
|
|
|
if (len == ARRAY_SIZE(archW) - 1 && !memcmp( p, archW, len * sizeof(WCHAR) ))
|
2012-03-28 15:33:30 +02:00
|
|
|
{
|
|
|
|
p = ++q;
|
|
|
|
if (!(name->arch = parse_value( p, &len ))) return E_INVALIDARG;
|
|
|
|
q += len;
|
|
|
|
}
|
2018-07-18 23:01:33 +02:00
|
|
|
else if (len == ARRAY_SIZE(tokenW) - 1 && !memcmp( p, tokenW, len * sizeof(WCHAR) ))
|
2012-03-28 15:33:30 +02:00
|
|
|
{
|
|
|
|
p = ++q;
|
|
|
|
if (!(name->token = parse_value( p, &len ))) return E_INVALIDARG;
|
|
|
|
q += len;
|
|
|
|
}
|
2018-07-18 23:01:33 +02:00
|
|
|
else if (len == ARRAY_SIZE(typeW) - 1 && !memcmp( p, typeW, len * sizeof(WCHAR) ))
|
2012-03-28 15:33:30 +02:00
|
|
|
{
|
|
|
|
p = ++q;
|
|
|
|
if (!(name->type = parse_value( p, &len ))) return E_INVALIDARG;
|
|
|
|
q += len;
|
|
|
|
}
|
2018-07-18 23:01:33 +02:00
|
|
|
else if (len == ARRAY_SIZE(versionW) - 1 && !memcmp( p, versionW, len * sizeof(WCHAR) ))
|
2012-03-28 15:33:30 +02:00
|
|
|
{
|
|
|
|
p = ++q;
|
|
|
|
if (!(name->version = parse_value( p, &len ))) return E_INVALIDARG;
|
|
|
|
q += len;
|
|
|
|
}
|
|
|
|
else return HRESULT_FROM_WIN32( ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME );
|
|
|
|
while (*q && *q != ',') q++;
|
|
|
|
if (!*q) break;
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-14 09:44:12 +01:00
|
|
|
/******************************************************************
|
|
|
|
* CreateAssemblyNameObject (SXS.@)
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI CreateAssemblyNameObject(
|
|
|
|
LPASSEMBLYNAME *obj,
|
|
|
|
LPCWSTR assembly,
|
|
|
|
DWORD flags,
|
|
|
|
LPVOID reserved )
|
|
|
|
{
|
|
|
|
struct name *name;
|
2012-03-28 15:33:30 +02:00
|
|
|
HRESULT hr;
|
2012-03-14 09:44:12 +01:00
|
|
|
|
|
|
|
TRACE("%p, %s, 0x%08x, %p\n", obj, debugstr_w(assembly), flags, reserved);
|
|
|
|
|
|
|
|
if (!obj) return E_INVALIDARG;
|
|
|
|
|
|
|
|
*obj = NULL;
|
|
|
|
if (!assembly || !assembly[0] || flags != CANOF_PARSE_DISPLAY_NAME)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
if (!(name = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*name) )))
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
name->IAssemblyName_iface.lpVtbl = &name_vtbl;
|
|
|
|
name->refs = 1;
|
|
|
|
|
2012-03-28 15:33:30 +02:00
|
|
|
hr = parse_displayname( name, assembly );
|
|
|
|
if (hr != S_OK)
|
|
|
|
{
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->name );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->arch );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->token );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->type );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name->version );
|
|
|
|
HeapFree( GetProcessHeap(), 0, name );
|
|
|
|
return hr;
|
|
|
|
}
|
2012-03-14 09:44:12 +01:00
|
|
|
*obj = &name->IAssemblyName_iface;
|
|
|
|
return S_OK;
|
|
|
|
}
|