yoy.be "Why-o-Why"

Delay a file copy until the next reboot

2005-10-21 10:43  i327  delphi  [permalink]

I have been looking for a while how to 'delay' a file-copy until the next reboot.
In searching the [[Microsoft Windows]] documentation, I have found the SetupApi functions, and they appear to be just what I need to make it work. Ported to Delphi, the code looks a little like this. The code I first had had some more exception-raising code in stead of a return value of boolean here, but feel free to build it up some more. I also provide a callBack routine that does a little more than absolutely neccessary, but that might come in handy of you want to do more with this single FileQueue. Note that I chose not to use the default callback routine here, which would handle all events with the proper dialogs and UI things.

interface uses Windows; type HSPFILEQ = THandle; function SetupOpenFileQueue: HSPFILEQ stdcall; function SetupCloseFileQueue(QueueHandle: HSPFILEQ): BOOL stdcall; function SetupQueueCopy(QueueHandle: HSPFILEQ; SourceRootPath: PChar; SourcePath: PChar; //optional SourceFilename: PChar; SourceDescription: PChar; SourceTagfile: PChar; //optional TargetDirectory: PChar; //optional TargetFileName: PChar; //optional CopyStyle: DWORD ) : BOOL stdcall; type PSP_FILE_CALLBACK_A=function(CONTEXT:pointer;NOTIFICATION:cardinal;PARAM1:cardinal;PARAM2:cardinal):cardinal stdcall; function SetupCommitFileQueue(Owner: HWND; QueueHandle: HSPFILEQ; //optional MsgHandler: PSP_FILE_CALLBACK_A; Context: pointer): BOOL stdcall; implementation function SetupOpenFileQueue; external 'setupapi.dll'; function SetupCloseFileQueue; external 'setupapi.dll'; function SetupQueueCopy; external 'setupapi.dll' name 'SetupQueueCopyA'; function SetupCommitFileQueue; external 'setupapi.dll' name 'SetupCommitFileQueue'; // CopyStyle values for copy and queue-related APIs const SP_COPY_DELETESOURCE = $0000001; // delete source file on successful copy SP_COPY_REPLACEONLY = $0000002; // copy only if target file already present SP_COPY_NEWER = $0000004; // copy only if source newer than or same as target SP_COPY_NEWER_OR_SAME = SP_COPY_NEWER; SP_COPY_NOOVERWRITE = $0000008; // copy only if target doesn't exist SP_COPY_NODECOMP = $0000010; // don't decompress source file while copying SP_COPY_LANGUAGEAWARE = $0000020; // don't overwrite file of different language SP_COPY_SOURCE_ABSOLUTE = $0000040; // SourceFile is a full source path SP_COPY_SOURCEPATH_ABSOLUTE = $0000080; // SourcePathRoot is the full path SP_COPY_IN_USE_NEEDS_REBOOT = $0000100; // System needs reboot if file in use SP_COPY_FORCE_IN_USE = $0000200; // Force target-in-use behavior SP_COPY_NOSKIP = $0000400; // Skip is disallowed for this file or section SP_FLAG_CABINETCONTINUATION = $0000800; // Used with need media notification SP_COPY_FORCE_NOOVERWRITE = $0001000; // like NOOVERWRITE but no callback nofitication SP_COPY_FORCE_NEWER = $0002000; // like NEWER but no callback nofitication SP_COPY_WARNIFSKIP = $0004000; // system critical file: warn if user tries to skip SP_COPY_NOBROWSE = $0008000; // Browsing is disallowed for this file or section SP_COPY_NEWER_ONLY = $0010000; // copy only if source file newer than target SP_COPY_SOURCE_SIS_MASTER = $0020000; // source is single-instance store master SP_COPY_OEMINF_CATALOG_ONLY = $0040000; // (SetupCopyOEMInf only) don't copy INF--just catalog SP_COPY_REPLACE_BOOT_FILE = $0080000; // file must be present upon reboot (i.e., it's needed by the loader); this flag implies a reboot SP_COPY_NOPRUNE = $0100000; {// never prune this file} // Operation/queue start/end notification. These are ordinal values. const SPFILENOTIFY_STARTQUEUE = $00000001; SPFILENOTIFY_ENDQUEUE = $00000002; SPFILENOTIFY_STARTSUBQUEUE = $00000003; SPFILENOTIFY_ENDSUBQUEUE = $00000004; SPFILENOTIFY_STARTDELETE = $00000005; SPFILENOTIFY_ENDDELETE = $00000006; SPFILENOTIFY_DELETEERROR = $00000007; SPFILENOTIFY_STARTRENAME = $00000008; SPFILENOTIFY_ENDRENAME = $00000009; SPFILENOTIFY_RENAMEERROR = $0000000a; SPFILENOTIFY_STARTCOPY = $0000000b; SPFILENOTIFY_ENDCOPY = $0000000c; SPFILENOTIFY_COPYERROR = $0000000d; SPFILENOTIFY_NEEDMEDIA = $0000000e; SPFILENOTIFY_QUEUESCAN = $0000000; // These are used with SetupIterateCabinet(). SPFILENOTIFY_CABINETINFO = $00000010; SPFILENOTIFY_FILEINCABINET = $00000011; SPFILENOTIFY_NEEDNEWCABINET = $00000012; SPFILENOTIFY_FILEEXTRACTED = $00000013; SPFILENOTIFY_FILEOPDELAYED = $00000014; // These are used for backup operations SPFILENOTIFY_STARTBACKUP = $00000015; SPFILENOTIFY_BACKUPERROR = $00000016; SPFILENOTIFY_ENDBACKUP = $00000017; // Extended notification for SetupScanFileQueue(Flags=SPQ_SCAN_USE_CALLBACKEX) SPFILENOTIFY_QUEUESCAN_EX = $00000018; SPFILENOTIFY_STARTREGISTRATION = $00000019; SPFILENOTIFY_ENDREGISTRATION = $00000020; //IFDEF _SETUPAPI_VER >= $0501 // Extended notification for SetupScanFileQueue(Flags=SPQ_SCAN_USE_CALLBACK_SIGNERINFO) SPFILENOTIFY_QUEUESCAN_SIGNERINFO = $00000040; //ENDIF // Copy notification. These are bit flags that may be combined. SPFILENOTIFY_LANGMISMATCH = $00010000; SPFILENOTIFY_TARGETEXISTS = $00020000; SPFILENOTIFY_TARGETNEWER = $00040000; // File operation codes and callback outcomes. const FILEOP_COPY = 0; FILEOP_RENAME = 1; FILEOP_DELETE = 2; FILEOP_BACKUP = 3; FILEOP_ABORT = 0; FILEOP_DOIT = 1; FILEOP_SKIP = 2; FILEOP_RETRY = FILEOP_DOIT; FILEOP_NEWPATH = 4; //callback context type TCallBackRaiseError=( cbrNone, cbrCopyError, cbrSourceNotFound, cbrDeleteError, cbrRenameError); TCallBackContext=record MediaNeededOnce,DelaySuccess:boolean; RaiseError:TCallBackRaiseError; end; function QueueFileCopyCallBack(Context: pointer; Notification: cardinal; Param1: cardinal; Param2: cardinal): cardinal stdcall; var ctx:^TCallBAckContext; begin ctx:=Context; case Notification of SPFILENOTIFY_DELETEERROR: begin ctx.RaiseError:=cbrDeleteError; Result:=FILEOP_ABORT; end; SPFILENOTIFY_RENAMEERROR: begin ctx.RaiseError:=cbrRenameError; Result:=FILEOP_ABORT; end; SPFILENOTIFY_COPYERROR: begin ctx.RaiseError:=cbrCopyError; Result:=FILEOP_ABORT; end; SPFILENOTIFY_NEEDMEDIA: begin if ctx.MediaNeededOnce then begin ctx.RaiseError:=cbrSourceNotFound; Result:=FILEOP_ABORT; end else begin ctx.MediaNeededOnce:=true; Result:=FILEOP_DOIT; end; end; SPFILENOTIFY_FILEOPDELAYED: begin ctx.DelaySuccess:=true; Result:=FILEOP_DOIT; end; else Result:=FILEOP_DOIT;//default: continue end; end; function QueueFileCopy(SrcPath,SrcFile,DestPath,DestFile:string; DeleteSource:boolean):boolean; var fq:HSPFILEQ; c:cardinal; ctx:TCallBackContext; begin //init callback context ctx.MediaNeededOnce:=false; ctx.DelaySuccess:=false; ctx.RaiseError:=cbrNone; fq:=SetupOpenFileQueue; c:= //SP_COPY_REPLACEONLY or SP_COPY_SOURCE_ABSOLUTE or //SP_COPY_FORCE_IN_USE or //SP_COPY_IN_USE_NEEDS_REBOOT or SP_COPY_NOSKIP; if DeleteSource then c:=c or SP_COPY_DELETESOURCE; if not(SetupQueueCopy( fq, PChar(SrcPath), nil, PChar(SrcFile), nil, nil, PChar(DestPath), PChar(DestFile), c ) ) then RaiseLastOSError; SetupCommitFileQueue(GetDesktopWindow,fq,@QueueFileCopyCallBack,@ctx);<BR>  //returns false on abort! don't RaiseLastOSError;<BR>  SetupCloseFileQueue(fq); Result:=ctx.RaiseError=cbrNone; end;

 


twitter reddit linkedin facebook