Build and load import libraries directly from the dll directory where
[wine] / dlls / shell32 / memorystream.c
1 /*
2  *      This class implements a pure IStream object
3  *      and can be used for many purposes.
4  *
5  *      The main reason for implementing this was
6  *      a cleaner implementation of IShellLink which
7  *      needs to be able to load lnks from an IStream
8  *      interface so it was obvious to capsule the file
9  *      access in an IStream to.
10  *
11  * Copyright 1999 Juergen Schmied
12  * Copyright 2003 Mike McCormack for CodeWeavers
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28
29 #include <stdarg.h>
30 #include <string.h>
31
32 #define COBJMACROS
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winuser.h"
38 #include "wingdi.h"
39 #include "shlobj.h"
40 #include "wine/debug.h"
41 #include "shell32_main.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(shell);
44
45 #define STGM_ACCESS_MODE(stgm)   ((stgm)&0x0000f)
46 #define STGM_SHARE_MODE(stgm)    ((stgm)&0x000f0)
47 #define STGM_CREATE_MODE(stgm)   ((stgm)&0x0f000)
48
49 typedef struct
50 {       
51         const IStreamVtbl       *lpvtst;
52         DWORD                   ref;
53         HANDLE                  handle;
54 } ISHFileStream;
55
56 /**************************************************************************
57 *  IStream_fnQueryInterface
58 */
59 static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj)
60 {
61         ISHFileStream *This = (ISHFileStream *)iface;
62
63         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
64
65         *ppvObj = NULL;
66
67         if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IStream))
68                 *ppvObj = This;
69
70         if(*ppvObj)
71         {
72                 IStream_AddRef((IStream*)*ppvObj);
73                 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
74                 return S_OK;
75         }
76         TRACE("-- Interface: E_NOINTERFACE\n");
77         return E_NOINTERFACE;
78 }
79
80 /**************************************************************************
81 *  IStream_fnAddRef
82 */
83 static ULONG WINAPI IStream_fnAddRef(IStream *iface)
84 {
85         ISHFileStream *This = (ISHFileStream *)iface;
86         ULONG refCount = InterlockedIncrement(&This->ref);
87
88         TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
89
90         return refCount;
91 }
92
93 /**************************************************************************
94 *  IStream_fnRelease
95 */
96 static ULONG WINAPI IStream_fnRelease(IStream *iface)
97 {
98         ISHFileStream *This = (ISHFileStream *)iface;
99         ULONG refCount = InterlockedDecrement(&This->ref);
100
101         TRACE("(%p)->(count=%lu)\n", This, refCount + 1);
102
103         if (!refCount)
104         {
105                 TRACE(" destroying SHFileStream (%p)\n",This);
106                 CloseHandle(This->handle);
107                 HeapFree(GetProcessHeap(),0,This);
108         }
109         return refCount;
110 }
111
112 static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead)
113 {
114         ISHFileStream *This = (ISHFileStream *)iface;
115
116         TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead);
117
118         if ( !pv )
119                 return STG_E_INVALIDPOINTER;
120
121         if ( ! ReadFile( This->handle, pv, cb, pcbRead, NULL ) )
122                 return S_FALSE;
123
124         return S_OK;
125 }
126
127 static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten)
128 {
129        DWORD dummy_count;
130         ISHFileStream *This = (ISHFileStream *)iface;
131
132         TRACE("(%p)\n",This);
133
134         if( !pv )
135                 return STG_E_INVALIDPOINTER;
136
137        /* WriteFile() doesn't allow to specify NULL as write count pointer */
138        if (!pcbWritten)
139                pcbWritten = &dummy_count;
140
141         if( ! WriteFile( This->handle, pv, cb, pcbWritten, NULL ) )
142                 return E_FAIL;
143
144         return S_OK;
145 }
146
147 static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
148 {
149         DWORD pos, newposlo, newposhi;
150
151         ISHFileStream *This = (ISHFileStream *)iface;
152
153         TRACE("(%p)\n",This);
154
155         pos = dlibMove.QuadPart; /* FIXME: truncates */
156         newposhi = 0;
157         newposlo = SetFilePointer( This->handle, pos, &newposhi, dwOrigin );
158         if( newposlo == INVALID_SET_FILE_POINTER )
159                 return E_FAIL;
160
161         plibNewPosition->QuadPart = newposlo | ( (LONGLONG)newposhi<<32);
162
163         return S_OK;
164 }
165
166 static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize)
167 {
168         ISHFileStream *This = (ISHFileStream *)iface;
169
170         TRACE("(%p)\n",This);
171
172         if( ! SetFilePointer( This->handle, libNewSize.QuadPart, NULL, FILE_BEGIN ) )
173                 return E_FAIL;
174
175         if( ! SetEndOfFile( This->handle ) )
176                 return E_FAIL;
177
178         return S_OK;
179 }
180 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
181 {
182         ISHFileStream *This = (ISHFileStream *)iface;
183
184         TRACE("(%p)\n",This);
185
186         return E_NOTIMPL;
187 }
188 static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags)
189 {
190         ISHFileStream *This = (ISHFileStream *)iface;
191
192         TRACE("(%p)\n",This);
193
194         return E_NOTIMPL;
195 }
196 static HRESULT WINAPI IStream_fnRevert (IStream * iface)
197 {
198         ISHFileStream *This = (ISHFileStream *)iface;
199
200         TRACE("(%p)\n",This);
201
202         return E_NOTIMPL;
203 }
204 static HRESULT WINAPI IStream_fnLockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
205 {
206         ISHFileStream *This = (ISHFileStream *)iface;
207
208         TRACE("(%p)\n",This);
209
210         return E_NOTIMPL;
211 }
212 static HRESULT WINAPI IStream_fnUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
213 {
214         ISHFileStream *This = (ISHFileStream *)iface;
215
216         TRACE("(%p)\n",This);
217
218         return E_NOTIMPL;
219 }
220 static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG*   pstatstg, DWORD grfStatFlag)
221 {
222         ISHFileStream *This = (ISHFileStream *)iface;
223
224         TRACE("(%p)\n",This);
225
226         return E_NOTIMPL;
227 }
228 static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm)
229 {
230         ISHFileStream *This = (ISHFileStream *)iface;
231
232         TRACE("(%p)\n",This);
233
234         return E_NOTIMPL;
235 }
236
237 static const IStreamVtbl stvt =
238 {
239         IStream_fnQueryInterface,
240         IStream_fnAddRef,
241         IStream_fnRelease,
242         IStream_fnRead,
243         IStream_fnWrite,
244         IStream_fnSeek,
245         IStream_fnSetSize,
246         IStream_fnCopyTo,
247         IStream_fnCommit,
248         IStream_fnRevert,
249         IStream_fnLockRegion,
250         IStream_fnUnlockRegion,
251         IStream_fnStat,
252         IStream_fnClone
253 };
254
255 /**************************************************************************
256  *   CreateStreamOnFile()
257  *
258  *   similar to CreateStreamOnHGlobal
259  */
260 HRESULT CreateStreamOnFile (LPCWSTR pszFilename, DWORD grfMode, IStream ** ppstm)
261 {
262         ISHFileStream*  fstr;
263         HANDLE          handle;
264         DWORD           access = GENERIC_READ, creat;
265
266         if( grfMode & STGM_TRANSACTED )
267                 return E_INVALIDARG;
268
269         switch( STGM_ACCESS_MODE( grfMode ) )
270         {
271         case STGM_READ:
272                 access = GENERIC_READ;
273                 break;
274         case STGM_WRITE:
275         case STGM_READWRITE:
276                 access = GENERIC_WRITE | GENERIC_READ;
277                 break;
278         default:
279                 return STG_E_INVALIDFLAG;
280         }
281
282         switch( STGM_CREATE_MODE( grfMode ) )
283         {
284         case STGM_CREATE:
285                 creat = CREATE_ALWAYS;
286                 break;
287         case STGM_FAILIFTHERE:
288                 creat = OPEN_EXISTING;
289                 break;
290         default:
291                 return STG_E_INVALIDFLAG;
292         }
293
294         handle = CreateFileW( pszFilename, access,
295                         FILE_SHARE_READ, NULL, creat, 0, NULL );
296         if( handle == INVALID_HANDLE_VALUE )
297                 return HRESULT_FROM_WIN32(GetLastError());
298
299         fstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ISHFileStream));
300         if( !fstr )
301                 return E_OUTOFMEMORY;
302         fstr->lpvtst = &stvt;
303         fstr->ref = 1;
304         fstr->handle = handle;
305
306         (*ppstm) = (IStream*)fstr;
307
308         return S_OK;
309 }