News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Implementation of the COM interface FileOperation

Started by jorgon, February 19, 2025, 11:39:35 AM

Previous topic - Next topic

jorgon

It turns out this is easier to code in assembler than in "C" because everything is obvious and there are no compiler quirks to be circumvented.  The attached asm file of 7KB (renamed FileOpsDelete.txt so it can be uploaded to the forum) contains all the code and there are no includes! When assembled and linked, this simple program deletes the file c:\temp\FileOpsDelete.txt. Obviously you can change the filename to suit.  The API CoCreateInstance is used to start the process. The FileOperation interface can be used to copy, move, create and delete shell items, so we use iShellItem to make a shell item from the file.

[EDIT1] Sorry I had to amend the file slightly - see the call to Release
[EDIT2] Where the exe has no message queue, COM should be initialised using COINIT_MULTITHREADED
[EDIT3] I forgot to say that I was looking for a way to send files to the recycle bin on delete, and although this can be done using SHFileOperation, I had found that to be rather flaky - very sensitive to unusual (but valid) filenames.  The SDK says that these days you should use the FileOperation interface instead, and I am hoping it will be more robust.

jorgon

In practice I found that neither SHFileOperation, nor its counterpart the COM interface FileOperation, worked properly from the main thread in my exe once that main thread had entered its message loop.  I have no idea why that is the case, bearing in mind the message loop is bog standard coding and all messages not responded to are sent to DefWindowProcW. I do use other COM things in the main thread and for that purpose it calls CoInitializeEx with flags of 6, that is COINIT_APARTMENTTHREADED (2) + COINIT_DISABLE_OLE1DDE (4) causing it to load a lot of stuff.  Maybe there is some conflict somewhere.
 
But once I put SHFileOperation into its own thread it worked fine - no objections to file names any more.  I noted in the debugger that SHFileOperation called CoInitializeEx with the same flags as my main thread was using, so no conflict there.  Also the COM interface FileOperation worked well from its own thread, with of course CoInitializeEx being called by that thread and CoUnitialize being called by that thread before exiting. 

Anyway I would say if you have trouble with these functions, try them in their own thread. It's very easy to do.  Here is some code (this assumes you have already populated SHFILEOPSTRUCTW):
(earlier code goes here)
PUSH ADDR ThreadId                       ;throw away value
PUSH 0,0
PUSH ADDR MAINTEMP1
PUSH 0,0
CALL CreateThread                        ;thread handle returns in eax
INVOKE WaitForSingleObject,EAX,10000     ;wait 10 seconds for the new thread to finish
CMP EAX,102h          ;see if timeout
JZ >L26                                  ;yes so abort all
MOV EAX,[MAINTEMP1_EXITCODE]
OR EAX,EAX ;see if succeeded, that is S_OK
JZ >L30 ;yes
L26:                                     ;no
(later code goes here)
;
MAINTEMP1:                               ;new thread starts here
INVOKE SHFileOperationW,ADDR SHFILEOPSTRUCTW
MOV [MAINTEMP1_EXITCODE],EAX          ;using this was more reliable than GetExitCodeThread
INVOKE ExitThread,0
;