Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using SHFileOperation to copy files to a zip file

908 views
Skip to first unread message

Priya

unread,
Nov 5, 2007, 12:47:03 PM11/5/07
to
Hi,

Could someone tell me if it is possible to use SHFileOperation() function to
copy files to a ZIP file?

I have seen a C# program which uses Shell32.Folder CopyHere() function to do
this successfully and I am trying to port this to C++ using standard Shell
functions. I have read that CopyHere is a wrapper around SHFileOperation so I
am trying to use that.

My problem is that SHFileOperation returns success, but the source file is
not copied to the destination zip file. Instead a copy of the source file is
created in the same folder as the source file.

I have set the wFunc field of the SHFILEOPSTRUCT structure that I pass into
SHFileOperation to FO_COPY and the fFlags field has been set to
FOF_NOCONFIRMATION | FOF_SILENT | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR
| FOF_NOERRORUI.

Can I use SHFileOperation() to add files to a zip folder? If so, what is the
right way to do this? If not, is there another method to accomplish this? Any
information is greatly appreciated.

Thanks,
Priya

Jim Barry

unread,
Nov 6, 2007, 7:25:15 AM11/6/07
to
Priya wrote:
> Could someone tell me if it is possible to use SHFileOperation()
> function to copy files to a ZIP file?

No, SHFileOperation only deals with filesystem files, not virtual namespace objects.

> I have seen a C# program which uses Shell32.Folder CopyHere()
> function to do this successfully and I am trying to port this to C++
> using standard Shell functions. I have read that CopyHere is a
> wrapper around SHFileOperation so I am trying to use that.

CopyHere uses SHFileOperation only if the parameter is a string containing a wildcard path. Otherwise, it simulates a drag-drop operation. You can code this directly, but it's probably easier just to use the shell folder object (it is a COM object that can be used in C++ - it does not require C#).

--
Jim Barry, MVP (Windows SDK)

Priya

unread,
Nov 6, 2007, 12:53:04 PM11/6/07
to
Hi Jim,

Thank you for your response.

I have not worked with Shell objects before, so could you please give me
some more information about using the Shell folder object in C++? Should I be
calling CoCreateInstance to create the object? What CLSID and IID should I
pass to CoCreateInstance?

I could not find the relevant information in the "Shell Objects for C++"
section of MSDN.

Thanks,
Priya

Jim Barry

unread,
Nov 7, 2007, 9:12:33 AM11/7/07
to
Priya wrote:
> I have not worked with Shell objects before, so could you please give
> me some more information about using the Shell folder object in C++?
> Should I be calling CoCreateInstance to create the object? What CLSID
> and IID should I pass to CoCreateInstance?

The CLSID is {13709620-C279-11CE-A49E-444553540000} (CLSID_Shell). The interface is IShellDispatch, IID {D8F015C0-C278-11CE-A49E-444553540000}. The definitions are in ShlDisp.idl/ShlDisp.h.

> I could not find the relevant information in the "Shell Objects for
> C++" section of MSDN.

It's in the "Shell Objects for Scripting and Microsoft Visual Basic" section:

http://msdn2.microsoft.com/en-us/library/bb774094.aspx

Priya

unread,
Nov 7, 2007, 12:43:00 PM11/7/07
to
Hi Jim,

Thanks again for the information. I wrote a sample program to test this out,
but could not get it to work properly. The program compiles and runs fine,
but the source file is not copied to the destination compressed folder. When
I step through the code I see that CopyHere() returns S_OK even though the
file is not copied to the ZIP file. I tried replacing the compressed folder
with a regular folder and CopyHere() worked as expected. Here is my sample
code:

int _tmain(int argc, _TCHAR* argv[])
{
DWORD strlen = 0;
char szFrom[] = "C:\\Test.log",
szTo[] = "C:\\Sample.zip";
HRESULT hResult;
IShellDispatch *pISD;
Folder *pToFolder = NULL;
VARIANT vDir, vFile, vOpt;
BSTR strptr1, strptr2;

CoInitialize(NULL);

hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
IID_IShellDispatch, (void **)&pISD);

