Added support of loading of IPicture data from non-statable
IStreams. Added testcases for this.
This commit is contained in:
parent
a533bd3056
commit
c49f5f0095
|
@ -1056,6 +1056,7 @@ static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
|
|||
static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
|
||||
HRESULT hr = E_FAIL;
|
||||
BOOL headerisdata = FALSE;
|
||||
BOOL statfailed = FALSE;
|
||||
ULONG xread, toread;
|
||||
BYTE *xbuf;
|
||||
DWORD header[2];
|
||||
|
@ -1065,19 +1066,29 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
|
|||
|
||||
TRACE("(%p,%p)\n",This,pStm);
|
||||
|
||||
/****************************************************************************************
|
||||
* Part 1: Load the data
|
||||
*/
|
||||
/* Sometimes we have a header, sometimes we don't. Apply some guesses to find
|
||||
* out whether we do.
|
||||
*
|
||||
* UPDATE: the IStream can be mapped to a plain file instead of a stream in a
|
||||
* compound file. This may explain most, if not all, of the cases of "no header",
|
||||
* and the header validation should take this into account. At least in Visual Basic 6,
|
||||
* resource streams, valid headers are
|
||||
* compound file. This may explain most, if not all, of the cases of "no
|
||||
* header", and the header validation should take this into account.
|
||||
* At least in Visual Basic 6, resource streams, valid headers are
|
||||
* header[0] == "lt\0\0",
|
||||
* header[1] == length_of_stream.
|
||||
*
|
||||
* Also handle streams where we do not have a working "Stat" method by
|
||||
* reading all data until the end of the stream.
|
||||
*/
|
||||
hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
|
||||
if (hr)
|
||||
FIXME("Stat failed with hres %lx\n",hr);
|
||||
if (hr) {
|
||||
TRACE("stat failed with hres %lx, proceeding to read all data.\n",hr);
|
||||
statfailed = TRUE;
|
||||
/* we will read at least 8 byte ... just right below */
|
||||
statstg.cbSize.QuadPart = 8;
|
||||
}
|
||||
hr=IStream_Read(pStm,header,8,&xread);
|
||||
if (hr || xread!=8) {
|
||||
FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
|
||||
|
@ -1089,42 +1100,77 @@ static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
|
|||
if (!memcmp(&(header[0]),"lt\0\0", 4) && (header[1] <= statstg.cbSize.QuadPart-8)) {
|
||||
toread = header[1];
|
||||
} else {
|
||||
if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
|
||||
!memcmp(&(header[0]), "BM", 2) || /* BMP header */
|
||||
!memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
|
||||
(header[1] > statstg.cbSize.QuadPart) || /* invalid size */
|
||||
(header[1]==0)
|
||||
if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
|
||||
!memcmp(&(header[0]), "BM", 2) || /* BMP header */
|
||||
!memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
|
||||
(header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
|
||||
(header[1]==0)
|
||||
) {/* Incorrect header, assume none. */
|
||||
headerisdata = TRUE;
|
||||
toread = statstg.cbSize.QuadPart-8;
|
||||
xread = 8;
|
||||
xread = 8;
|
||||
} else {
|
||||
FIXME("Unknown stream header magic: %08lx\n", header[0]);
|
||||
FIXME("Unknown stream header magic: %08lx\n", header[0]);
|
||||
toread = header[1];
|
||||
}
|
||||
}
|
||||
|
||||
This->datalen = toread+(headerisdata?8:0);
|
||||
xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
|
||||
if (statfailed) { /* we dont know the size ... read all we get */
|
||||
int sizeinc = 4096;
|
||||
int origsize = sizeinc;
|
||||
ULONG nread = 42;
|
||||
|
||||
if (headerisdata)
|
||||
memcpy (xbuf, &header, 8);
|
||||
TRACE("Reading all data from stream.\n");
|
||||
xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
|
||||
if (headerisdata)
|
||||
memcpy (xbuf, &header, 8);
|
||||
while (1) {
|
||||
while (xread < origsize) {
|
||||
hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
|
||||
xread+=nread;
|
||||
if (hr || !nread)
|
||||
break;
|
||||
}
|
||||
if (!nread || hr) /* done, or error */
|
||||
break;
|
||||
if (xread == origsize) {
|
||||
origsize += sizeinc;
|
||||
sizeinc = 2*sizeinc; /* exponential increase */
|
||||
xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
|
||||
}
|
||||
}
|
||||
if (hr)
|
||||
TRACE("hr in no-stat loader case is %08lx\n", hr);
|
||||
TRACE("loaded %ld bytes.\n", xread);
|
||||
This->datalen = xread;
|
||||
This->data = xbuf;
|
||||
} else {
|
||||
This->datalen = toread+(headerisdata?8:0);
|
||||
xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
|
||||
|
||||
while (xread < This->datalen) {
|
||||
ULONG nread;
|
||||
hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
|
||||
xread+=nread;
|
||||
if (hr || !nread)
|
||||
break;
|
||||
if (headerisdata)
|
||||
memcpy (xbuf, &header, 8);
|
||||
|
||||
while (xread < This->datalen) {
|
||||
ULONG nread;
|
||||
hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
|
||||
xread+=nread;
|
||||
if (hr || !nread)
|
||||
break;
|
||||
}
|
||||
if (xread != This->datalen)
|
||||
FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
|
||||
}
|
||||
if (xread != This->datalen)
|
||||
FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
|
||||
|
||||
if (This->datalen == 0) { /* Marks the "NONE" picture */
|
||||
if (This->datalen == 0) { /* Marks the "NONE" picture */
|
||||
This->desc.picType = PICTYPE_NONE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Part 2: Process the loaded data
|
||||
*/
|
||||
|
||||
magic = xbuf[0] + (xbuf[1]<<8);
|
||||
switch (magic) {
|
||||
case 0x4947: { /* GIF */
|
||||
|
|
|
@ -102,17 +102,24 @@ static const unsigned char gif4pixel[42] = {
|
|||
0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
|
||||
};
|
||||
|
||||
static void
|
||||
test_pic(const unsigned char *imgdata, unsigned int imgsize)
|
||||
struct NoStatStreamImpl
|
||||
{
|
||||
const IStreamVtbl *lpVtbl;
|
||||
LONG ref;
|
||||
|
||||
HGLOBAL supportHandle;
|
||||
ULARGE_INTEGER streamSize;
|
||||
ULARGE_INTEGER currentPosition;
|
||||
};
|
||||
typedef struct NoStatStreamImpl NoStatStreamImpl;
|
||||
static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal);
|
||||
|
||||
static void
|
||||
test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
|
||||
{
|
||||
LPBYTE data;
|
||||
LPSTREAM stream;
|
||||
IPicture* pic = NULL;
|
||||
HRESULT hres;
|
||||
LPVOID pvObj = NULL;
|
||||
HGLOBAL hglob;
|
||||
ULARGE_INTEGER newpos1;
|
||||
LARGE_INTEGER seekto;
|
||||
OLE_HANDLE handle, hPal;
|
||||
OLE_XSIZE_HIMETRIC width;
|
||||
OLE_YSIZE_HIMETRIC height;
|
||||
|
@ -120,18 +127,6 @@ test_pic(const unsigned char *imgdata, unsigned int imgsize)
|
|||
DWORD attr;
|
||||
ULONG res;
|
||||
|
||||
/* let the fun begin */
|
||||
hglob = GlobalAlloc (0, imgsize);
|
||||
data = GlobalLock (hglob);
|
||||
memcpy(data, imgdata, imgsize);
|
||||
|
||||
hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
|
||||
ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08lx\n", hres);
|
||||
|
||||
memset(&seekto,0,sizeof(seekto));
|
||||
hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
|
||||
ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
|
||||
|
||||
pvObj = NULL;
|
||||
hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
|
||||
pic = pvObj;
|
||||
|
@ -141,20 +136,6 @@ test_pic(const unsigned char *imgdata, unsigned int imgsize)
|
|||
if (pic == NULL)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos2);
|
||||
ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
|
||||
|
||||
/* The stream position here is some bytes after the image, in both wine and
|
||||
* native. But not at the correct end. -Marcus
|
||||
*/
|
||||
fprintf(stderr,"newpos1 %ld, newpos2 %ld\n", newpos1.LowPart, newpos2.LowPart);
|
||||
ok ( newpos2.LowPart == imgsize,
|
||||
"seeked after end of gifimage (offset %d instead of expected %d)\n",
|
||||
newpos2.LowPart, imgsize
|
||||
);
|
||||
#endif
|
||||
|
||||
pvObj = NULL;
|
||||
hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
|
||||
|
||||
|
@ -195,7 +176,35 @@ test_pic(const unsigned char *imgdata, unsigned int imgsize)
|
|||
ok(hPal == 0, "IPicture_get_hPal returns %ld, but it should be 0.\n", (long)hPal);
|
||||
|
||||
res = IPicture_Release (pic);
|
||||
ok (res == 0, "refcount after release is %ld, but should be 1?\n", res);
|
||||
ok (res == 0, "refcount after release is %ld, but should be 0?\n", res);
|
||||
}
|
||||
|
||||
static void
|
||||
test_pic(const unsigned char *imgdata, unsigned int imgsize)
|
||||
{
|
||||
LPSTREAM stream;
|
||||
HGLOBAL hglob;
|
||||
LPBYTE data;
|
||||
HRESULT hres;
|
||||
LARGE_INTEGER seekto;
|
||||
ULARGE_INTEGER newpos1;
|
||||
|
||||
/* Let the fun begin */
|
||||
hglob = GlobalAlloc (0, imgsize);
|
||||
data = GlobalLock (hglob);
|
||||
memcpy(data, imgdata, imgsize);
|
||||
|
||||
hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
|
||||
ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08lx\n", hres);
|
||||
|
||||
memset(&seekto,0,sizeof(seekto));
|
||||
hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
|
||||
ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
|
||||
test_pic_with_stream(stream, imgsize);
|
||||
|
||||
/* again with Non Statable and Non Seekable stream */
|
||||
stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
|
||||
test_pic_with_stream(stream, 0);
|
||||
}
|
||||
|
||||
static void test_empty_image(void) {
|
||||
|
@ -288,9 +297,294 @@ START_TEST(olepicture)
|
|||
test_pic(jpgimage, sizeof(jpgimage));
|
||||
test_pic(bmpimage, sizeof(bmpimage));
|
||||
test_pic(gif4pixel, sizeof(gif4pixel));
|
||||
/* no PNG support yet here or in older Windows...
|
||||
/* No PNG support yet here or in older Windows...
|
||||
test_pic(pngimage, sizeof(pngimage));
|
||||
*/
|
||||
test_empty_image();
|
||||
test_empty_image_2();
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions only ... */
|
||||
|
||||
|
||||
static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
|
||||
{
|
||||
GlobalFree(This->supportHandle);
|
||||
This->supportHandle=0;
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
static ULONG WINAPI NoStatStreamImpl_AddRef(
|
||||
IStream* iface)
|
||||
{
|
||||
NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
|
||||
return InterlockedIncrement(&This->ref);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
|
||||
IStream* iface,
|
||||
REFIID riid, /* [in] */
|
||||
void** ppvObject) /* [iid_is][out] */
|
||||
{
|
||||
NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
|
||||
if (ppvObject==0) return E_INVALIDARG;
|
||||
*ppvObject = 0;
|
||||
if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
|
||||
{
|
||||
*ppvObject = (IStream*)This;
|
||||
}
|
||||
else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
|
||||
{
|
||||
*ppvObject = (IStream*)This;
|
||||
}
|
||||
|
||||
if ((*ppvObject)==0)
|
||||
return E_NOINTERFACE;
|
||||
NoStatStreamImpl_AddRef(iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI NoStatStreamImpl_Release(
|
||||
IStream* iface)
|
||||
{
|
||||
NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
|
||||
ULONG newRef = InterlockedDecrement(&This->ref);
|
||||
if (newRef==0)
|
||||
NoStatStreamImpl_Destroy(This);
|
||||
return newRef;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_Read(
|
||||
IStream* iface,
|
||||
void* pv, /* [length_is][size_is][out] */
|
||||
ULONG cb, /* [in] */
|
||||
ULONG* pcbRead) /* [out] */
|
||||
{
|
||||
NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
|
||||
void* supportBuffer;
|
||||
ULONG bytesReadBuffer;
|
||||
ULONG bytesToReadFromBuffer;
|
||||
|
||||
if (pcbRead==0)
|
||||
pcbRead = &bytesReadBuffer;
|
||||
bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
|
||||
supportBuffer = GlobalLock(This->supportHandle);
|
||||
memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
|
||||
This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
|
||||
*pcbRead = bytesToReadFromBuffer;
|
||||
GlobalUnlock(This->supportHandle);
|
||||
if(*pcbRead == cb)
|
||||
return S_OK;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_Write(
|
||||
IStream* iface,
|
||||
const void* pv, /* [size_is][in] */
|
||||
ULONG cb, /* [in] */
|
||||
ULONG* pcbWritten) /* [out] */
|
||||
{
|
||||
NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
|
||||
void* supportBuffer;
|
||||
ULARGE_INTEGER newSize;
|
||||
ULONG bytesWritten = 0;
|
||||
|
||||
if (pcbWritten == 0)
|
||||
pcbWritten = &bytesWritten;
|
||||
if (cb == 0)
|
||||
return S_OK;
|
||||
newSize.u.HighPart = 0;
|
||||
newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
|
||||
if (newSize.u.LowPart > This->streamSize.u.LowPart)
|
||||
IStream_SetSize(iface, newSize);
|
||||
|
||||
supportBuffer = GlobalLock(This->supportHandle);
|
||||
memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
|
||||
This->currentPosition.u.LowPart+=cb;
|
||||
*pcbWritten = cb;
|
||||
GlobalUnlock(This->supportHandle);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_Seek(
|
||||
IStream* iface,
|
||||
LARGE_INTEGER dlibMove, /* [in] */
|
||||
DWORD dwOrigin, /* [in] */
|
||||
ULARGE_INTEGER* plibNewPosition) /* [out] */
|
||||
{
|
||||
NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
|
||||
ULARGE_INTEGER newPosition;
|
||||
switch (dwOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET:
|
||||
newPosition.u.HighPart = 0;
|
||||
newPosition.u.LowPart = 0;
|
||||
break;
|
||||
case STREAM_SEEK_CUR:
|
||||
newPosition = This->currentPosition;
|
||||
break;
|
||||
case STREAM_SEEK_END:
|
||||
newPosition = This->streamSize;
|
||||
break;
|
||||
default:
|
||||
return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
|
||||
return STG_E_INVALIDFUNCTION;
|
||||
newPosition.QuadPart += dlibMove.QuadPart;
|
||||
if (plibNewPosition) *plibNewPosition = newPosition;
|
||||
This->currentPosition = newPosition;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_SetSize(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libNewSize) /* [in] */
|
||||
{
|
||||
NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
|
||||
HGLOBAL supportHandle;
|
||||
if (libNewSize.u.HighPart != 0)
|
||||
return STG_E_INVALIDFUNCTION;
|
||||
if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
|
||||
return S_OK;
|
||||
supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
|
||||
if (supportHandle == 0)
|
||||
return STG_E_MEDIUMFULL;
|
||||
This->supportHandle = supportHandle;
|
||||
This->streamSize.u.LowPart = libNewSize.u.LowPart;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_CopyTo(
|
||||
IStream* iface,
|
||||
IStream* pstm, /* [unique][in] */
|
||||
ULARGE_INTEGER cb, /* [in] */
|
||||
ULARGE_INTEGER* pcbRead, /* [out] */
|
||||
ULARGE_INTEGER* pcbWritten) /* [out] */
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BYTE tmpBuffer[128];
|
||||
ULONG bytesRead, bytesWritten, copySize;
|
||||
ULARGE_INTEGER totalBytesRead;
|
||||
ULARGE_INTEGER totalBytesWritten;
|
||||
|
||||
if ( pstm == 0 )
|
||||
return STG_E_INVALIDPOINTER;
|
||||
totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
|
||||
totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
|
||||
|
||||
while ( cb.u.LowPart > 0 )
|
||||
{
|
||||
if ( cb.u.LowPart >= 128 )
|
||||
copySize = 128;
|
||||
else
|
||||
copySize = cb.u.LowPart;
|
||||
IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
|
||||
totalBytesRead.u.LowPart += bytesRead;
|
||||
IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
|
||||
totalBytesWritten.u.LowPart += bytesWritten;
|
||||
if (bytesRead != bytesWritten)
|
||||
{
|
||||
hr = STG_E_MEDIUMFULL;
|
||||
break;
|
||||
}
|
||||
if (bytesRead!=copySize)
|
||||
cb.u.LowPart = 0;
|
||||
else
|
||||
cb.u.LowPart -= bytesRead;
|
||||
}
|
||||
if (pcbRead)
|
||||
{
|
||||
pcbRead->u.LowPart = totalBytesRead.u.LowPart;
|
||||
pcbRead->u.HighPart = totalBytesRead.u.HighPart;
|
||||
}
|
||||
|
||||
if (pcbWritten)
|
||||
{
|
||||
pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
|
||||
pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_LockRegion(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libOffset, /* [in] */
|
||||
ULARGE_INTEGER cb, /* [in] */
|
||||
DWORD dwLockType) /* [in] */
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
|
||||
IStream* iface,
|
||||
ULARGE_INTEGER libOffset, /* [in] */
|
||||
ULARGE_INTEGER cb, /* [in] */
|
||||
DWORD dwLockType) /* [in] */
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_Stat(
|
||||
IStream* iface,
|
||||
STATSTG* pstatstg, /* [out] */
|
||||
DWORD grfStatFlag) /* [in] */
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI NoStatStreamImpl_Clone(
|
||||
IStream* iface,
|
||||
IStream** ppstm) /* [out] */
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
static const IStreamVtbl NoStatStreamImpl_Vtbl;
|
||||
|
||||
static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
|
||||
{
|
||||
NoStatStreamImpl* newStream;
|
||||
|
||||
newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
|
||||
if (newStream!=0)
|
||||
{
|
||||
newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
|
||||
newStream->ref = 0;
|
||||
newStream->supportHandle = hGlobal;
|
||||
|
||||
if (!newStream->supportHandle)
|
||||
newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
|
||||
GMEM_SHARE, 0);
|
||||
newStream->currentPosition.u.HighPart = 0;
|
||||
newStream->currentPosition.u.LowPart = 0;
|
||||
newStream->streamSize.u.HighPart = 0;
|
||||
newStream->streamSize.u.LowPart = GlobalSize(newStream->supportHandle);
|
||||
}
|
||||
return newStream;
|
||||
}
|
||||
|
||||
|
||||
static const IStreamVtbl NoStatStreamImpl_Vtbl =
|
||||
{
|
||||
NoStatStreamImpl_QueryInterface,
|
||||
NoStatStreamImpl_AddRef,
|
||||
NoStatStreamImpl_Release,
|
||||
NoStatStreamImpl_Read,
|
||||
NoStatStreamImpl_Write,
|
||||
NoStatStreamImpl_Seek,
|
||||
NoStatStreamImpl_SetSize,
|
||||
NoStatStreamImpl_CopyTo,
|
||||
NoStatStreamImpl_Commit,
|
||||
NoStatStreamImpl_Revert,
|
||||
NoStatStreamImpl_LockRegion,
|
||||
NoStatStreamImpl_UnlockRegion,
|
||||
NoStatStreamImpl_Stat,
|
||||
NoStatStreamImpl_Clone
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue