# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  [VB6] Use IFileOperation to replace SHFileOperation for modern Copy/Move box/prompts

## fafalone

*cFileOperation 0.1*

Display the latest version of the copy/move/delete progress dialog and the related prompts.

SHFileOperation has been superseded by IFileOperation on Windows Vista and above. At least the basic parts of it are easy to access in VB6- showing the standard Windows dialog/progress boxes to Move, Copy, or Delete files. While the class handles it, this function also requires us to bring in the IShellItem interface and its relatives into VB, so take a look at the class module code if you ever wanted to use other functions that required this.

*PROJECT UPDATE 30 Apr 2016:
Cancelling through code*

I'm updating the project to show how to cancel operations through code. While there doesn't seem to be built-in way to cancel e.g. in the middle of a large file, you can cancel between items by using the VTable-swap technique to replace the subs in the callback class with functions that can return an error in the HRESULT (I use E_ABORT). This technique has been implemented for Multiple Files copy in the demo project. Also note that the project now references the latest version of oleexp.tlb, while the previous version still used a 3.x version, so if you haven't downloaded that yet you'll either need to, or (not recommended but possible) change the references back..

*Project Update - 17 Apr 2015*
The project now includes a template class implementing the IFileOperationProgressSink, so you can get feedback while the dialog is running. Examples of what to do with that information are included, like getting the final name, or passing progress back to the application.

Note:
If there's an error in a function called from the events class, the operation will not be performed but the result will say that it was. So if everything else looks right but an operation isn't happening, check that. Took me a while to catch such a problem.

-----
From MSDN, advantages to IFileOperation:



> Use of IShellItem to identify items rather than string paths. SHFileOperation required path and destination strings to terminate in two null characters rather than the standard single null character, which itself was used to delimit multiple paths in the string. Identifying an item through IShellItem is more robust and less prone to programming errors. It also allows you to access non-file system items such as virtual folders. Multiple items in one operation can be passed as an IShellItemArray, IDataObject, or a collection accessed through IEnumShellItems rather than as a string.
>     More accurate error reporting through HRESULT values in conjunction with an API such as FormatMessage. Return codes from SHFileOperation could be misleading or inaccurate.
>     Extensibility. As a Component Object Model (COM) interface, IFileOperation can have its capabilities extended by a third-party to meet their specific needs, although this should be a very rare case. Windows provides a default implementation of IFileOperation that should meet the needs of most users.
>     Better progress feedback. Detailed operation progress, including notifications when specific operations begin and end on individual items as well as the overall progress, can be received during the operation. While SHFileOperation did provide progress UI, it was not as detailed.
>     More functionality. In addition to the copy, delete, move, and rename functionality provided by SHFileOperation, IFileOperation allows you to apply property values and create new items.
>     More control over the operation. In addition to the operation flags recognized by SHFileOperation, new flags are recognized in IFileOperation::SetOperationFlags that specify extended operation options.
>     Different operations can be performed in one call. For instance, you can move a set of files, copy others, rename a folder, and apply properties to yet another item all in one operation. SHFileOperation could only do one operationcopy, move, rename, or deleteat a time.


*Requirements*
-IFileOperation is only available on Windows Vista and higher; this project will not work on XP.
-Requires oleexp.tlb v4.0 or higher

*Usage Summary*
Using the class is fairly straight forward;
-Make sure the project's reference to oleexp.tlb is correct
-Add the class module to the project and go nuts.
-Sample project included to show how the class is called.

*The Class*
Once you've added oleexp, you're ready to start using cFileOperation. Since this calls the native methods, everything functions the same as in Explorer, including prompts about overwriting, confirmation deletion, etc. No extra code is needed to handle that.
Here are the currently supported calls:

.ParentWindow - Specify the parent window (e.g. Form1.hWnd) to keep the dialogs on top of it.
.SingleFile - For performing operations on a single file.
.SetFileList - For multiple files, specify an array containing a single full path to a file in each item.
.FileList - Retrieve the current file list.
.DestFolder - The destination folder; don't need to set for Delete.
.Flags - Set flags for the operation; uses the standard FileOperationFlags enum (see below).
.CopyFile - Copies the single file.
.CopyFiles - Copies the file list.
.MoveFile - Moves the single file.
.MoveFiles - Moves the file list.
.DeleteFile - Deletes the single file.
.DeleteFiles - Deletes the file list.