if (SUCCEEDED(hResult))
{
strlen = MultiByteToWideChar(CP_ACP, 0, szTo, -1, 0, 0);
strptr1 = SysAllocStringLen(0, strlen);
MultiByteToWideChar(CP_ACP, 0, szTo, -1, strptr1, strlen);

VariantInit(&vDir);
vDir.vt = VT_BSTR;
vDir.bstrVal = strptr1;
hResult = pISD->NameSpace(vDir, &pToFolder);

if (SUCCEEDED(hResult))
{
strlen = MultiByteToWideChar(CP_ACP, 0, szFrom, -1, 0, 0);
strptr2 = SysAllocStringLen(0, strlen);
MultiByteToWideChar(CP_ACP, 0, szFrom, -1, strptr2, strlen);

VariantInit(&vFile);
vFile.vt = VT_BSTR;
vFile.bstrVal = strptr2;

VariantInit(&vOpt);
vOpt.vt = VT_I4;
vOpt.lVal = 4; // Do not display a progress dialog box

hResult = pToFolder->CopyHere(vFile, vOpt);

SysFreeString(strptr2);
pToFolder->Release();
}

SysFreeString(strptr1);
pISD->Release();
}

CoUninitialize();

return 0;
}

Is this the proper way to do it or am I missing some steps? If I wanted to
pass in FolderItem or FolderItems to CopyHere() function what is the variable
type to use?

Please excuse the very basic questions. Normally I look up things like this
online, but there seems to surprisingly little information about this on MSDN
or the other developer sites like CodeProject. Or maybe I am not looking in
the right places. Thanks again for taking the time to answer my questions.

Regards,
Priya

Jim Barry

unread,
Nov 7, 2007, 3:22:24 PM11/7/07
to
Priya wrote:
> Thanks again for the information. I wrote a sample program to test
> this out, but could not get it to work properly. The program compiles
> and runs fine, but the source file is not copied to the destination
> compressed folder.

I think the problem here is that the copy operation is scheduled on a background thread, and your process exits before the thread has had a chance to run. I guess you need to look out for a new thread being created and wait for it to finish before exiting the process.

Priya

unread,
Nov 8, 2007, 5:20:01 AM11/8/07
to
Hi Jim,

Yes, that was the problem. I have got it working now. Thanks for all your
help.

Regards,
Priya

Christian Kaiser

unread,
Nov 8, 2007, 9:32:24 AM11/8/07
to
>I think the problem here is that the copy operation is scheduled on a
>background thread, and your process exits before the thread has had a
>chance to run. I >guess you need to look out for a new thread being
>created and wait for it to finish before exiting the process.

And what if the thread list differences cannot be reliably detected
(for example when having a DLL that creates threads independent of the
applicaction)? Is there no reliable way to ask the shell object? It
would mean it's pretty useless as you can never be sure all files are
packed into the ZIP file.

Periodically checking by opeining the file READWRITE, DENY_ALL does
not work - possibly the file is not opened by the thread after some
CopyHere() calls.

Do you have any idea?

Christian

Jim Barry

unread,
Nov 9, 2007, 9:37:17 AM11/9/07
to
Christian Kaiser wrote:
> And what if the thread list differences cannot be reliably detected
> (for example when having a DLL that creates threads independent of the
> applicaction)? Is there no reliable way to ask the shell object?

The correct way is to use SHSetInstanceExplorer, but not all context menu handlers conform to this protocol. There is a good discussion of the issue here:

http://www.eluent.com/runmenu.htm

CamperRon

unread,
Jul 5, 2008, 4:40:01 PM7/5/08
to

"Jim Barry" wrote:

Can you refer me to some sample code showing how to look out for a new
thread being created and waiting for it to finish? I need to detect when
CopyHere completes. Thanks.

Jim Barry

unread,
Jul 7, 2008, 6:40:03 AM7/7/08
to
CamperRon wrote:
> Can you refer me to some sample code showing how to look out for a new
> thread being created and waiting for it to finish?

No sample code, but the idea is basically this:

1) Enumerate current threads in the process using Thread32First/Thread32Next

2) Start the operation

3) Enumerate the threads again

4) Wait for any new threads using WaitForMultipleObjects

Of course, if the operation creates any new threads that don't exit, then you have a problem.

--
Jim Barry, Microsoft MVP

0 new messages