| /* |
| * SHLWAPI Registry Stream functions |
| * |
| * Copyright 1999 Juergen Schmied |
| * Copyright 2002 Jon Griffiths |
| * |
| * 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 <string.h> |
| |
| #define COBJMACROS |
| |
| #include "winerror.h" |
| #include "windef.h" |
| #include "winbase.h" |
| #include "objbase.h" |
| #include "winreg.h" |
| #include "shlwapi.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); |
| |
| typedef struct |
| { |
| const IStreamVtbl *lpVtbl; |
| LONG ref; |
| HKEY hKey; |
| LPBYTE pbBuffer; |
| DWORD dwLength; |
| DWORD dwPos; |
| } ISHRegStream; |
| |
| /************************************************************************** |
| * IStream_fnQueryInterface |
| */ |
| static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); |
| |
| *ppvObj = NULL; |
| |
| if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/ |
| *ppvObj = This; |
| else if(IsEqualIID(riid, &IID_IStream)) /*IStream*/ |
| *ppvObj = This; |
| |
| if(*ppvObj) |
| { |
| IStream_AddRef((IStream*)*ppvObj); |
| TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); |
| return S_OK; |
| } |
| TRACE("-- Interface: E_NOINTERFACE\n"); |
| return E_NOINTERFACE; |
| } |
| |
| /************************************************************************** |
| * IStream_fnAddRef |
| */ |
| static ULONG WINAPI IStream_fnAddRef(IStream *iface) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| ULONG refCount = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p)->(ref before=%u)\n",This, refCount - 1); |
| |
| return refCount; |
| } |
| |
| /************************************************************************** |
| * IStream_fnRelease |
| */ |
| static ULONG WINAPI IStream_fnRelease(IStream *iface) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| ULONG refCount = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p)->(ref before=%u)\n",This, refCount + 1); |
| |
| if (!refCount) |
| { |
| TRACE(" destroying SHReg IStream (%p)\n",This); |
| |
| HeapFree(GetProcessHeap(),0,This->pbBuffer); |
| |
| if (This->hKey) |
| RegCloseKey(This->hKey); |
| |
| HeapFree(GetProcessHeap(),0,This); |
| return 0; |
| } |
| |
| return refCount; |
| } |
| |
| /************************************************************************** |
| * IStream_fnRead |
| */ |
| static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| DWORD dwBytesToRead, dwBytesLeft; |
| |
| TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead); |
| |
| if (!pv) |
| return STG_E_INVALIDPOINTER; |
| |
| dwBytesLeft = This->dwLength - This->dwPos; |
| |
| if ( 0 >= dwBytesLeft ) /* end of buffer */ |
| return S_FALSE; |
| |
| dwBytesToRead = ( cb > dwBytesLeft) ? dwBytesLeft : cb; |
| |
| memmove ( pv, (This->pbBuffer) + (This->dwPos), dwBytesToRead); |
| |
| This->dwPos += dwBytesToRead; /* adjust pointer */ |
| |
| if (pcbRead) |
| *pcbRead = dwBytesToRead; |
| |
| return S_OK; |
| } |
| |
| /************************************************************************** |
| * IStream_fnWrite |
| */ |
| static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| |
| if (pcbWritten) |
| *pcbWritten = 0; |
| |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************** |
| * IStream_fnSeek |
| */ |
| static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| |
| if (plibNewPosition) |
| plibNewPosition->QuadPart = 0; |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************** |
| * IStream_fnSetSize |
| */ |
| static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************** |
| * IStream_fnCopyTo |
| */ |
| static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| if (pcbRead) |
| pcbRead->QuadPart = 0; |
| if (pcbWritten) |
| pcbWritten->QuadPart = 0; |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************** |
| * IStream_fnCommit |
| */ |
| static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************** |
| * IStream_fnRevert |
| */ |
| static HRESULT WINAPI IStream_fnRevert (IStream * iface) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************** |
| * IStream_fnLockUnlockRegion |
| */ |
| static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************* |
| * IStream_fnStat |
| */ |
| static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| |
| return E_NOTIMPL; |
| } |
| |
| /************************************************************************* |
| * IStream_fnClone |
| */ |
| static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| |
| TRACE("(%p)\n",This); |
| if (ppstm) |
| *ppstm = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static const IStreamVtbl rstvt = |
| { |
| IStream_fnQueryInterface, |
| IStream_fnAddRef, |
| IStream_fnRelease, |
| IStream_fnRead, |
| IStream_fnWrite, |
| IStream_fnSeek, |
| IStream_fnSetSize, |
| IStream_fnCopyTo, |
| IStream_fnCommit, |
| IStream_fnRevert, |
| IStream_fnLockUnlockRegion, |
| IStream_fnLockUnlockRegion, |
| IStream_fnStat, |
| IStream_fnClone |
| }; |
| |
| /* Methods overridden by the dummy stream */ |
| |
| /************************************************************************** |
| * IStream_fnAddRefDummy |
| */ |
| static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| TRACE("(%p)\n", This); |
| return 2; |
| } |
| |
| /************************************************************************** |
| * IStream_fnReleaseDummy |
| */ |
| static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface) |
| { |
| ISHRegStream *This = (ISHRegStream *)iface; |
| TRACE("(%p)\n", This); |
| return 1; |
| } |
| |
| /************************************************************************** |
| * IStream_fnReadDummy |
| */ |
| static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead) |
| { |
| if (pcbRead) |
| *pcbRead = 0; |
| return E_NOTIMPL; |
| } |
| |
| static const IStreamVtbl DummyRegStreamVTable = |
| { |
| IStream_fnQueryInterface, |
| IStream_fnAddRefDummy, /* Overridden */ |
| IStream_fnReleaseDummy, /* Overridden */ |
| IStream_fnReadDummy, /* Overridden */ |
| IStream_fnWrite, |
| IStream_fnSeek, |
| IStream_fnSetSize, |
| IStream_fnCopyTo, |
| IStream_fnCommit, |
| IStream_fnRevert, |
| IStream_fnLockUnlockRegion, |
| IStream_fnLockUnlockRegion, |
| IStream_fnStat, |
| IStream_fnClone |
| }; |
| |
| /* Dummy registry stream object */ |
| static ISHRegStream rsDummyRegStream = |
| { |
| &DummyRegStreamVTable, |
| 1, |
| NULL, |
| NULL, |
| 0, |
| 0 |
| }; |
| |
| /************************************************************************** |
| * IStream_Create |
| * |
| * Internal helper: Create and initialise a new registry stream object. |
| */ |
| static IStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength) |
| { |
| ISHRegStream* regStream; |
| |
| regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream)); |
| |
| if (regStream) |
| { |
| regStream->lpVtbl = &rstvt; |
| regStream->ref = 1; |
| regStream->hKey = hKey; |
| regStream->pbBuffer = pbBuffer; |
| regStream->dwLength = dwLength; |
| regStream->dwPos = 0; |
| } |
| TRACE ("Returning %p\n", regStream); |
| return (IStream *)regStream; |
| } |
| |
| /************************************************************************* |
| * SHOpenRegStream2A [SHLWAPI.@] |
| * |
| * Create a stream to read binary registry data. |
| * |
| * PARAMS |
| * hKey [I] Registry handle |
| * pszSubkey [I] The sub key name |
| * pszValue [I] The value name under the sub key |
| * dwMode [I] Unused |
| * |
| * RETURNS |
| * Success: An IStream interface referring to the registry data |
| * Failure: NULL, if the registry key could not be opened or is not binary. |
| */ |
| IStream * WINAPI SHOpenRegStream2A(HKEY hKey, LPCSTR pszSubkey, |
| LPCSTR pszValue,DWORD dwMode) |
| { |
| HKEY hStrKey = NULL; |
| LPBYTE lpBuff = NULL; |
| DWORD dwLength, dwType; |
| |
| TRACE("(%p,%s,%s,0x%08x)\n", hKey, pszSubkey, pszValue, dwMode); |
| |
| /* Open the key, read in binary data and create stream */ |
| if (!RegOpenKeyExA (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && |
| !RegQueryValueExA (hStrKey, pszValue, 0, 0, 0, &dwLength) && |
| (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && |
| !RegQueryValueExA (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && |
| dwType == REG_BINARY) |
| return IStream_Create(hStrKey, lpBuff, dwLength); |
| |
| HeapFree (GetProcessHeap(), 0, lpBuff); |
| if (hStrKey) |
| RegCloseKey(hStrKey); |
| return NULL; |
| } |
| |
| /************************************************************************* |
| * SHOpenRegStream2W [SHLWAPI.@] |
| * |
| * See SHOpenRegStream2A. |
| */ |
| IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey, |
| LPCWSTR pszValue, DWORD dwMode) |
| { |
| HKEY hStrKey = NULL; |
| LPBYTE lpBuff = NULL; |
| DWORD dwLength, dwType; |
| |
| TRACE("(%p,%s,%s,0x%08x)\n", hKey, debugstr_w(pszSubkey), |
| debugstr_w(pszValue), dwMode); |
| |
| /* Open the key, read in binary data and create stream */ |
| if (!RegOpenKeyExW (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && |
| !RegQueryValueExW (hStrKey, pszValue, 0, 0, 0, &dwLength) && |
| (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && |
| !RegQueryValueExW (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && |
| dwType == REG_BINARY) |
| return IStream_Create(hStrKey, lpBuff, dwLength); |
| |
| HeapFree (GetProcessHeap(), 0, lpBuff); |
| if (hStrKey) |
| RegCloseKey(hStrKey); |
| return NULL; |
| } |
| |
| /************************************************************************* |
| * SHOpenRegStreamA [SHLWAPI.@] |
| * |
| * Create a stream to read binary registry data. |
| * |
| * PARAMS |
| * hKey [I] Registry handle |
| * pszSubkey [I] The sub key name |
| * pszValue [I] The value name under the sub key |
| * dwMode [I] STGM mode for opening the file |
| * |
| * RETURNS |
| * Success: An IStream interface referring to the registry data |
| * Failure: If the registry key could not be opened or is not binary, |
| * A dummy (empty) IStream object is returned. |
| */ |
| IStream * WINAPI SHOpenRegStreamA(HKEY hkey, LPCSTR pszSubkey, |
| LPCSTR pszValue, DWORD dwMode) |
| { |
| IStream *iStream; |
| |
| TRACE("(%p,%s,%s,0x%08x)\n", hkey, pszSubkey, pszValue, dwMode); |
| |
| iStream = SHOpenRegStream2A(hkey, pszSubkey, pszValue, dwMode); |
| return iStream ? iStream : (IStream *)&rsDummyRegStream; |
| } |
| |
| /************************************************************************* |
| * SHOpenRegStreamW [SHLWAPI.@] |
| * |
| * See SHOpenRegStreamA. |
| */ |
| IStream * WINAPI SHOpenRegStreamW(HKEY hkey, LPCWSTR pszSubkey, |
| LPCWSTR pszValue, DWORD dwMode) |
| { |
| IStream *iStream; |
| |
| TRACE("(%p,%s,%s,0x%08x)\n", hkey, debugstr_w(pszSubkey), |
| debugstr_w(pszValue), dwMode); |
| iStream = SHOpenRegStream2W(hkey, pszSubkey, pszValue, dwMode); |
| return iStream ? iStream : (IStream *)&rsDummyRegStream; |
| } |
| |
| /************************************************************************* |
| * @ [SHLWAPI.12] |
| * |
| * Create an IStream object on a block of memory. |
| * |
| * PARAMS |
| * lpbData [I] Memory block to create the IStream object on |
| * dwDataLen [I] Length of data block |
| * |
| * RETURNS |
| * Success: A pointer to the IStream object. |
| * Failure: NULL, if any parameters are invalid or an error occurs. |
| * |
| * NOTES |
| * A copy of the memory pointed to by lpbData is made, and is freed |
| * when the stream is released. |
| */ |
| IStream * WINAPI SHCreateMemStream(LPBYTE lpbData, DWORD dwDataLen) |
| { |
| IStream *iStrmRet = NULL; |
| |
| TRACE("(%p,%d)\n", lpbData, dwDataLen); |
| |
| if (lpbData) |
| { |
| LPBYTE lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen); |
| |
| if (lpbDup) |
| { |
| memcpy(lpbDup, lpbData, dwDataLen); |
| iStrmRet = IStream_Create(NULL, lpbDup, dwDataLen); |
| |
| if (!iStrmRet) |
| HeapFree(GetProcessHeap(), 0, lpbDup); |
| } |
| } |
| return iStrmRet; |
| } |
| |
| /************************************************************************* |
| * SHCreateStreamWrapper [SHLWAPI.@] |
| * |
| * Create an IStream object on a block of memory. |
| * |
| * PARAMS |
| * lpbData [I] Memory block to create the IStream object on |
| * dwDataLen [I] Length of data block |
| * dwReserved [I] Reserved, Must be 0. |
| * lppStream [O] Destination for IStream object |
| * |
| * RETURNS |
| * Success: S_OK. lppStream contains the new IStream object. |
| * Failure: E_INVALIDARG, if any parameters are invalid, |
| * E_OUTOFMEMORY if memory allocation fails. |
| * |
| * NOTES |
| * The stream assumes ownership of the memory passed to it. |
| */ |
| HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen, |
| DWORD dwReserved, IStream **lppStream) |
| { |
| IStream* lpStream; |
| |
| if (lppStream) |
| *lppStream = NULL; |
| |
| if(dwReserved || !lppStream) |
| return E_INVALIDARG; |
| |
| lpStream = IStream_Create(NULL, lpbData, dwDataLen); |
| |
| if(!lpStream) |
| return E_OUTOFMEMORY; |
| |
| IStream_QueryInterface(lpStream, &IID_IStream, (void**)lppStream); |
| IStream_Release(lpStream); |
| return S_OK; |
| } |