diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index f251d70da23..70f8a0d9164 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -2217,6 +2217,188 @@ static CRITICAL_SECTION_DEBUG cache_section_debug = static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 }; +typedef struct TLB_PEFile +{ + const IUnknownVtbl *lpvtbl; + LONG refs; + HMODULE dll; + HRSRC typelib_resource; + HGLOBAL typelib_global; + LPVOID typelib_base; +} TLB_PEFile; + +static HRESULT WINAPI TLB_PEFile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI TLB_PEFile_AddRef(IUnknown *iface) +{ + TLB_PEFile *This = (TLB_PEFile *)iface; + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI TLB_PEFile_Release(IUnknown *iface) +{ + TLB_PEFile *This = (TLB_PEFile *)iface; + ULONG refs = InterlockedDecrement(&This->refs); + if (!refs) + { + if (This->typelib_global) + FreeResource(This->typelib_global); + if (This->dll) + FreeLibrary(This->dll); + HeapFree(GetProcessHeap(), 0, 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; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->lpvtbl = &TLB_PEFile_Vtable; + This->refs = 1; + This->dll = NULL; + This->typelib_resource = NULL; + This->typelib_global = NULL; + This->typelib_base = NULL; + + This->dll = LoadLibraryExW(path, 0, DONT_RESOLVE_DLL_REFERENCES | + LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH); + + if (This->dll) + { + static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0}; + This->typelib_resource = FindResourceW(This->dll, MAKEINTRESOURCEW(index), TYPELIBW); + if (This->typelib_resource) + { + This->typelib_global = LoadResource(This->dll, This->typelib_resource); + if (This->typelib_global) + { + This->typelib_base = LockResource(This->typelib_global); + + if (This->typelib_base) + { + *pdwTLBLength = SizeofResource(This->dll, This->typelib_resource); + *ppBase = This->typelib_base; + *ppFile = (IUnknown *)&This->lpvtbl; + return S_OK; + } + } + } + } + + TLB_PEFile_Release((IUnknown *)&This->lpvtbl); + return TYPE_E_CANTLOADLIBRARY; +} + + +typedef struct TLB_Mapping +{ + const IUnknownVtbl *lpvtbl; + LONG refs; + HANDLE file; + HANDLE mapping; + LPVOID typelib_base; +} TLB_Mapping; + +static HRESULT WINAPI TLB_Mapping_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI TLB_Mapping_AddRef(IUnknown *iface) +{ + TLB_Mapping *This = (TLB_Mapping *)iface; + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI TLB_Mapping_Release(IUnknown *iface) +{ + TLB_Mapping *This = (TLB_Mapping *)iface; + ULONG refs = InterlockedDecrement(&This->refs); + if (!refs) + { + if (This->typelib_base) + UnmapViewOfFile(This->typelib_base); + if (This->mapping) + CloseHandle(This->mapping); + if (This->file != INVALID_HANDLE_VALUE) + CloseHandle(This->file); + HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->lpvtbl = &TLB_Mapping_Vtable; + This->refs = 1; + This->file = INVALID_HANDLE_VALUE; + This->mapping = NULL; + This->typelib_base = NULL; + + This->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE != This->file) + { + This->mapping = CreateFileMappingW(This->file, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); + if (This->mapping) + { + This->typelib_base = MapViewOfFile(This->mapping, FILE_MAP_READ, 0, 0, 0); + if(This->typelib_base) + { + /* retrieve file size */ + *pdwTLBLength = GetFileSize(This->file, NULL); + *ppBase = This->typelib_base; + *ppFile = (IUnknown *)&This->lpvtbl; + return S_OK; + } + } + } + + IUnknown_Release((IUnknown *)&This->lpvtbl); + return TYPE_E_CANTLOADLIBRARY; +} + /**************************************************************************** * TLB_ReadTypeLib * @@ -2228,10 +2410,12 @@ static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 } static int TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, ITypeLib2 **ppTypeLib) { ITypeLibImpl *entry; - int ret = TYPE_E_CANTLOADLIBRARY; + HRESULT ret; INT index = 1; - HINSTANCE hinstDLL; LPWSTR index_str, file = (LPWSTR)pszFileName; + LPVOID pBase = NULL; + DWORD dwTLBLength = 0; + IUnknown *pFile = NULL; *ppTypeLib = NULL; @@ -2285,63 +2469,27 @@ static int TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath, IT /* now actually load and parse the typelib */ - hinstDLL = LoadLibraryExW(pszPath, 0, DONT_RESOLVE_DLL_REFERENCES | - LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH); - - if (hinstDLL) + ret = TLB_PEFile_Open(pszPath, index, &pBase, &dwTLBLength, &pFile); + if (ret == TYPE_E_CANTLOADLIBRARY) + ret = TLB_Mapping_Open(pszPath, &pBase, &dwTLBLength, &pFile); + if (SUCCEEDED(ret)) { - static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0}; - HRSRC hrsrc = FindResourceW(hinstDLL, MAKEINTRESOURCEW(index), TYPELIBW); - if (hrsrc) + if (dwTLBLength >= 4) { - HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc); - if (hGlobal) + 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 { - LPVOID pBase = LockResource(hGlobal); - DWORD dwTLBLength = SizeofResource(hinstDLL, hrsrc); - - if (pBase) - { - /* try to load as incore resource */ - 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); - } - FreeResource( hGlobal ); + FIXME("Header type magic 0x%08x not supported.\n",dwSignature); + ret = TYPE_E_CANTLOADLIBRARY; } } - FreeLibrary(hinstDLL); - } - else - { - HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - if (INVALID_HANDLE_VALUE != hFile) - { - HANDLE hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL ); - if (hMapping) - { - LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); - if(pBase) - { - /* retrieve file size */ - DWORD dwTLBLength = GetFileSize(hFile, NULL); - 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); - - UnmapViewOfFile(pBase); - } - CloseHandle(hMapping); - } - CloseHandle(hFile); - } + else + ret = TYPE_E_CANTLOADLIBRARY; + IUnknown_Release(pFile); } if(*ppTypeLib) {