_File Operation Flags_

See MSDN Description of Flags

Can't put it much better than MSDN.




-------
All bug reports, comments, criticisms, and suggestions welcome.
PLEASE NOTE: I don't have access to multiple test systems; everything works on Win7 x64, and everything should work from Vista through 10, but please let met know if there's an issue.

--------------------------
Project update 24 Nov 2016: Updated to reference oleexp v4.0 or higher

----------


## fafalone

*Appendix*

Here's how the interface is added in as VB-accessable:



```
[
	odl,
    uuid(947aab5f-0a5c-4c13-b4d6-4bf7836fc9f8),
]
interface IFileOperation : stdole.IUnknown
{
    // 1) (Optional) Set up your event sink.
    [helpstring("Not implemented. Needs IFileOperationProgressSink class module implementation.")]
    HRESULT Advise([in] void *pfops, [out] LONG *pdwCookie);

    HRESULT Unadvise([in] LONG dwCookie);

    // 2) Set operation state
    // FOF_ flags (defined in shellapi.h) and FOFX_ flags are passed here
    // if not specified the default flags are FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR
    HRESULT SetOperationFlags([in] FILEOP_FLAGS dwOperationFlags);

    HRESULT SetProgressMessage([in] LPCWSTR pszMessage);

    HRESULT SetProgressDialog([in] IOperationsProgressDialog *popd);

    HRESULT SetProperties([in] IPropertyChangeArray  *pproparray);

    HRESULT SetOwnerWindow([in] LONG hwndOwner);

    // 3) Specify operations to take on given items.
    // FooItem takes an IShellItem*.
    // FooItems takes an IShellItem*, an IEnumShellItems* or an IDataObject*.
    HRESULT ApplyPropertiesToItem([in] IShellItem *psiItem);

    HRESULT ApplyPropertiesToItems([in] IUnknown *punkItems);

    HRESULT RenameItem(
        [in] IShellItem *psiItem,
        [in] LPCWSTR pszNewName,
        [in] void *pfopsItem); //IFileOperationProgressSink
    
    [helpstring("punkItems is either IShellItemArray, IEnumShellItems, or IDataObject")]
    HRESULT RenameItems(
        [in] IUnknown *pUnkItems,
        [in] LPCWSTR pszNewName);

    HRESULT MoveItem(
        [in] IShellItem *psiItem,
        [in] IShellItem *psiDestinationFolder,
        [in] LPCWSTR pszNewName,
        [in] void *pfopsItem); //IFileOperationProgressSink

    [helpstring("punkItems is either IShellItemArray, IEnumShellItems, or IDataObject")]
    HRESULT MoveItems(
        [in] IUnknown *punkItems,
        [in] IShellItem *psiDestinationFolder);

    HRESULT CopyItem(
        [in] IShellItem *psiItem,
        [in] IShellItem *psiDestinationFolder,
        [in] LPCWSTR pszCopyName,
        [in] void *pfopsItem);
    
    [helpstring("punkItems is either IShellItemArray, IEnumShellItems, or IDataObject")]
    HRESULT CopyItems(
        [in] IUnknown *punkItems,
        [in] IShellItem *psiDestinationFolder);

    HRESULT DeleteItem(
        [in] IShellItem *psiItem,
        [in] void *pfopsItem);
    
    [helpstring("punkItems is either IShellItemArray, IEnumShellItems, or IDataObject")]
    HRESULT DeleteItems([in] IUnknown *punkItems);

    HRESULT NewItem(
        [in] IShellItem *psiDestinationFolder,
        [in] LONG dwFileAttributes,
        [in] LPCWSTR pszName,
        [in] LPCWSTR pszTemplateName,
        [in] void *pfopsItem);

    // 4) Perform operations.
    HRESULT PerformOperations();

    // 5) Were any operations aborted?
    HRESULT GetAnyOperationsAborted([out] LONG *pfAnyOperationsAborted);
}
```

Interfaces that aren't mandatory and not yet implemented by me are left as void *, which translates to As Any in VB. Types are converted into ones that are understood by VB.

