/* * 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 #include #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; TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead); if (This->dwPos >= This->dwLength) dwBytesToRead = 0; else dwBytesToRead = This->dwLength - This->dwPos; dwBytesToRead = (cb > dwBytesToRead) ? dwBytesToRead : cb; if (dwBytesToRead != 0) /* not at end of buffer and we want to read something */ { 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, %p, %d)\n",This,pstatstg,grfStatFlag); pstatstg->pwcsName = NULL; pstatstg->type = STGTY_STREAM; pstatstg->cbSize.QuadPart = This->dwLength; pstatstg->mtime.dwHighDateTime = 0; pstatstg->mtime.dwLowDateTime = 0; pstatstg->ctime.dwHighDateTime = 0; pstatstg->ctime.dwLowDateTime = 0; pstatstg->atime.dwHighDateTime = 0; pstatstg->atime.dwLowDateTime = 0; pstatstg->grfMode = STGM_READWRITE; pstatstg->grfLocksSupported = 0; pstatstg->clsid = CLSID_NULL; pstatstg->grfStateBits = 0; pstatstg->reserved = 0; return S_OK; } /************************************************************************* * 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(const BYTE *lpbData, UINT dwDataLen) { IStream *iStrmRet = NULL; LPBYTE lpbDup; TRACE("(%p,%d)\n", lpbData, dwDataLen); if (!lpbData) dwDataLen = 0; 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; }