Huw Davies : oleaut32: Add support for loading typelibs from NE files.
Alexandre Julliard
julliard at winehq.org
Wed Nov 26 07:32:22 CST 2008
Module: wine
Branch: master
Commit: 49368cb14bd5d627f8bd8a6abca59951f5501876
URL: http://source.winehq.org/git/wine.git/?a=commit;h=49368cb14bd5d627f8bd8a6abca59951f5501876
Author: Huw Davies <huw at codeweavers.com>
Date: Tue Nov 25 13:52:24 2008 +0000
oleaut32: Add support for loading typelibs from NE files.
---
dlls/oleaut32/typelib.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 218 insertions(+), 0 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c
index f807c05..bbdebae 100644
--- a/dlls/oleaut32/typelib.c
+++ b/dlls/oleaut32/typelib.c
@@ -64,7 +64,9 @@
#include "winnls.h"
#include "winreg.h"
#include "winuser.h"
+#include "lzexpand.h"
+#include "wine/winbase16.h"
#include "wine/unicode.h"
#include "objbase.h"
#include "typelib.h"
@@ -2326,6 +2328,220 @@ static HRESULT TLB_PEFile_Open(LPCWSTR path, INT index, LPVOID *ppBase, DWORD *p
return TYPE_E_CANTLOADLIBRARY;
}
+typedef struct TLB_NEFile
+{
+ const IUnknownVtbl *lpvtbl;
+ LONG refs;
+ LPVOID typelib_base;
+} TLB_NEFile;
+
+static HRESULT WINAPI TLB_NEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *ppv = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI TLB_NEFile_AddRef(IUnknown *iface)
+{
+ TLB_NEFile *This = (TLB_NEFile *)iface;
+ return InterlockedIncrement(&This->refs);
+}
+
+static ULONG WINAPI TLB_NEFile_Release(IUnknown *iface)
+{
+ TLB_NEFile *This = (TLB_NEFile *)iface;
+ ULONG refs = InterlockedDecrement(&This->refs);
+ if (!refs)
+ {
+ HeapFree(GetProcessHeap(), 0, This->typelib_base);
+ HeapFree(GetProcessHeap(), 0, 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 0;
+
+ resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
+ if ( !resTabSize )
+ {
+ TRACE("No resources in NE dll\n" );
+ return FALSE;
+ }
+
+ /* Read in resource table */
+ resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
+ if ( !resTab ) return FALSE;
+
+ LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
+ if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
+ {
+ HeapFree( GetProcessHeap(), 0, resTab );
+ return FALSE;
+ }
+
+ /* Find resource */
+ typeInfo = (NE_TYPEINFO *)(resTab + 2);
+
+ if (HIWORD(typeid) != 0) /* 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 );
+ HeapFree( GetProcessHeap(), 0, resTab );
+ return FALSE;
+
+ found_type:
+ nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
+
+ if (HIWORD(resid) != 0) /* 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 );
+ HeapFree( GetProcessHeap(), 0, resTab );
+ return FALSE;
+
+ found_name:
+ /* Return resource data */
+ if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
+ if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
+
+ HeapFree( GetProcessHeap(), 0, 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 = NULL;
+
+ This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+ if (!This) return E_OUTOFMEMORY;
+
+ This->lpvtbl = &TLB_NEFile_Vtable;
+ This->refs = 1;
+ This->typelib_base = NULL;
+
+ lzfd = LZOpenFileW( (LPWSTR)path, &ofs, OF_READ );
+ if ( lzfd >= 0 && read_xx_header( lzfd ) == IMAGE_OS2_SIGNATURE )
+ {
+ DWORD reslen, offset;
+ if( find_ne_resource( lzfd, "TYPELIB", MAKEINTRESOURCEA(index), &reslen, &offset ) )
+ {
+ This->typelib_base = HeapAlloc(GetProcessHeap(), 0, 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 = (IUnknown *)&This->lpvtbl;
+ return S_OK;
+ }
+ }
+ }
+
+ if( lzfd >= 0) LZClose( lzfd );
+ TLB_NEFile_Release((IUnknown *)&This->lpvtbl);
+ return hr;
+}
typedef struct TLB_Mapping
{
@@ -2486,6 +2702,8 @@ static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath
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))
{
More information about the wine-cvs
mailing list