fusion: Implement IAssemblyCache::InstallAssembly.
This commit is contained in:
parent
d3afff856e
commit
282246eca4
|
@ -3,11 +3,12 @@ TOPOBJDIR = ../..
|
|||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = fusion.dll
|
||||
IMPORTS = kernel32
|
||||
IMPORTS = advapi32 dbghelp kernel32 shlwapi version
|
||||
|
||||
C_SRCS = \
|
||||
asmcache.c \
|
||||
asmname.c \
|
||||
assembly.c \
|
||||
fusion.c \
|
||||
fusion_main.c
|
||||
|
||||
|
|
|
@ -19,18 +19,78 @@
|
|||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define COBJMACROS
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "winver.h"
|
||||
#include "wincrypt.h"
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
#include "dbghelp.h"
|
||||
#include "ole2.h"
|
||||
#include "fusion.h"
|
||||
#include "corerror.h"
|
||||
|
||||
#include "fusionpriv.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(fusion);
|
||||
|
||||
static BOOL create_full_path(LPCSTR path)
|
||||
{
|
||||
LPSTR new_path;
|
||||
BOOL ret = TRUE;
|
||||
int len;
|
||||
|
||||
new_path = HeapAlloc(GetProcessHeap(), 0, lstrlenA(path) + 1);
|
||||
if (!new_path)
|
||||
return FALSE;
|
||||
|
||||
lstrcpyA(new_path, path);
|
||||
|
||||
while ((len = lstrlenA(new_path)) && new_path[len - 1] == '\\')
|
||||
new_path[len - 1] = 0;
|
||||
|
||||
while (!CreateDirectoryA(new_path, NULL))
|
||||
{
|
||||
LPSTR slash;
|
||||
DWORD last_error = GetLastError();
|
||||
|
||||
if(last_error == ERROR_ALREADY_EXISTS)
|
||||
break;
|
||||
|
||||
if(last_error != ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!(slash = strrchr(new_path, '\\')))
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
len = slash - new_path;
|
||||
new_path[len] = 0;
|
||||
if(!create_full_path(new_path))
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
new_path[len] = '\\';
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, new_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* IAssemblyCache */
|
||||
|
||||
typedef struct {
|
||||
|
@ -130,10 +190,80 @@ static HRESULT WINAPI IAssemblyCacheImpl_InstallAssembly(IAssemblyCache *iface,
|
|||
LPCWSTR pszManifestFilePath,
|
||||
LPCFUSION_INSTALL_REFERENCE pRefData)
|
||||
{
|
||||
FIXME("(%p, %d, %s, %p) stub!\n", iface, dwFlags,
|
||||
ASSEMBLY *assembly;
|
||||
LPSTR filename;
|
||||
LPSTR name = NULL;
|
||||
LPSTR token = NULL;
|
||||
LPSTR version = NULL;
|
||||
LPSTR asmpath = NULL;
|
||||
CHAR path[MAX_PATH];
|
||||
CHAR windir[MAX_PATH];
|
||||
LPWSTR ext;
|
||||
HRESULT hr;
|
||||
|
||||
static const WCHAR ext_exe[] = {'.','e','x','e',0};
|
||||
static const WCHAR ext_dll[] = {'.','d','l','l',0};
|
||||
|
||||
TRACE("(%p, %d, %s, %p)\n", iface, dwFlags,
|
||||
debugstr_w(pszManifestFilePath), pRefData);
|
||||
|
||||
return E_NOTIMPL;
|
||||
if (!pszManifestFilePath || !*pszManifestFilePath)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!(ext = strrchrW(pszManifestFilePath, '.')))
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
||||
|
||||
if (lstrcmpW(ext, ext_exe) && lstrcmpW(ext, ext_dll))
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
||||
|
||||
if (GetFileAttributesW(pszManifestFilePath) == INVALID_FILE_ATTRIBUTES)
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
|
||||
hr = assembly_create(&assembly, pszManifestFilePath);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
hr = COR_E_ASSEMBLYEXPECTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
hr = assembly_get_name(assembly, &name);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
hr = assembly_get_pubkey_token(assembly, &token);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
hr = assembly_get_version(assembly, &version);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
GetWindowsDirectoryA(windir, MAX_PATH);
|
||||
|
||||
FIXME("Ignoring assembly architecture!\n");
|
||||
|
||||
sprintf(path, "%s\\assembly\\GAC_MSIL\\%s\\%s__%s\\", windir, name,
|
||||
version, token);
|
||||
|
||||
create_full_path(path);
|
||||
|
||||
hr = assembly_get_path(assembly, &asmpath);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
filename = PathFindFileNameA(asmpath);
|
||||
|
||||
lstrcatA(path, filename);
|
||||
if (!CopyFileA(asmpath, path, FALSE))
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
done:
|
||||
HeapFree(GetProcessHeap(), 0, name);
|
||||
HeapFree(GetProcessHeap(), 0, token);
|
||||
HeapFree(GetProcessHeap(), 0, version);
|
||||
HeapFree(GetProcessHeap(), 0, asmpath);
|
||||
assembly_release(assembly);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static const IAssemblyCacheVtbl AssemblyCacheVtbl = {
|
||||
|
|
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* assembly parser
|
||||
*
|
||||
* Copyright 2008 James Hawkins
|
||||
*
|
||||
* 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>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "winver.h"
|
||||
#include "wincrypt.h"
|
||||
#include "dbghelp.h"
|
||||
#include "ole2.h"
|
||||
#include "fusion.h"
|
||||
|
||||
#include "fusionpriv.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#define MAX_CLR_TABLES 64
|
||||
|
||||
typedef struct tagCLRTABLE
|
||||
{
|
||||
DWORD rows;
|
||||
DWORD offset;
|
||||
} CLRTABLE;
|
||||
|
||||
struct tagASSEMBLY
|
||||
{
|
||||
LPSTR path;
|
||||
|
||||
HANDLE hfile;
|
||||
HANDLE hmap;
|
||||
BYTE *data;
|
||||
|
||||
IMAGE_NT_HEADERS32 *nthdr;
|
||||
IMAGE_COR20_HEADER *corhdr;
|
||||
|
||||
METADATAHDR *metadatahdr;
|
||||
|
||||
METADATATABLESHDR *tableshdr;
|
||||
DWORD numtables;
|
||||
DWORD *numrows;
|
||||
CLRTABLE tables[MAX_CLR_TABLES];
|
||||
|
||||
BYTE *strings;
|
||||
BYTE *blobs;
|
||||
};
|
||||
|
||||
/* FIXME: fill in */
|
||||
const DWORD COR_TABLE_SIZES[64] =
|
||||
{
|
||||
sizeof(MODULETABLE),
|
||||
sizeof(TYPEREFTABLE),
|
||||
sizeof(TYPEDEFTABLE),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
sizeof(ASSEMBLYTABLE),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
sizeof(MANIFESTRESTABLE),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static LPSTR strdupWtoA(LPCWSTR str)
|
||||
{
|
||||
LPSTR ret = NULL;
|
||||
DWORD len;
|
||||
|
||||
if (!str)
|
||||
return ret;
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
|
||||
ret = HeapAlloc(GetProcessHeap(), 0, len);
|
||||
if (ret)
|
||||
WideCharToMultiByte(CP_ACP, 0, str, -1, ret, len, NULL, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD rva_to_offset(IMAGE_NT_HEADERS *nthdrs, DWORD rva)
|
||||
{
|
||||
DWORD offset = rva, limit;
|
||||
IMAGE_SECTION_HEADER *img;
|
||||
WORD i;
|
||||
|
||||
img = IMAGE_FIRST_SECTION(nthdrs);
|
||||
|
||||
if (rva < img->PointerToRawData)
|
||||
return rva;
|
||||
|
||||
for (i = 0; i < nthdrs->FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
if (img[i].SizeOfRawData)
|
||||
limit = img[i].SizeOfRawData;
|
||||
else
|
||||
limit = img[i].Misc.VirtualSize;
|
||||
|
||||
if (rva >= img[i].VirtualAddress &&
|
||||
rva < (img[i].VirtualAddress + limit))
|
||||
{
|
||||
if (img[i].PointerToRawData != 0)
|
||||
{
|
||||
offset -= img[i].VirtualAddress;
|
||||
offset += img[i].PointerToRawData;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BYTE *GetData(BYTE *pData, ULONG *pLength)
|
||||
{
|
||||
if ((*pData & 0x80) == 0x00)
|
||||
{
|
||||
*pLength = (*pData & 0x7f);
|
||||
return pData + 1;
|
||||
}
|
||||
|
||||
if ((*pData & 0xC0) == 0x80)
|
||||
{
|
||||
*pLength = ((*pData & 0x3f) << 8 | *(pData + 1));
|
||||
return pData + 2;
|
||||
}
|
||||
|
||||
if ((*pData & 0xE0) == 0xC0)
|
||||
{
|
||||
*pLength = ((*pData & 0x1f) << 24 | *(pData + 1) << 16 |
|
||||
*(pData + 2) << 8 | *(pData + 3));
|
||||
return pData + 4;
|
||||
}
|
||||
|
||||
*pLength = (ULONG)-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID *assembly_data_offset(ASSEMBLY *assembly, ULONG offset)
|
||||
{
|
||||
return (VOID *)&assembly->data[offset];
|
||||
}
|
||||
|
||||
static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset)
|
||||
{
|
||||
DWORD i, previ, offidx;
|
||||
ULONG currofs;
|
||||
|
||||
currofs = offset;
|
||||
assembly->tableshdr = (METADATATABLESHDR *)assembly_data_offset(assembly, currofs);
|
||||
if (!assembly->tableshdr)
|
||||
return E_FAIL;
|
||||
|
||||
currofs += sizeof(METADATATABLESHDR);
|
||||
assembly->numrows = (DWORD *)assembly_data_offset(assembly, currofs);
|
||||
if (!assembly->numrows)
|
||||
return E_FAIL;
|
||||
|
||||
assembly->numtables = 0;
|
||||
for (i = 0; i < MAX_CLR_TABLES; i++)
|
||||
{
|
||||
if ((i < 32 && (assembly->tableshdr->MaskValid.LowPart >> i) & 1) ||
|
||||
(i >= 32 && (assembly->tableshdr->MaskValid.HighPart >> i) & 1))
|
||||
{
|
||||
assembly->numtables++;
|
||||
}
|
||||
}
|
||||
|
||||
currofs += assembly->numtables * sizeof(DWORD);
|
||||
memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE));
|
||||
|
||||
if (assembly->tableshdr->MaskValid.LowPart & 1)
|
||||
{
|
||||
assembly->tables[0].offset = currofs;
|
||||
assembly->tables[0].rows = assembly->numrows[0];
|
||||
}
|
||||
|
||||
previ = 0;
|
||||
offidx = 1;
|
||||
for (i = 1; i < MAX_CLR_TABLES; i++)
|
||||
{
|
||||
if ((i < 32 && (assembly->tableshdr->MaskValid.LowPart >> i) & 1) ||
|
||||
(i >= 32 && (assembly->tableshdr->MaskValid.HighPart >> i) & 1))
|
||||
{
|
||||
currofs += COR_TABLE_SIZES[previ] * assembly->numrows[offidx - 1];
|
||||
assembly->tables[i].offset = currofs;
|
||||
assembly->tables[i].rows = assembly->numrows[offidx];
|
||||
offidx++;
|
||||
previ = i;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
|
||||
{
|
||||
METADATASTREAMHDR *streamhdr;
|
||||
ULONG rva, i, ofs;
|
||||
LPSTR stream;
|
||||
HRESULT hr;
|
||||
BYTE *ptr;
|
||||
|
||||
rva = assembly->corhdr->MetaData.VirtualAddress;
|
||||
assembly->metadatahdr = ImageRvaToVa(assembly->nthdr, assembly->data,
|
||||
rva, NULL);
|
||||
if (!assembly->metadatahdr)
|
||||
return E_FAIL;
|
||||
|
||||
ptr = ImageRvaToVa(assembly->nthdr, assembly->data,
|
||||
rva + sizeof(METADATAHDR), NULL);
|
||||
if (!ptr)
|
||||
return E_FAIL;
|
||||
|
||||
for (i = 0; i < assembly->metadatahdr->Streams; i++)
|
||||
{
|
||||
streamhdr = (METADATASTREAMHDR *)ptr;
|
||||
ofs = rva_to_offset(assembly->nthdr, rva + streamhdr->Offset);
|
||||
|
||||
ptr += sizeof(METADATASTREAMHDR);
|
||||
stream = (LPSTR)ptr;
|
||||
|
||||
if (!lstrcmpA(stream, "#~"))
|
||||
{
|
||||
hr = parse_clr_tables(assembly, ofs);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
else if (!lstrcmpA(stream, "#Strings"))
|
||||
assembly->strings = (BYTE *)assembly_data_offset(assembly, ofs);
|
||||
else if (!lstrcmpA(stream, "#Blob"))
|
||||
assembly->blobs = (BYTE *)assembly_data_offset(assembly, ofs);
|
||||
|
||||
ptr += lstrlenA(stream);
|
||||
while (!*ptr) ptr++;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT parse_pe_header(ASSEMBLY *assembly)
|
||||
{
|
||||
IMAGE_DATA_DIRECTORY *datadirs;
|
||||
|
||||
assembly->nthdr = ImageNtHeader(assembly->data);
|
||||
if (!assembly->nthdr)
|
||||
return E_FAIL;
|
||||
|
||||
datadirs = assembly->nthdr->OptionalHeader.DataDirectory;
|
||||
if (!datadirs)
|
||||
return E_FAIL;
|
||||
|
||||
if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
|
||||
!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
|
||||
datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
|
||||
if (!assembly->corhdr)
|
||||
return E_FAIL;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
|
||||
{
|
||||
ASSEMBLY *assembly;
|
||||
HRESULT hr;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
assembly = HeapAlloc(GetProcessHeap(), 0, sizeof(ASSEMBLY));
|
||||
if (!assembly)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
ZeroMemory(assembly, sizeof(ASSEMBLY));
|
||||
|
||||
assembly->path = strdupWtoA(file);
|
||||
if (!assembly->path)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (!assembly->hfile)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
|
||||
0, 0, NULL);
|
||||
if (!assembly->hmap)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!assembly->data)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
hr = parse_pe_header(assembly);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = parse_clr_metadata(assembly);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
*out = assembly;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT assembly_release(ASSEMBLY *assembly)
|
||||
{
|
||||
if (!assembly)
|
||||
return S_OK;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, assembly->path);
|
||||
UnmapViewOfFile(assembly->data);
|
||||
CloseHandle(assembly->hmap);
|
||||
CloseHandle(assembly->hfile);
|
||||
HeapFree(GetProcessHeap(), 0, assembly);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static LPSTR assembly_dup_str(ASSEMBLY *assembly, WORD index)
|
||||
{
|
||||
return strdup((LPSTR)&assembly->strings[index]);
|
||||
}
|
||||
|
||||
HRESULT assembly_get_name(ASSEMBLY *assembly, LPSTR *name)
|
||||
{
|
||||
ASSEMBLYTABLE *asmtbl;
|
||||
ULONG offset;
|
||||
|
||||
offset = assembly->tables[0x20].offset; /* FIXME: add constants */
|
||||
if (offset < 0)
|
||||
return E_FAIL;
|
||||
|
||||
asmtbl = (ASSEMBLYTABLE *)assembly_data_offset(assembly, offset);
|
||||
if (!asmtbl)
|
||||
return E_FAIL;
|
||||
|
||||
*name = assembly_dup_str(assembly, asmtbl->Name);
|
||||
if (!*name)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT assembly_get_path(ASSEMBLY *assembly, LPSTR *path)
|
||||
{
|
||||
*path = strdup(assembly->path);
|
||||
if (!*path)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT assembly_get_version(ASSEMBLY *assembly, LPSTR *version)
|
||||
{
|
||||
LPSTR verdata;
|
||||
VS_FIXEDFILEINFO *ffi;
|
||||
HRESULT hr = S_OK;
|
||||
DWORD size;
|
||||
|
||||
size = GetFileVersionInfoSizeA(assembly->path, NULL);
|
||||
if (!size)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
verdata = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
if (!verdata)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (!GetFileVersionInfoA(assembly->path, 0, size, verdata))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!VerQueryValueA(verdata, "\\", (LPVOID *)&ffi, &size))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto done;
|
||||
}
|
||||
|
||||
*version = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
|
||||
if (!*version)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sprintf(*version, "%d.%d.%d.%d", HIWORD(ffi->dwFileVersionMS),
|
||||
LOWORD(ffi->dwFileVersionMS), HIWORD(ffi->dwFileVersionLS),
|
||||
LOWORD(ffi->dwFileVersionLS));
|
||||
|
||||
done:
|
||||
HeapFree(GetProcessHeap(), 0, verdata);
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT assembly_get_architecture(ASSEMBLY *assembly, DWORD fixme)
|
||||
{
|
||||
/* FIXME */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static BYTE *assembly_get_blob(ASSEMBLY *assembly, WORD index, ULONG *size)
|
||||
{
|
||||
return GetData(&assembly->blobs[index], size);
|
||||
}
|
||||
|
||||
static void bytes_to_str(BYTE *bytes, DWORD len, LPSTR str)
|
||||
{
|
||||
int i;
|
||||
|
||||
static const char hexval[16] = {
|
||||
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
|
||||
};
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
str[i * 2] = hexval[((bytes[i] >> 4) & 0xF)];
|
||||
str[i * 2 + 1] = hexval[(bytes[i]) & 0x0F];
|
||||
}
|
||||
}
|
||||
|
||||
#define BYTES_PER_TOKEN 8
|
||||
#define CHARS_PER_BYTE 2
|
||||
#define TOKEN_LENGTH (BYTES_PER_TOKEN * CHARS_PER_BYTE + 1)
|
||||
|
||||
HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPSTR *token)
|
||||
{
|
||||
ASSEMBLYTABLE *asmtbl;
|
||||
ULONG i, offset, size;
|
||||
BYTE *hashdata;
|
||||
HCRYPTPROV crypt;
|
||||
HCRYPTHASH hash;
|
||||
BYTE *pubkey;
|
||||
BYTE tokbytes[BYTES_PER_TOKEN];
|
||||
HRESULT hr = E_FAIL;
|
||||
LPSTR tok;
|
||||
|
||||
*token = NULL;
|
||||
|
||||
offset = assembly->tables[0x20].offset; /* FIXME: add constants */
|
||||
if (offset < 0)
|
||||
return E_FAIL;
|
||||
|
||||
asmtbl = (ASSEMBLYTABLE *)assembly_data_offset(assembly, offset);
|
||||
if (!asmtbl)
|
||||
return E_FAIL;
|
||||
|
||||
pubkey = assembly_get_blob(assembly, asmtbl->PublicKey, &size);
|
||||
|
||||
if (!CryptAcquireContextA(&crypt, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT))
|
||||
return E_FAIL;
|
||||
|
||||
if (!CryptCreateHash(crypt, CALG_SHA1, 0, 0, &hash))
|
||||
return E_FAIL;
|
||||
|
||||
if (!CryptHashData(hash, pubkey, size, 0))
|
||||
return E_FAIL;
|
||||
|
||||
size = 0;
|
||||
if (!CryptGetHashParam(hash, HP_HASHVAL, NULL, &size, 0))
|
||||
return E_FAIL;
|
||||
|
||||
hashdata = HeapAlloc(GetProcessHeap(), 0, size);
|
||||
if (!hashdata)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!CryptGetHashParam(hash, HP_HASHVAL, hashdata, &size, 0))
|
||||
goto done;
|
||||
|
||||
for (i = size - 1; i >= size - 8; i--)
|
||||
tokbytes[size - i - 1] = hashdata[i];
|
||||
|
||||
tok = HeapAlloc(GetProcessHeap(), 0, TOKEN_LENGTH);
|
||||
if (!tok)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
bytes_to_str(tokbytes, BYTES_PER_TOKEN, tok);
|
||||
tok[TOKEN_LENGTH - 1] = '\0';
|
||||
|
||||
*token = tok;
|
||||
hr = S_OK;
|
||||
|
||||
done:
|
||||
HeapFree(GetProcessHeap(), 0, hashdata);
|
||||
CryptDestroyHash(hash);
|
||||
CryptReleaseContext(crypt, 0);
|
||||
|
||||
return hr;
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* fusion private definitions
|
||||
*
|
||||
* Copyright 2008 James Hawkins
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __WINE_FUSION_PRIVATE__
|
||||
#define __WINE_FUSION_PRIVATE__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Signature;
|
||||
USHORT MajorVersion;
|
||||
USHORT MinorVersion;
|
||||
ULONG Reserved;
|
||||
ULONG VersionLength;
|
||||
BYTE Version[12];
|
||||
BYTE Flags;
|
||||
WORD Streams;
|
||||
} METADATAHDR;
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD Offset;
|
||||
DWORD Size;
|
||||
} METADATASTREAMHDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD Reserved1;
|
||||
BYTE MajorVersion;
|
||||
BYTE MinorVersion;
|
||||
BYTE HeapOffsetSizes;
|
||||
BYTE Reserved2;
|
||||
LARGE_INTEGER MaskValid;
|
||||
LARGE_INTEGER MaskSorted;
|
||||
} METADATATABLESHDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD Generation;
|
||||
WORD Name;
|
||||
WORD Mvid;
|
||||
WORD EncId;
|
||||
WORD EncBaseId;
|
||||
} MODULETABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD Flags;
|
||||
WORD Name;
|
||||
WORD Namespace;
|
||||
WORD Extends;
|
||||
WORD FieldList;
|
||||
WORD MethodList;
|
||||
} TYPEDEFTABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD ResolutionScope;
|
||||
WORD Name;
|
||||
WORD Namespace;
|
||||
} TYPEREFTABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD HashAlgId;
|
||||
WORD MajorVersion;
|
||||
WORD MinorVersion;
|
||||
WORD BuildNumber;
|
||||
WORD RevisionNumber;
|
||||
DWORD Flags;
|
||||
WORD PublicKey;
|
||||
WORD Name;
|
||||
WORD Culture;
|
||||
} ASSEMBLYTABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD Offset;
|
||||
DWORD Flags;
|
||||
WORD Name;
|
||||
WORD Implementation;
|
||||
} MANIFESTRESTABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD ImportLookupTable;
|
||||
DWORD DateTimeStamp;
|
||||
DWORD ForwarderChain;
|
||||
DWORD Name;
|
||||
DWORD ImportAddressTable;
|
||||
BYTE pad[20];
|
||||
} IMPORTTABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD HintNameTableRVA;
|
||||
BYTE pad[8];
|
||||
} IMPORTLOOKUPTABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD Hint;
|
||||
BYTE Name[12];
|
||||
BYTE Module[12];
|
||||
DWORD Reserved;
|
||||
WORD EntryPoint;
|
||||
DWORD RVA;
|
||||
} HINTNAMETABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD PageRVA;
|
||||
DWORD Size;
|
||||
DWORD Relocation;
|
||||
} RELOCATION;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
WCHAR szKey[17];
|
||||
VS_FIXEDFILEINFO Value;
|
||||
} VS_VERSIONINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
WCHAR szKey[13];
|
||||
} VARFILEINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
WCHAR szKey[13];
|
||||
DWORD Value;
|
||||
} VAR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
WCHAR szKey[15];
|
||||
} STRINGFILEINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
WCHAR szKey[9];
|
||||
} STRINGTABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
} STRINGHDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD Size;
|
||||
DWORD Signature;
|
||||
DWORD HeaderVersion;
|
||||
DWORD SkipData;
|
||||
BYTE Data[168];
|
||||
} RESOURCE;
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
struct tagASSEMBLY;
|
||||
typedef struct tagASSEMBLY ASSEMBLY;
|
||||
|
||||
HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file);
|
||||
HRESULT assembly_release(ASSEMBLY *assembly);
|
||||
HRESULT assembly_get_name(ASSEMBLY *assembly, LPSTR *name);
|
||||
HRESULT assembly_get_path(ASSEMBLY *assembly, LPSTR *path);
|
||||
HRESULT assembly_get_version(ASSEMBLY *assembly, LPSTR *version);
|
||||
HRESULT assembly_get_architecture(ASSEMBLY *assembly, DWORD fixme);
|
||||
HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPSTR *token);
|
||||
|
||||
#endif /* __WINE_FUSION_PRIVATE__ */
|
|
@ -853,6 +853,7 @@ static void test_InstallAssembly(void)
|
|||
IAssemblyCache *cache;
|
||||
HRESULT hr;
|
||||
ULONG disp;
|
||||
DWORD attr;
|
||||
|
||||
static const WCHAR empty[] = {0};
|
||||
static const WCHAR noext[] = {'f','i','l','e',0};
|
||||
|
@ -877,64 +878,44 @@ static void test_InstallAssembly(void)
|
|||
|
||||
/* NULL pszManifestFilePath */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, NULL, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
|
||||
}
|
||||
|
||||
/* empty pszManifestFilePath */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, empty, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
|
||||
}
|
||||
|
||||
/* pszManifestFilePath has no extension */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, noext, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_NAME),
|
||||
"Expected HRESULT_FROM_WIN32(ERROR_INVALID_NAME), got %08x\n", hr);
|
||||
}
|
||||
|
||||
/* pszManifestFilePath has bad extension */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, badext, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_NAME),
|
||||
"Expected HRESULT_FROM_WIN32(ERROR_INVALID_NAME), got %08x\n", hr);
|
||||
}
|
||||
|
||||
/* pszManifestFilePath has dll extension */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, dllext, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
|
||||
"Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr);
|
||||
}
|
||||
|
||||
/* pszManifestFilePath has exe extension */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, exeext, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
|
||||
"Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr);
|
||||
}
|
||||
|
||||
/* empty file */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, testdll, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == COR_E_ASSEMBLYEXPECTED,
|
||||
"Expected COR_E_ASSEMBLYEXPECTED, got %08x\n", hr);
|
||||
}
|
||||
|
||||
/* wine assembly */
|
||||
hr = IAssemblyCache_InstallAssembly(cache, 0, winedll, NULL);
|
||||
todo_wine
|
||||
{
|
||||
ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
|
||||
}
|
||||
|
||||
attr = GetFileAttributes("C:\\windows\\assembly\\GAC_MSIL\\wine\\"
|
||||
"1.0.0.0__2d03617b1c31e2f5/wine.dll");
|
||||
ok(attr != INVALID_FILE_ATTRIBUTES, "Expected assembly to exist\n");
|
||||
|
||||
/* uninstall the assembly from the GAC */
|
||||
hr = IAssemblyCache_UninstallAssembly(cache, 0, wine, NULL, &disp);
|
||||
|
@ -945,6 +926,12 @@ static void test_InstallAssembly(void)
|
|||
"Expected IASSEMBLYCACHE_UNINSTALL_DISPOSITION_UNINSTALLED, got %d\n", disp);
|
||||
}
|
||||
|
||||
/* FIXME: remove once UninstallAssembly is implemented */
|
||||
DeleteFileA("C:\\windows\\assembly\\GAC_MSIL\\wine\\"
|
||||
"1.0.0.0__2d03617b1c31e2f5\\wine.dll");
|
||||
RemoveDirectoryA("C:\\windows\\assembly\\GAC_MSIL\\wine\\1.0.0.0__2d03617b1c31e2f5");
|
||||
RemoveDirectoryA("C:\\windows\\assembly\\GAC_MSIL\\wine");
|
||||
|
||||
DeleteFileA("test.dll");
|
||||
DeleteFileA("wine.dll");
|
||||
IAssemblyCache_Release(cache);
|
||||
|
|
Loading…
Reference in New Issue