Vista API - basic IFileOperation

Share your advanced PureBasic knowledge/code with the community.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Vista API - basic IFileOperation

Post by SFSxOI »

In versions of windows prior to Vista the SHFileOperation API function was used to copy files with the SHFILEOPSTRUCT structure. There were limitations with the SHFileOperation API - you couldn't do complex calls in a single operation with it without placing multiple paths in a double null terminated buffer and then they could only be with the same operation type.

With the new Vista API IFileOperation interface you can add as many different operations as you'd like and perform them all with a single call to PerformOperations() of the IFileOperation interface. Below is the basic file copy method of the IFileOperation interface using another new Vista API called SHCreateItemFromParsingName.

IFileOperation can only be applied in a STA COM apartment. It will not work properly for MTA. For MTA apartment, SHFileOperation is still the only option.

Code: Select all

; interface parameter items beginning with 'psi' are .IShellItem - eg...psiNewlyCreated_in.IShellItem
; interface parameter items beginning with 'pUnk' are .IUnknown - eg....pUnkItems_in.IUnknown
; '_in' or 'in_' = In
; '_out' or 'out_' = Out
; LPCWSTR indicates unicode, all strings are unicode

#FOF_NOERRORUI = 512  ;don't put up error UI, other UI may be displayed, progress, confirmations
#FOF_NO_UI = #FOF_SILENT | #FOF_NOCONFIRMATION | #FOF_NOERRORUI | #FOF_NOCONFIRMMKDIR ; don't display any UI at all

Enumeration ; COINIT {
  #COINIT_MULTITHREADED     = 0
  #COINIT_APARTMENTTHREADED = 2
  #COINIT_DISABLE_OLE1DDE   = 4
  #COINIT_SPEED_OVER_MEMORY = 8
EndEnumeration

Interface IFileOperation Extends IUnknown
  Advise(pfops, pdwCookie)
  Unadvise(in_dwCookie.l)
  SetOperationFlags(in_dwOperationFlags.l)
  SetProgressMessage(in_string_LPCWSTR_pszMessage)
  SetProgressDialog(popd_in)
  SetProperties(pproparray_in)
  SetOwnerWindow(in_hwndParent.l)
  ApplyPropertiesToItem(psiItem_in)
  ApplyPropertiesToItems(punkItems_in)
  RenameItem(psiItem_in, in_string_LPCWSTR_pszNewName, pfopsItem_in_unique)
  RenameItems(pUnkItems_in, in_string_LPCWSTR_pszNewName)
  MoveItem(psiItem_in, psiDestinationFolder_in, in_unique_string_LPCWSTR_pszNewName, pfopsItem_in_unique)
  MoveItems(punkItems_in, psiDestinationFolder_in)
  CopyItem(psiItem_in, psiDestinationFolder_in, in_unique_string_LPCWSTR_pszCopyName, pfopsItem_in_unique)
  CopyItems(punkItems_in, psiDestinationFolder_in)
  DeleteItem(psiItem_in, pfopsItem_in_unique)
  DeleteItems(punkItems_in)
  NewItem(psiDestinationFolder_in, in_dwFileAttributes.l, in_unique_string_LPCWSTR_pszName, in_unique_string_LPCWSTR_pszTemplateName, pfopsItem_in_unique)
  PerformOperations()
  GetAnyOperationsAborted(pfAnyOperationsAborted_out_BOOL)
EndInterface

Procedure.l x_Ansi2Uni(string.s) ; forum code - Droopy I think
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out  
EndProcedure

Procedure SHCreateItemFromParsingName(pszSrc_Dest_Item, pbc, riid)
Libci = LoadLibrary_("shell32.dll")
  If Libci
    *SH_Create_ParsingName = GetProcAddress_(Libci, "SHCreateItemFromParsingName")
    If *SH_Create_ParsingName
    CallFunctionFast(*SH_Create_ParsingName, pszSrc_Dest_Item, pbc, riid, @psi.IShellItem)
    EndIf
  EndIf
  FreeLibrary_(Libci)
ProcedureReturn psi.IShellItem ; returns .IShellItem
EndProcedure

Procedure CopyMyFile(Source_Item.l, Dest_Item.l, New_Name.l)
; com init STA
CoInitializeEx_(#Null, #COINIT_APARTMENTTHREADED | #COINIT_DISABLE_OLE1DDE) 
  ; create the IFileOperation object   
  CoCreateInstance_(?CLSID_FileOperation, 0, 1, ?IID_IFileOperation, @pfo.IFileOperation)
  pfo\SetOperationFlags(#FOF_NOERRORUI)
  
  ; create the source IShellItem object using new Vista API 
  psiFrom.IShellItem = SHCreateItemFromParsingName(Source_Item, #Null, ?IID_IShellItem)
    
  ;create the destination IShellItem object using new Vista API
  psiTo.IShellItem = SHCreateItemFromParsingName(Dest_Item, #Null, ?IID_IShellItem)
    
  ; add the operation - add as many as you'd like
  pfo\CopyItem(psiFrom, psiTo, New_Name, #Null)
  
  If psiTo <> #Null
  psiTo\Release()
  EndIf
  
  psiFrom\Release()
  
  ; perform the operations
  pfo\PerformOperations()
  
  pfo\Release()
 
CoUninitialize_()

EndProcedure

SrcItem = x_Ansi2Uni("H:\temp\test.iso")
DesItem = x_Ansi2Uni("E:\temp")
NewName = #Null ; uncomment to NOT rename
;NewName = x_Ansi2Uni("Test1.txt") ; uncomment TO rename

CopyMyFile(SrcItem, DesItem, NewName)

DataSection
CLSID_FileOperation:
Data.l $3ad05575 
Data.w $8857,$4850
Data.b $92,$77,$11,$b8,$5b,$db,$8e,$09
IID_IFileOperation:
Data.l $947aab5f
Data.w $0a5c,$4c13
Data.b $b4,$d6,$4b,$f7,$83,$6f,$c9,$f8
IID_IShellItem:
Data.l $43826d1e
Data.w $e718,$42ee
Data.b $bc,$55,$a1,$e2,$61,$c3,$7b,$fe
EndDataSection