----------


## voxy

Hi fafalone,

great job, thanks a lot!

Question: Why did you change the definition of interface IDataObject in dataobj.inc? This breaks some of my code using the original olelib.tlb.

Original:
    LONG GetData(
        [in, out] FORMATETC *pformatetcIn,
        [in, out] STGMEDIUM *pmedium);
New:
    HRESULT GetData(
                   [in] FORMATETC *pformatetcIn,
                   [in,out] STGMEDIUM *pmedium);

I'm using GetData as a function, but with the new olelib.tlb it#s just a sub.

Thanks,
voxy

----------


## fafalone

I had changed it since I was having a very difficult time getting it working in VB (still can't get it).. I can switch it back, give me a couple hours.


Edit: Ok, here's it as a function again and the corresponding editing source if you wanted to compile it yourself.

If you wouldn't mind sharing how you got IDataObject working from the TLB I'd appreciate it.

I'm going to look into splitting this off... there's just so many things that would have to be duplicated though.


Edit2: Here's a better solution. I've split off all the new interfaces. The original olelib still needs to be replaced with this one; read changes.txt for more information, but it's absolutely identical to the original olelib except for having the IShellFolder/IShellFolder2/IEnumIDList interfaces corrected (they were wrong in original olelib, many things needed to be functions and not subs) and ITaskbarList coclass removed to avoid a conflict with ITaskbarList3/4 (backwards compatible tho).


tl_ole.zip is the way it was with just the IDataObject change, oleexp.zip is the new version that I'll be using henceforth in all updates and new projects.

----------


## voxy

Thanks, works great now! I will use the non-split way for now (less changes to my code). I will later let you know how IFileOperation is working (testing under Win8.1)...

Eduardo A. Morcillo describes how IDataObject can be used in VB6:
http://forums.devx.com/showthread.ph...ail-to-listbox

----------


## fafalone

You're using the original IShellFolder/IShellFolder2/IEnumIDList definitions?

----------


## voxy

> You're using the original IShellFolder/IShellFolder2/IEnumIDList definitions?


Yes, it worked with the original definitions, but it also works with your corrections.

----------


## fafalone

In case you're interested, the changes to those are based on being able to receive the HRESULT for things; like being able to use If SUCCEEDED(isdParent.EnumObjects(hWndOwner, shflag, ieidl)) Then
 instead of having to call it as a sub, and then check if IEnumIDList has been set, and similar such error checking.

----------


## voxy

I successfully renamed a file using your class under Win8.1. Very good! So I assume the other functions will work as well. Well done, thank you very much!!!

----------


## fafalone

Thanks, good to know it works on 8 too as I don't currently have the ability to test code in it.

----------


## fafalone

Project Updated with IFileOperationProgressSink
-Class implementation of IFileOperationProgressSink allows you to get feedback once the operation has started. Events are sent Pre- and Post- operation, and there's also an UpdateProgress event that allows you to pass the current progress back to your program.

----------


## voxy

Thank you!

I noted a possible issue with your sample code: On copying or moving a file to a destination where a file of the same name already exists, you get the expected overwrite prompt only the first time (within the project session). Subsequently, even when copying other files, there is no more overwrite prompt, and the target file is overwritten without asking. Apparently something is not reset...

----------


## fafalone

Since that's not something stored by the user program, I expect that it could only be cleared by Set cFO = Nothing and then Set cFO = New cFileOperation again. Is it after you check the 'keep doing this' box right?
If it's straight up overwriting things and not sending them to the recycle bin, you could specify the FOF_WANTNUKEWARNING option to get a confirm dialog.

----------


## voxy

Good idea, that works, thanks!

No, there isn't any 'keep doing this' box in that overwrite prompt.

* * *

I have another issue: When I move a non-empty folder from a portable device (a tablet in my case) to a local drive, only the folder is moved but the contents disappear to nirvana. This is 100% reproducible. There is an error message showing apparently error E_UNEXPECTED (I have it only in German, sorry):

Note that *copying* non-empty folders in any direction works just fine, and moving non-empty folders in the reverse direction also works fine, and moving empty folders in any direction is as well fine.

Note that files on portable devices need to be referenced using "USB paths" (e.g. ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_18d1&pid_4ee1#r32ca05dakr#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,14049177600}\{00000006-0001-0001-0000-000000000000}\{00000C07-0001-0001-0000-000000000000}\{00000C59-0001-0001-0000-000000000000}).

----------


## fafalone

I'll look into it further, but possibly try the FOFX_NOSKIPJUNCTIONS flag. 

I don't speak German; could you translate what the dialog is saying?

----------


## voxy

FOFX_NOSKIPJUNCTIONS did not change anything.

The message means roughly:

Because of an unexpected error you cannot move the file. If you continue to get the error you can search for this issue in Help using this error code.

Error 0x8000FFFF: Catastrophic Failure

[ ] Repeat for all current items


Thanks for looking into this.

----------


## voxy

FYI, a note independent of the above issue:

It looks like the IShellFolder2::GetDetailsEx method is not correctly defined in your oleexp.tlb.

Acc. to MS doc (http://msdn.microsoft.com/en-us/libr...s.85%29.aspx):


```
HRESULT GetDetailsEx(
  [in]   PCUITEMID_CHILD pidl,
  [in]   const SHCOLUMNID *pscid,
  [out]  VARIANT *pv
);
```

In oleexp.tlb however, the 3rd and crucial return argument is missing:


```
Function GetDetailsEx(pidl As Long, pscid As SHCOLUMNID)
```

PS: Looks like all arguments with "retval" in the ODL are not compiled correctly to TLB.

----------


## fafalone

*pv is the return value, not the HRESULT. 

For example,


```
      For ic = 0 To 3

        Call isdParent.MapColumnToSCID(ic, pst)
        DebugAppend "FillEx,GetDetailsEx(" & ic & ")=" & isdParent.GetDetailsEx(pidlRelChild, pst)
    Next ic
```

outputs

FillEx,GetDetailsEx(0)=movie1.avi
FillEx,GetDetailsEx(1)=729696256
FillEx,GetDetailsEx(2)=.avi
FillEx,GetDetailsEx(3)=8/9/2010 8:51:56 PM


In any case, things like that were why I started rewriting that and IShellFolder; it's a holdover from the original olelib shell.inc
I've really been thinking about just redefining HRESULT as a long and turning everything into a function like it should be... but it could have far reaching implications. Not sure why all HRESULT's were set up in a way that made everything a sub anyway.

----------


## voxy

Ah -- facepalm -- ok, thanks!

----------


## voxy

Back to GetDetailsEx: I wonder why you did it that way. The original HRESULT was a useful return value since it allowed to catch invalid calls to GetDetailsEx. Now, for example, when I call for PID_STG_SIZE on a folder (which is not a valid call) I get an automation error.

BAD, Error:
vReturn = isf.GetDetailsEx(pidl, SHCI)

GOOD:
  ret = isf.GetDetailsEx(pidl, SHCI, vReturn)
  If ret = S_OK Then
  ...

----------


## fafalone

I didn't intentionally do it that way I just hadn't changed it yet from the original olelib definition.

Here, now everything will return an hresult and nothing has an [out] as a retval.



```
[
	odl,
    helpstring("IShellFolder2"),
    uuid(93F2F68C-1D1B-11d3-A30E-00C04F79ABD1),
]
interface IShellFolder2 : stdole.IUnknown {

    long ParseDisplayName(
        [in] long hwndOwner,
        [in] long pbcReserved,
        [in] long lpszDisplayName,
        [in, out] long* pchEaten,
        [in, out] long* ppidl,
        [in, out] long* pdwAttributes);

    long EnumObjects(
        [in] long hwndOwner,
        [in] SHCONTF grfFlags,
        [in, out] IEnumIDList **ppenumIDList);

    long BindToObject(
        [in] long pidl,
        [in] long pbcReserved,
        [in, out] UUID *riid,
        [in, out] LPVOID ppvOut);

    long BindToStorage(
        [in] long pidl,
        [in] long pbcReserved,
        [in, out] UUID *riid,
        [out] IStorage **ppvObj);

    long CompareIDs(
        [in] long lparam,
        [in] long pidl1,
        [in] long pidl2);

    long CreateViewObject(
        [in] long hwndOwner,
        [in, out] UUID* riid,
        [out] long *ppvOut);

    long GetAttributesOf(
        [in] long cidl,
        [in, out] long* apidl,
        [in, out] long* rgfInOut);

    long GetUIObjectOf(
        [in] long hwndOwner,
        [in] long cidl,
        [in, out] long *apidl,
        [in, out] UUID  *riid,
        [in, out] long *prgfInOut,
        [out] long *ppvOut);

    long GetDisplayNameOf(
        [in] long pidl,
        [in] SHGNO_Flags uFlags,
        [in, out] STRRET* lpName);

    long SetNameOf(
        [in] long hwndOwner,
        [in] long pidl,
        [in] long lpszName,
        [in] SHGNO_Flags uFlags,
        [out] long* ppidlOut);

    // Returns the guid of the search that is to be invoked when user clicks 
    // on the search toolbar button
    long GetDefaultSearchGUID(
		[out] GUID *pguid);

    // gives an enumerator of the searches to be added to the search menu
    long EnumSearches(
		[out] IEnumExtraSearch **ppenum);
    
    long GetDefaultColumn(
		[in] LONG dwRes,
		[out] LONG *pSort,
		[out] LONG *pDisplay);

    // return SHCOLSTATE_ values
    long GetDefaultColumnState(
		[in] INT iColumn, 
		[out] SHCOLSTATE *pcsFlags);
    
    long GetDetailsEx(
		[in] LONG pidl,
		[in] SHCOLUMNID *pscid,
		[out] VARIANT *pv);
    
    long GetDetailsOf(
		[in] LONG pidl,
		[in] INT iColumn,
		[out] SHELLDETAILS *psd);
    
    long MapColumnToSCID(
		[in] INT iColumn,
		[in] SHCOLUMNID *pscid);
};
```

----------


## voxy

Thanks a lot, works fine now.

----------


## fafalone

Project has been updated showing a technique to cancel a multi-file operation between files using code; useful for example if you want to set it to silent so the regular progress dialog isn't shown and still want the user to be able to cancel; or any circumstance where you want the user/your program to cancel through code instead of relying on the cancel button on the progress dialog.

This is done with the v-table swap method to return E_ABORT as an HRESULT (anything other than S_OK cancels though).

----------


## freesix

Hi fafalone,

I'd like to know whether if I use SHFileOperation or IFileOperation for copying folders and its sub-directories in silent mode, displaying only progress (if I want...) I'm gonna get rid of app freezing (Not Responding)??

----------


## fafalone

You can use the progress sink (.Advise) for all operations and have DoEvents in the IFileOperationProgressSink_UpdateProgress sub like the sample project does for the copy multiple files part; it fires frequently enough the lag isn't really noticable unless you're doing something intense. DoEvents on a progress callback is the best you can get without multithreading or just shelling a command prompt (no way of knowing progress or many other details, plus the bad user experience).

----------


## freesix

Your code work great !!!

even if it doesn't abort the copy operation of a more than 5 GO file, ...but less than 2 GO it DOES abort perfectly !!!
it works PERFECT nevertheless !

Anyway, even SuperCopier or Windows Explorer Copy also crash sometimes if you try to cancel a big file like over 3 GO.

===

I'd like know what to do if I want to set it to silent ??  (Hide the windows progress bar)

----------


## fafalone

It accepts all the flags that SHFileOperation does + extra ones; use .Flags = IFO_SILENT
For clarity I made a new enum instead of expanding the old one; so all the new flags (and old) are in IFO_Flags

----------


## freesix

Hi fafalone.

I tried to do that but I couldn't locate where to put that *".Flags = IFO_SILENT"* to hide the progress bar.

Can you please tell me exactly what to do?? _(in which module, which function, which line)???_


I'd like to use your application in replacement of the current one for Windows;
as I tested it and realized that it's faster than windows explorer copy.  (FANTASTIC !!!) 


So, it'll save me a lot of time !!!

----------


## fafalone

If you're using the class from the demo project you set it along with all the other things you're setting for the class...
cFO.Flags = IFO_SILENT (obviously before starting the action with cFO.CopyFiles and others)...

If you're using the FileOperation object directly, it's .SetOperationFlags IFO_SILENT, before .PerformOperations

It's odd that it would be faster than Explorer since it essentially *is* Explorer's dialog.. it's the same thing Explorer calls.

----------


## freesix

Hi fafalone,

Your app was working perfectly until it crashes when trying to copy.
I even downloaded a new Zip folder to check maybe... but still behaving the same.

when I click on "Copy With Events" or "Copy" button, I got an error saying :



```
Runntime : '91'

Object Variable or Block Variable with undefined

The error is located in the below function.

Public Sub IFileOperationProgressSink_PreCopyItem(ByVal dwFlags As Long, ByVal psiItem As IShellItem, ByVal psiDestinationFolder As IShellItem, ByVal pszNewName As Long)
Dim lPtr As Long
psiDestinationFolder.GetDisplayName SIGDN_FILESYSPATH, lPtr
Debug.Print "cFileOperationProgressSink.IFileOperationProgressSink_PreCopyItem.destfolder=" & BStrFromLPWStr(lPtr, True)
DoEvents
End Sub


The debugger highlights the below line.

psiDestinationFolder.GetDisplayName SIGDN_FILESYSPATH, lPtr
```

----------


## fafalone

That's odd... you set a destination folder right? You can't copy an item without having a destination. Also I'm assuming the error number is right because 91 is 'not set', not 'undefined'. Although I can't reproduce the error by leaving the path blank on my system, or by specifying a path that doesn't exist. And what do you mean 'zip folder'... are you trying to copy out of or into a .zip?

So I'm pretty sure it's got something to do with the destination not being valid, but you can always either delete that line or do a sanity check (as any production app should do anyway; thorough error checking isn't traditionally included in demos) with If (psiDestinationFolder Is Nothing) = False Then

----------


## freesix

It's solved. Seems like it was due to my OWN mistake when entering the destination folder and was nothing to do with your code. I was entering a file name with an extension instead of a folder name.




> And what do you mean 'zip folder'... are you trying to copy out of or into a .zip?


I meant I downloaded the new zip file (*cFileOperationNew.zip*) from your first post to check... but it was also behaving the same way. Anyway, it's okay now!!!

===




> If you're using the class from the demo project you set it along with all the other things you're setting for the class...
> cFO.Flags = IFO_SILENT (obviously before starting the action with cFO.CopyFiles and others)...


it's *cFO.Flags = FOF_SILENT* instead.

===

*Question*

Is it possible to make the copy operation *PAUSE*, and obviously *CONTINUE* ???
if you may implement those two functionalities, it'll be fantastic.

Looking forward to see that !

----------


## fafalone

I'm sure I noted it somewhere... but for some compatibility reason I don't recall too well (this decision was nearly 1.5 years ago in the first version of oleexp), I left the FILEOP_Flags enum alone (the one that contains FOF_SILENT) so that SHFileOperation users didn't get confused/think they could use all the new FOFX_ flags that only apply to IFileOperation. So for IFileOperation I made a new enum, IFO_Flags, and just changed FOF_ and FOFX_ to IFO_ and IFOX_. So FOF_SILENT is the same as IFO_SILENT, and the IFO_ enum is in fact the one that applies to IFileOperation (and thus cFO.Flags). 

Pause/Continue can't really be done well here... remember this is an interface to Window's functions, it's not the VB project or typelib that contains the code that performs the operation. The only things you have to work with are the callback events, but I believe even if you put a function in that didn't return, you'd need a DoEvents somewhere to have a responsive UI to continue, and that would just let the op continue. 
What you can do is fall back to the lower level CopyFileEx and related APIs, which do offer such functionality.

----------


## freesix

Is it possible to set two destination path??


Because it's already got multiple source path.

----------


## fafalone

No, only 1 destination is allowed, although it's trivial to add another op right after the first.

----------


## freesix

Hi fafalone,

Is the *oleexp3.tlb* library will also work in Win XP, 2000, ME & 98 ??

or it's only work on Win Vista and higher???   if so, What to do to have it work on Win XP and lower?

----------


## fafalone

The TLB itself will work, but only if the interface being called is available, and few of the interfaces added by oleexp are available on XP, and none before.

----------


## freesix

Hi fafalone,

I tried to add a menu "File" and a sub menu "exit" in your App.
but curiously while a copy operation is in progress, when I click on "File" menu... the copy operation stops itself, and I have to click on the main form to make it continue !!!

I also put a "Command button" on the Form displaying a Msgbox, 
but while a copy is in progress, when I click on that Cmd button to display the Msgbox, the copy stops as well !!!

My main concern is I don't want the copy operation to stop when I click some where else.

Do I only need multi-threading ???


How can I get rid of that ???

----------


## fafalone

That's a limit of the DoEvents statement; DoEvents just processes other events, so execution won't resume if one of those other events (messagebox, etc) hasn't returned. You'd have to stick the operation in another thread to avoid that yes; the same issue would occur with any other method too; FSO, CopyFileEx.. none of them are asynchronous so all would have to be placed in another thread.

----------


## freesix

Thanks Fafalone for clarifying me.

But The problem is I'm still learning multi-threading, I mean I don't have very clear idea of what I'm doing,
and I'm not sure to make a stable application with that knowledge after a couple of weeks ONLY !!!

I'm gonna also take a look at that "VBRICHCLIENT5" too.
http://www.vbforums.com/showthread.p...-ThreadHandler

----------


## chrislong2

Hi fafalone, First - THANK YOU for this!  :Smilie: 

I am not actually using the class, but took out the necessary parts I needed to do a basic move operation and it works fine.  However, both my code and also in the class invokes an interface function like so:

In MoveFile function for instance:
iFileOp.PerformOperations

Not:
retval = iFileOp.PerformOperations

which won't work.  How do I get the return value from the PerformOperations function?  Surely there's a way as that's important to know what the error return code is!??

In other words, all the "functions" seem to be declared as Subs in the tlb and thus not returning their hresult/long.  Yet that hresult is key to knowing what went wrong.  For example, if the move didn't succeed, that hresult tells you why.

What am I missing?  Is there some other way I'm supposed to be getting the return value of those interface functions?

EDIT: I ran across your notes for the TLB and see this problem is a common one.  I don't understand why you declared them as HRESULT in the TLB if VB treats those as Subs?  I also am not clear at all how to use the SwapvTableEntry thing to get the return value.  Is there another way?  What do I need to do?

----------


## fafalone

It's declared as an HRESULT because that's the default; it's not that HRESULT by definition is a Sub, that's something that VB forces behind the scenes. If you used it in another language, it would have a return value.
Changing it to a Long to get the return value has a consequence; any interface that has a return other than HRESULT cannot be implemented in VB (Implements)- that's why oleexmpimp.tlb exists, because it contains alternate versions of interfaces that do have non-HRESULT returns. 

To get the return values, the TLB itself has to be changed. Swapping the v-table entry is only for when you're sending a return from your program, not receiving one, in an interface you're implementing yourself (e.g. IFileOperationProgressSink). 

Since it's very uncommon to implement IFileOperation yourself, I'll go ahead and change it in the next version. I'll post the next version sometime in the next few days (as there's unrelated updates for a new version that I'm in the middle of), until then, there's two options:
1) Use IFileOperationProgressSink. In each 'Post' event, e.g. PostCopyItem, and after each series of operations, FinishOperations, the HRESULT of that particular operation is returned as one of the parameters. This has the added benefit of telling you precisely which operations failed if you were working with more than 1 file.

2) Modify the TLB yourself; IFileOperation is in exp_main.odl; change HRESULT to long, then recompile. Please do not distribute a modified TLB (a program compiled with it is fine though, as the TLB shouldn't be included with a compiled app).

----------


## chrislong2

> Since it's very uncommon to implement IFileOperation yourself, I'll go ahead and change it in the next version. I'll post the next version sometime in the next few days


Thank you so much for the explanation!  :Smilie:   I don't have VC6 installed anymore so am not easily set up to create a TLB and I don't really need the callback function so I'll just wait for your version update - thank you!  :Smilie:

----------


## fafalone

The updated TLB has been posted in the main oleexp thread.

----------


## chrislong2

Thanks so much fafalone!!  :Smilie:   :Smilie:

----------

