Discussion:
COleDataSource with IStream and CFSTR_FILEDESCRIPTOR
(too old to reply)
Nathan R.
2003-10-19 10:04:23 UTC
Permalink
Hello,
I use COleDataSource to set the Clipboard for my application. I am
using CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS with ColeDataSource
and IStream. My application displays the objects of a remote system
which resembles the directory structure of windows. Please can anybody
tell how to use an IStream object (implemented by me) ca be used for
getting data. Here is the code i used...

BOOL CMyDataSource::OnRenderData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM
lpStgMedium)
{
BOOL bReturn = FALSE;
if (lpFormatEtc->cfFormat == g_cfFileContents)
{
HRESULT hr = S_FALSE;
//Create an instance of CIStreamImpl which implements IStream
CIStreamImpl *pStreamImpl= new CIStreamImpl();
hr = pStreamImpl->QueryInterface(IID_IStream,(void FAR*
FAR*)&pStreamImpl);
if(SUCCEEDED(hr))
{
lpStgMedium->tymed = TYMED_ISTREAM;
lpStgMedium->pstm = pStreamImpl;
lpStgMedium->pUnkForRelease = NULL;
bReturn = TRUE;//Set the return value
}else
pStreamImpl->Release();
}
else
if (lpFormatEtc->cfFormat == g_cfFileGroupDescriptor)
{
lpStgMedium->tymed = TYMED_HGLOBAL;
lpStgMedium->hGlobal = CreateFileGroupDescriptor();
bReturn = TRUE; //Set the return value
}
return bReturn;
}
In CreateFileGroupDescriptor(), the file group descriptor is created
with file descriptor flag (dwFlag) FD_FILESIZE. nFileSizeLow = 1024
and nFileSizeHigh = 0; When the user clicks on "paste" menu item in
the explorer, the CIStreamImpl::Read( void *pv, ULONG cb, ULONG
*pcbRead ) is getting called. But the value of the parameter ''cb" is
always 16384 :-(. Also it seems that the Read(...) method being called
just as in an infinite loop. Why the Windows Explorer does not call
Read method with cb=1024 (Which is set in Filegroupdescriptor)? Can
anybody help me to figure out the things?

Here is the read method of CIStremImpl, cb is always 16384.
STDMETHODIMP CIStreamImpl::Read( void *pv, ULONG cb, ULONG *pcbRead )
{
if(NULL == pv) return STG_E_INVALIDPOINTER;
if(cb > 0)
{
TRACE ("The value of cb=%d\n",cb);
//Set some data
memset( pv, 'A', cb);
*pcbRead = cb;
return S_OK;
}
return S_FALSE;
}

regards
Nathan
unknown
2003-10-19 18:18:52 UTC
Permalink
When your stream is asked to read 16384 bytes, just return 1024 bytes. It is
legal to issue a read request for 16384 bytes even if the stream has only
1024. The stream should return what it has. (and set the number of bytes
read accordingly.)

The file size in the file group descriptor is merely advisory. It's possible
that in the time between the query for the file group descriptor and the
actual stream, the size of the virtual file may have changed, so Explorer
plays it safe and tries to read as much as possible.
Post by Nathan R.
In CreateFileGroupDescriptor(), the file group descriptor is created
with file descriptor flag (dwFlag) FD_FILESIZE. nFileSizeLow = 1024
and nFileSizeHigh = 0; When the user clicks on "paste" menu item in
the explorer, the CIStreamImpl::Read( void *pv, ULONG cb, ULONG
*pcbRead ) is getting called. But the value of the parameter ''cb" is
always 16384 :-(. Also it seems that the Read(...) method being called
just as in an infinite loop. Why the Windows Explorer does not call
Read method with cb=1024 (Which is set in Filegroupdescriptor)? Can
anybody help me to figure out the things?
Nathan R.
2003-10-20 05:21:57 UTC
Permalink
Thankyou Chen.
What you are saying is, the size specified in FileGroupDescriptor has
nothing to do with the actual size of the stream? Then it becomes the
resposibility of the IStream implementor to handle the size of the
stream internally. Okay, I'll change the code accordingly. Thank you
for the valueable information.

regards
Nathan R.
Post by unknown
When your stream is asked to read 16384 bytes, just return 1024 bytes. It is
legal to issue a read request for 16384 bytes even if the stream has only
1024. The stream should return what it has. (and set the number of bytes
read accordingly.)
The file size in the file group descriptor is merely advisory. It's possible
that in the time between the query for the file group descriptor and the
actual stream, the size of the virtual file may have changed, so Explorer
plays it safe and tries to read as much as possible.
Post by Nathan R.
In CreateFileGroupDescriptor(), the file group descriptor is created
with file descriptor flag (dwFlag) FD_FILESIZE. nFileSizeLow = 1024
and nFileSizeHigh = 0; When the user clicks on "paste" menu item in
the explorer, the CIStreamImpl::Read( void *pv, ULONG cb, ULONG
*pcbRead ) is getting called. But the value of the parameter ''cb" is
always 16384 :-(. Also it seems that the Read(...) method being called
just as in an infinite loop. Why the Windows Explorer does not call
Read method with cb=1024 (Which is set in Filegroupdescriptor)? Can
anybody help me to figure out the things?
Henk Devos
2003-10-20 22:46:49 UTC
Permalink
I rather think they take the easiest approach and have a fixed buffer size.
Post by Nathan R.
Thankyou Chen.
What you are saying is, the size specified in FileGroupDescriptor has
nothing to do with the actual size of the stream? Then it becomes the
resposibility of the IStream implementor to handle the size of the
stream internally. Okay, I'll change the code accordingly. Thank you
for the valueable information.
regards
Nathan R.
Post by unknown
When your stream is asked to read 16384 bytes, just return 1024 bytes. It is
legal to issue a read request for 16384 bytes even if the stream has only
1024. The stream should return what it has. (and set the number of bytes
read accordingly.)
The file size in the file group descriptor is merely advisory. It's possible
that in the time between the query for the file group descriptor and the
actual stream, the size of the virtual file may have changed, so Explorer
plays it safe and tries to read as much as possible.
Post by Nathan R.
In CreateFileGroupDescriptor(), the file group descriptor is created
with file descriptor flag (dwFlag) FD_FILESIZE. nFileSizeLow = 1024
and nFileSizeHigh = 0; When the user clicks on "paste" menu item in
the explorer, the CIStreamImpl::Read( void *pv, ULONG cb, ULONG
*pcbRead ) is getting called. But the value of the parameter ''cb" is
always 16384 :-(. Also it seems that the Read(...) method being called
just as in an infinite loop. Why the Windows Explorer does not call
Read method with cb=1024 (Which is set in Filegroupdescriptor)? Can
anybody help me to figure out the things?
unknown
2003-10-22 04:29:45 UTC
Permalink
The size in the FileGroupDescriptor is used to guide the progress bar and to
give the shell an idea of how big the stream is going to be. But if there
is a disagreement between the FileGroupDescriptor and the stream itself, the
stream size wins.

If you are implementing a stream, you have to be prepared for reading past
the end anyway. So this is something you already had to do, it's not like
it's new work.

This is necessary because a stream's length might change during the
drag/drop operation. For eaxmple, when you start the drag, the file is 100
bytes long. While you drag it, the file changes size to 200 bytes. If the
shell used the size in the FileGroupDescriptor and ignored the length
reported by the stream itself, it would end up copying only the first 100
bytes of the file, which is wrong. It should copy the entire file. And it
does, by reading the stream until the stream reports no more data.
Post by Nathan R.
Thankyou Chen.
What you are saying is, the size specified in FileGroupDescriptor has
nothing to do with the actual size of the stream? Then it becomes the
resposibility of the IStream implementor to handle the size of the
stream internally. Okay, I'll change the code accordingly. Thank you
for the valueable information.
regards
Nathan R.
Post by unknown
When your stream is asked to read 16384 bytes, just return 1024 bytes. It is
legal to issue a read request for 16384 bytes even if the stream has only
1024. The stream should return what it has. (and set the number of bytes
read accordingly.)
The file size in the file group descriptor is merely advisory. It's possible
that in the time between the query for the file group descriptor and the
actual stream, the size of the virtual file may have changed, so Explorer
plays it safe and tries to read as much as possible.
Post by Nathan R.
In CreateFileGroupDescriptor(), the file group descriptor is created
with file descriptor flag (dwFlag) FD_FILESIZE. nFileSizeLow = 1024
and nFileSizeHigh = 0; When the user clicks on "paste" menu item in
the explorer, the CIStreamImpl::Read( void *pv, ULONG cb, ULONG
*pcbRead ) is getting called. But the value of the parameter ''cb" is
always 16384 :-(. Also it seems that the Read(...) method being called
just as in an infinite loop. Why the Windows Explorer does not call
Read method with cb=1024 (Which is set in Filegroupdescriptor)? Can
anybody help me to figure out the things?
Nathan R.
2003-10-22 13:16:56 UTC
Permalink
Yes Chen, what you said is right. But now arises one more doubt
regarding the implementation of folder copying. Inorder to copy the
file/folder to the Windows Explorer (using CFSTR_FILEDESCRIPTOR)the
FileDescriptors are to be created first, right. But if a remote folder
which contains a number of subfolders and files is to be copied, how
the FileDescriptor is created? i.e. Do we need to create all the
FileDescriptors of all the files and subfolders at the begining
itself?

regards
Nathan.
Post by unknown
The size in the FileGroupDescriptor is used to guide the progress bar and to
give the shell an idea of how big the stream is going to be. But if there
is a disagreement between the FileGroupDescriptor and the stream itself, the
stream size wins.
If you are implementing a stream, you have to be prepared for reading past
the end anyway. So this is something you already had to do, it's not like
it's new work.
This is necessary because a stream's length might change during the
drag/drop operation. For eaxmple, when you start the drag, the file is 100
bytes long. While you drag it, the file changes size to 200 bytes. If the
shell used the size in the FileGroupDescriptor and ignored the length
reported by the stream itself, it would end up copying only the first 100
bytes of the file, which is wrong. It should copy the entire file. And it
does, by reading the stream until the stream reports no more data.
Post by Nathan R.
Thankyou Chen.
What you are saying is, the size specified in FileGroupDescriptor has
nothing to do with the actual size of the stream? Then it becomes the
resposibility of the IStream implementor to handle the size of the
stream internally. Okay, I'll change the code accordingly. Thank you
for the valueable information.
regards
Nathan R.
Post by unknown
When your stream is asked to read 16384 bytes, just return 1024 bytes.
It is
Post by Nathan R.
Post by unknown
legal to issue a read request for 16384 bytes even if the stream has
only
Post by Nathan R.
Post by unknown
1024. The stream should return what it has. (and set the number of bytes
read accordingly.)
The file size in the file group descriptor is merely advisory. It's
possible
Post by Nathan R.
Post by unknown
that in the time between the query for the file group descriptor and the
actual stream, the size of the virtual file may have changed, so
Explorer
Post by Nathan R.
Post by unknown
plays it safe and tries to read as much as possible.
Post by Nathan R.
In CreateFileGroupDescriptor(), the file group descriptor is created
with file descriptor flag (dwFlag) FD_FILESIZE. nFileSizeLow = 1024
and nFileSizeHigh = 0; When the user clicks on "paste" menu item in
the explorer, the CIStreamImpl::Read( void *pv, ULONG cb, ULONG
*pcbRead ) is getting called. But the value of the parameter ''cb" is
always 16384 :-(. Also it seems that the Read(...) method being called
just as in an infinite loop. Why the Windows Explorer does not call
Read method with cb=1024 (Which is set in Filegroupdescriptor)? Can
anybody help me to figure out the things?
Loading...