Как поймать отменить копирование файла проводником?
От: xteam777  
Дата: 05.10.16 13:45
Оценка:
Перехватываю API функции копирования/перемещения использую Detours. При тестах на своем приложении хуки срабатывают. А при инжекте DLL (DLL успешно подгружается и выгружается) в эксплорер, систем, или вообще во все процессы, не срабатывает. Видимо эксплорер использует какие-то другие функции. Подскажите куда копать.
Единственное, удалось перехватить копирование, поставив хуки на методы интерфейса IFileOperation, но он срабатывает до диалога замены файла (где написано файл существует. заменить?), а мне нужно чтобы срабатывало после него.

Код Dll:
library thread_splice_lib;

uses
  Windows,
  System.SysUtils,
  ActiveX,
  ShlObj,
  ShellApi,
  CPUID in '..\..\..\delphi-detours-library-master\Source\CPUID.pas',
  DDetours in '..\..\..\delphi-detours-library-master\Source\DDetours.pas',
  InstDecode in '..\..\..\delphi-detours-library-master\Source\InstDecode.pas';

{$R *.res}

type
  _tagpropertykey = packed record
    fmtid: TGUID;
    pid: DWORD;
  end;
  PROPERTYKEY = _tagpropertykey;

   //----------------------------------------------
   // IShellItem interface declaration
   //----------------------------------------------

  IShellItem = interface(IUnknown)
    ['{43826d1e-e718-42ee-bc55-a1e261c37bfe}']
    function BindToHandler(const pbc: IBindCtx; const bhid: TGUID;
      const riid: TIID; out ppv): HResult; stdcall;
    function GetParent(var ppsi: IShellItem): HResult; stdcall;
    function GetDisplayName(sigdnName: DWORD; var ppszName: LPWSTR): HResult; stdcall;
    function GetAttributes(sfgaoMask: DWORD; var psfgaoAttribs: DWORD): HResult; stdcall;
    function Compare(const psi: IShellItem; hint: DWORD;
      var piOrder: Integer): HResult; stdcall;
  end;

   //----------------------------------------------
   // ISHellEnumItems interface declaration
   //----------------------------------------------

  IEnumShellItems = interface(IUnknown)
    ['{70629033-e363-4a28-a567-0db78006e6d7}']
    function Next(celt: ULONG; out rgelt; pceltFetched: PLongint): HResult; stdcall;
    function Skip(celt: ULONG): HResult; stdcall;
    function Reset: HResult; stdcall;
    function Clone(out ppenum: IEnumShellItems): HResult; stdcall;
  end;

   //----------------------------------------------
   // IShellItemArray interface declaration
   //----------------------------------------------

  IShellItemArray = interface(IUnknown)
    ['{b63ea76d-1f85-456f-a19c-48159efa858b}']
    function BindToHandler(const pbc: IBindCtx; const rbhid: TGUID;
      const riid: TIID; out ppvOut): HResult; stdcall;
    function GetPropertyStore(flags: DWORD; const riid: TIID; out ppv): HResult; stdcall;
    function GetPropertyDescriptionList(const keyType: PropertyKey;
      const riid: TIID; out ppv): HResult; stdcall;
    function GetAttributes(dwAttribFlags: DWORD; sfgaoMask: DWORD;
      var psfgaoAttribs: DWORD): HResult; stdcall;
    function GetCount(var pdwNumItems: DWORD): HResult; stdcall;
    function GetItemAt(dwIndex: DWORD; var ppsi: IShellItem): HResult; stdcall;
    function EnumItems(var ppenumShellItems:    IEnumShellItems): HResult; stdcall;
  end;

   //----------------------------------------------
   // SHCreateShellItemArrayFromDataObject declaration
   //----------------------------------------------

   TSHCreateShellItemArrayFromDataObject = function(pdo: IDataObject;
      const riid: TGUID; ppv: Pointer): HRESULT; StdCall;

   //----------------------------------------------
   // Operations done by IFileOperation
   //----------------------------------------------

   TFileOperation = (opCopy, opMove, opDelete, opRename);

var
   //---------------------------------------------------------------------------
   // Hook's nextProcs
   //---------------------------------------------------------------------------

   CoCreateInstance_np: function(const clsid: TCLSID; unkOuter: Pointer;
     dwClsContext: Longint; const iid: TIID; pv: Pointer): HResult; stdcall;

   CopyItems_np: function( p: POinter; punkItems: IUnknown;
      psiDestinationFolder: IShellItem ): HRESULT; stdcall;

   CopyItem_np: function( p: POinter; psiitem: IShellItem;
      psiDestinationFolder: IShellItem; pszCopyName: LPCWSTR;
      pfopsItem: Pointer ): HRESULT; stdcall;

   DeleteItem_np: function( p: POinter; psiItem: IShellItem; pfopsItem:
      Pointer ): HRESULT; stdcall;

   DeleteItems_np: function( p: POinter; punkItems: IUnknown ): HRESULT; stdcall;

   MoveItems_np: function( p: POinter; punkItems: IUnknown;
      psiDestinationFolder: IShellItem ): HRESULT; stdcall;

   MoveItem_np: function( p: POinter; psiitem: IShellItem;
      psiDestinationFolder: IShellItem; pszCopyName: LPCWSTR;
      pfopsItem: Pointer ): HRESULT; stdcall;

   RenameItem_np: function( p: Pointer; psiItem: IShellItem; pszNewName:
      LPCWSTR; pfopsItem: Pointer ): HRESULT; stdcall;

   RenameItems_np: function( p: Pointer; punkItems: IUnknown; pszNewName:
      LPCWSTR ): HRESULT; stdcall;

const
   IID_ShellItemArray : TGUID = '{b63ea76d-1f85-456f-a19c-48159efa858b}';
   IID_DataObject: TGUID = '{0000010E-0000-0000-C000-000000000046}';
   SIGDN_FILESYSPATH     = $80058000;
   SIGDN_NORMALDISPLAY   = $00000000;

//----------------------------------------------
// Little function for string to PWideChar convertion
//----------------------------------------------

function PWideToString( wide: PWideChar ): string;
var
   pAtual: Pointer;
begin
   pAtual := wide;
   Result := '';

   // A PWideChar ends when a #0#0 is found. 2 bytes, then we can
 // typecast for a Word comparasion

   while PWord( pAtual )^ <> 0 do
   begin

      // We use only the first byte. Jump 2.
      Result := Result + Chr( PByte( pAtual )^ );
      pAtual := Pointer( Integer( pAtual ) + 2 );
   end;
end;

//----------------------------------------------
// Convert and returns as true, to be used on one line IF
//----------------------------------------------


function ConvertWtoS( wide: PWideChar; var output: string ): Boolean;
begin
   Result := True;
   output := PWideToString( wide );
end;

//----------------------------------------------
// All one item operation will step here.
//----------------------------------------------

function canPerform_ShellItem( item, dest: IShellItem; secParam: LPCWSTR;
   op: TFileOperation ): Boolean;
var
   itemPath, destPath: PWideChar;
   sItemPath, sDestPath: string;
begin
   Result := True;

   if Item.GetDisplayName( SIGDN_FILESYSPATH, itemPath ) = S_OK then
   begin
      // Extract the origin file path
      sItemPath := PWideToString( itemPath );

      // For deletion, there's no need for destiny
      if op <> opDelete then
      begin
         // There's destiny
         if ( dest <> nil ) and (dest.GetDisplayName(
            SIGDN_FILESYSPATH, destPath ) = S_OK) then

              // Transforms the string including a path delimiter
              sDestPath := IncludeTrailingPathDelimiter( PWideToString( destPath ) )
         else sDestPath := IncludeTrailingPathDelimiter( ExtractFilePath( sItemPath ) );


         // If there's no destiny, we'll use the origin
         if secParam = nil then
              sDestPath := sDestPath + ExtractFileName( sItemPath )
         else sDestPath := sDestPath + PWideToString( secParam );
      end;

      case op of
         opCopy:
            // Shows a messageBox
            Result := MessageBoxA( 0, PAnsiChar( 'Copying from: ' + sItemPath + #13#10 + 'to: ' + sDestPath ),'Allow?', MB_YESNO ) = ID_YES;

         opMove  :
            // Shows a messageBox
            Result := MessageBoxA( 0, PAnsiChar( 'Moving from: ' + sItemPath + #13#10 + 'to: ' + sDestPath ),'Allow?', MB_YESNO ) = ID_YES;

         opDelete:
            // Shows a messageBox
            Result := MessageBoxA( 0, PAnsiChar( 'Deleteing file: ' + sItemPath ),'Allow?', MB_YESNO ) = ID_YES;

         opRename:
            // Shows a messageBox
            Result := MessageBoxA( 0, PAnsiChar( 'Renaming from: ' + sItemPath + #13#10 + 'to: ' + sDestPath ),'Allow?', MB_YESNO ) = ID_YES;

      end;
   end;
end;

//-------------------------------------
// Many items performing method
//-------------------------------------

function canPerform_ShellItemArray( itemArr: IShellItemArray; dest: IShellItem;
   op: TFileOperation ): Boolean;
var
   nTotal: Cardinal;
   nAux: Integer;
   shellItem: IShellItem;
begin
   Result := True;

   // Is a valid array?
   if itemArr.GetCount( nTotal ) = S_OK then
   begin
      for nAux := 0 to nTotal -1 do
      begin

         // Extract the current item
         if itemArr.GetItemAt( nAux, shellItem ) = S_OK then
         begin
            // check if the operation can be performed
            Result := Result and canPerform_ShellItem( shellItem, dest, nil, op );

            // In abortion case, break
            if not Result then
               Break;
         end;
      end;
   end;
end;

//-------------------------------------
// Many items performing method, trough IDataObject
//-------------------------------------

function canPerform_DataObject( dataObject: IDataObject; dest: IShellItem;
   op: TFileOperation ): Boolean;
var
   SHConverteFromData: TSHCreateShellItemArrayFromDataObject;
   shellItemArr: IShellItemArray;
begin
   Result := True;

   // Windows Vista has implemented a function to convert an
 // IDataObject to ISHellItemArray. We'll use it.

   @SHConverteFromData := GetProcAddress( GetModuleHandle('shell32.dll'),
      'SHCreateShellItemArrayFromDataObject' );

   // Functoun found, use it.
   if (@SHConverteFromData <> nil) and ( SHConverteFromData(
      dataObject, IID_ShellItemArray, @shellItemArr ) = S_OK ) then
   begin

      // Perform the item now.
      Result := canPerform_ShellItemArray( shellItemArr, dest, op );
   end;
end;

//------------------------------------
// Many items performing method, trough punkData
//------------------------------------

function canPerform_PunkItem( punkItems: IUnknown; dest: IShellItem;
   op: TFileOperation ): Boolean;
var
   shellItemArr: IShellItemArray;
   dataObject: IDataObject;
begin
   Result := True;

   if punkItems.QueryInterface( IID_ShellItemArray, shellItemArr ) = S_OK then

      // If we have a ShellItemArr, check directly
      result := canPerform_ShellItemArray( shellItemArr, dest, op )


   // In case of IDataObject, convert to IShellItemArray
   else if punkItems.QueryInterface( IID_DataObject, dataObject ) = S_OK then

      result := canPerform_DataObject( dataObject, dest, op );
end;

function IsWindows64: Boolean;
type
  TIsWow64Process = function(AHandle:THandle; var AIsWow64: BOOL): BOOL; stdcall;
var
  vKernel32Handle: DWORD;
  vIsWow64Process: TIsWow64Process;
  vIsWow64       : BOOL;
begin
  // 1) assume that we are not running under Windows 64 bit
  Result := False;

  // 2) Load kernel32.dll library
  vKernel32Handle := LoadLibrary('kernel32.dll');
  if (vKernel32Handle = 0) then Exit; // Loading kernel32.dll was failed, just return

  try

    // 3) Load windows api IsWow64Process
    @vIsWow64Process := GetProcAddress(vKernel32Handle, 'IsWow64Process');
    if not Assigned(vIsWow64Process) then Exit; // Loading IsWow64Process was failed, just return

    // 4) Execute IsWow64Process against our own process
    vIsWow64 := False;
    if (vIsWow64Process(GetCurrentProcess, vIsWow64)) then
      Result := vIsWow64;   // use the returned value

  finally
    FreeLibrary(vKernel32Handle);  // unload the library
  end;
end;

//------------------------------------------
// Given an interface pointer, find out the position by it's index
//------------------------------------------

function GetInterfaceMethod(const intf; methodIndex: dword) : pointer;
begin
  if IsWindows64 then
    result := pointer(pointer(DWORD_PTR(pointer(intf)^) + methodIndex * {sizeOf(cardinal)} 8)^)
  else
    result := pointer(pointer(DWORD(pointer(intf)^) + methodIndex * {sizeOf(cardinal)} 4)^);
end;

//-----------------------------
// DeleteItems callBack
//-----------------------------

function DeleteItems_cb( p: POinter; punkItems: IUnknown ): HRESULT; stdcall;
begin
   if canPerform_PunkItem( punkItems, nil, opDelete ) then
      Result := deleteItems_np( p, punkItems )

   else Result := E_ABORT;
end;




//-----------------------------
// DeleteItem callBack
//-----------------------------


function DeleteItem_cb( p: POinter; psiItem: IShellItem;
   pfopsItem: Pointer ): HRESULT; stdcall;
begin
   if canPerform_ShellItem( psiItem, nil, nil, opDelete ) then
      Result := deleteItem_np( p, psiItem, pfopsItem )

   else Result := E_ABORT;
end;




//-----------------------------
// CopyItem callBack
//-----------------------------


function CopyItem_cb( p: POinter; psiItem: IShellItem; psiDestinationFolder:
   IShellItem; pszCopyName: LPCWSTR; pfopsItem: Pointer ): HRESULT; stdcall;
begin
   if canPerform_ShellItem( psiItem, psiDestinationFolder, pszCopyName, opCopy ) then
      Result := CopyItem_np( p, psiItem, psiDestinationFolder, pszCopyName,
         pfopsItem )

   else Result := E_ABORT;
end;




//-----------------------------
// CopyItems callBack
//-----------------------------


function CopyItems_cb( p: POinter; punkItems: IUnknown; psiDestinationFolder:
   IShellItem ): HRESULT; stdcall;
begin
   if canPerform_PunkItem( punkItems, psiDestinationFolder, opCopy ) then
      Result := CopyItems_np( p, punkItems, psiDestinationFolder )

   else Result := E_ABORT;
end;




//-----------------------------
// MoveItem callBack
//-----------------------------


function MoveItem_cb( p: POinter; psiItem: IShellItem; psiDestinationFolder:
   IShellItem; pszCopyName: LPCWSTR; pfopsItem: Pointer ): HRESULT; stdcall;
begin
   if canPerform_ShellItem( psiItem, psiDestinationFolder, pszCopyName, opMove ) then
      Result := MoveItem_np( p, psiItem, psiDestinationFolder, pszCopyName,
         pfopsItem )

   else Result := E_ABORT;
end;




//-----------------------------
// MoveItems callBack
//-----------------------------


function MoveItems_cb( p: POinter; punkItems: IUnknown; psiDestinationFolder:
   IShellItem ): HRESULT; stdcall;
begin
   if canPerform_PunkItem( punkItems, psiDestinationFolder, opMove ) then
      Result := MoveItems_np( p, punkItems, psiDestinationFolder )

   else Result := E_ABORT;
end;




//-----------------------------
// RenameItem callBack
//-----------------------------


function RenameItem_cb( p: Pointer; psiItem: IShellItem; pszNewName:
   LPCWSTR; pfopsItem: Pointer ): HRESULT; stdcall;
begin
   if canPerform_ShellItem( psiItem, nil, pszNewName, opRename ) then
      Result := RenameItem_np( p, psiItem, pszNewName, pfopsItem )

   else Result := E_ABORT;
end;




//-----------------------------
// RenameItems callBack
//-----------------------------


function RenameItems_cb( p: Pointer; punkItems: IUnknown; pszNewName:
   LPCWSTR ): HRESULT; stdcall;
begin
   if canPerform_PunkItem( punkItems, nil, opRename ) then
      Result := RenameItems_np( p, punkItems, pszNewName )

   else Result := E_ABORT;
end;




//-----------------------------
// coCreateInstance callBack
//-----------------------------


function CoCreateInstance_cb(const clsid: TCLSID; unkOuter: Pointer;
  dwClsContext: Longint; const iid: TIID; pv: Pointer): HResult; stdcall;
const
   IFileOperation_GUID = '3AD05575-8857-4850-9277-11B85BDB8E09';

   procedure HookFunctionIndex( index: Integer; CallBack: Pointer; var NextProc: Pointer );
   begin
      // Hook if it is not yet hooked
      if NextProc = nil then
         //HookCode( GetInterfaceMethod( pv^, index ), CallBack, NextProc );
         NextProc := InterceptCreate(GetInterfaceMethod( pv^, index ), CallBack);
   end;

begin
   // Call the original API to get it's instance pointer
   Result := CoCreateInstance_np( clsid, unkOuter, dwClsContext, iid, pv );

   // Check IFileOperation GUID
   if pos( IFIleOperation_GUID, GUIDToString(clsid) ) <> 0 then
   begin
      //------------------------------------
      // Hook each function of our interface
      //------------------------------------

      HookFunctionIndex( 12, @RenameItem_Cb , @RenameItem_np  );
      HookFunctionIndex( 13, @RenameItems_Cb, @RenameItems_np );
      HookFunctionIndex( 14, @MoveItem_Cb   , @MoveItem_np    );
      HookFunctionIndex( 15, @MoveItems_cb  , @MoveItems_np   );
      HookFunctionIndex( 16, @CopyItem_cb   , @CopyItem_np    );
      HookFunctionIndex( 17, @CopyItems_cb  , @CopyItems_np   );
      HookFunctionIndex( 18, @DeleteItem_cb , @DeleteItem_np  );
      HookFunctionIndex( 19, @DeleteItems_cb, @DeleteItems_np );
   end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

var
  CopyFileA_np: function(lpExistingFileName, lpNewFileName: LPCSTR; bFailIfExists: BOOL): BOOL; stdcall;
  CopyFileW_np: function(lpExistingFileName, lpNewFileName: LPCWSTR; bFailIfExists: BOOL): BOOL; stdcall;
  CopyFileExA_np: function(lpExistingFileName, lpNewFileName: LPWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD): BOOL; stdcall;
  CopyFileExW_np: function(lpExistingFileName, lpNewFileName: LPCWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD): BOOL; stdcall;
  ReplaceFileA_np: function(lpReplacedFileName, lpReplacementFileName, lpBackupFileName: LPCSTR; dwReplaceFlags: DWORD; lpExclude, lpReserved: Pointer): BOOL; stdcall;
  ReplaceFileW_np: function(lpReplacedFileName, lpReplacementFileName, lpBackupFileName: LPCWSTR; dwReplaceFlags: DWORD; lpExclude, lpReserved: Pointer): BOOL; stdcall;
  CopyFileTransactedA_np: function(lpExistingFileName, lpNewFileName: LPSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD; hTransaction: THandle): BOOL; stdcall;
  CopyFileTransactedW_np: function(lpExistingFileName, lpNewFileName: LPWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD; hTransaction: THandle): BOOL; stdcall;
  MoveFileA_np: function(lpExistingFileName, lpNewFileName: LPCSTR): BOOL; stdcall;
  MoveFileW_np: function(lpExistingFileName, lpNewFileName: LPCWSTR): BOOL; stdcall;
  MoveFileExA_np: function(lpExistingFileName, lpNewFileName: LPCSTR; dwFlags: DWORD): BOOL; stdcall;
  MoveFileExW_np: function(lpExistingFileName, lpNewFileName: LPCWSTR; dwFlags: DWORD): BOOL; stdcall;
  MoveFileWithProgressA_np: function (lpExistingFileName, lpNewFileName: LPCSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; dwFlags: DWORD): BOOL; stdcall;
  MoveFileWithProgressW_np: function (lpExistingFileName, lpNewFileName: LPCWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; dwFlags: DWORD): BOOL; stdcall;
  SHFileOperationA_np: function(const lpFileOp: TSHFileOpStructA): Integer; stdcall;
  SHFileOperationW_np: function(const lpFileOp: TSHFileOpStructW): Integer; stdcall;

function SHFileOperationA_cb(const lpFileOp: TSHFileOpStructA): Integer; stdcall;
begin
  if MessageBoxA(0, PAnsiChar('SHFileOperationA'), 'Allow?', MB_YESNO) = ID_YES then
    Result := SHFileOperationA_np(lpFileOp);
end;

function SHFileOperationW_cb(const lpFileOp: TSHFileOpStructW): Integer; stdcall;
begin
  if MessageBoxA(0, PAnsiChar('SHFileOperationW'), 'Allow?', MB_YESNO) = ID_YES then
    Result := SHFileOperationW_np(lpFileOp);
end;

function MoveFileWithProgressA_cb(lpExistingFileName, lpNewFileName: LPCSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; dwFlags: DWORD): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('MoveFileWithProgressA from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := MoveFileWithProgressA_np(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags);
end;

function MoveFileWithProgressW_cb(lpExistingFileName, lpNewFileName: LPCWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; dwFlags: DWORD): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('MoveFileWithProgressW from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := MoveFileWithProgressW_np(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags);
end;

function CopyFileA_cb(lpExistingFileName, lpNewFileName: LPCSTR; bFailIfExists: BOOL): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('CopyFileA from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := CopyFileA_np(lpExistingFileName, lpNewFileName, bFailIfExists);
end;

function CopyFileW_cb(lpExistingFileName, lpNewFileName: LPCWSTR; bFailIfExists: BOOL): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('CopyFileW from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := CopyFileW_np(lpExistingFileName, lpNewFileName, bFailIfExists);
end;

function CopyFileExA_cb(lpExistingFileName, lpNewFileName: LPWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('CopyFileExA from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := CopyFileExA_np(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags);
end;

function CopyFileExW_cb(lpExistingFileName, lpNewFileName: LPCWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('CopyFileExW from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := CopyFileExA_np(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags);
end;

function ReplaceFileA_cb(lpReplacedFileName, lpReplacementFileName, lpBackupFileName: LPCSTR; dwReplaceFlags: DWORD; lpExclude, lpReserved: Pointer): BOOL; stdcall;
begin
  Result := MessageBoxA(0, PAnsiChar('ReplaceFileA from: ' + lpReplacedFileName + #13#10 + 'to: ' + lpReplacementFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := ReplaceFileA_np(lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved);
end;

function ReplaceFileW_cb(lpReplacedFileName, lpReplacementFileName, lpBackupFileName: LPCWSTR; dwReplaceFlags: DWORD; lpExclude, lpReserved: Pointer): BOOL; stdcall;
begin
  Result := MessageBoxA(0, PAnsiChar('ReplaceFileW from: ' + lpReplacedFileName + #13#10 + 'to: ' + lpReplacementFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := ReplaceFileW_np(lpReplacedFileName, lpReplacementFileName, lpBackupFileName, dwReplaceFlags, lpExclude, lpReserved);
end;

function CopyFileTransactedA_cb(lpExistingFileName, lpNewFileName: LPSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD; hTransaction: THandle): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('CopyFileTransactedA from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := CopyFileTransactedA_np(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags, hTransaction);
end;

function CopyFileTransactedW_cb(lpExistingFileName, lpNewFileName: LPCWSTR; lpProgressRoutine: TFNProgressRoutine; lpData: Pointer; pbCancel: PBool; dwCopyFlags: DWORD; hTransaction: THandle): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('CopyFileTransactedW from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := CopyFileTransactedW_np(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags, hTransaction);
end;

function MoveFileA_cb(lpExistingFileName, lpNewFileName: LPCSTR): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('MoveFileA from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := MoveFileA_np(lpExistingFileName, lpNewFileName);
end;

function MoveFileW_cb(lpExistingFileName, lpNewFileName: LPCWSTR): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('MoveFileW from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := MoveFileW_np(lpExistingFileName, lpNewFileName);
end;

function MoveFileExA_cb(lpExistingFileName, lpNewFileName: LPCSTR; dwFlags: DWORD): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('MoveFileExA from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := MoveFileExA_np(lpExistingFileName, lpNewFileName, dwFlags);
end;

function MoveFileExW_cb(lpExistingFileName, lpNewFileName: LPCWSTR; dwFlags: DWORD): BOOL;
begin
  Result := MessageBoxA(0, PAnsiChar('MoveFileExW from: ' + lpExistingFileName + #13#10 + 'to: ' + lpNewFileName ), 'Allow?', MB_YESNO) = ID_YES;
  if Result then
    Result := MoveFileExW_np(lpExistingFileName, lpNewFileName, dwFlags);
end;

procedure DLLEntryPoint(dwReason: DWORD);
begin
  case dwReason of
    DLL_PROCESS_ATTACH:
    begin
      CoCreateInstance_np := InterceptCreate('ole32.dll', 'CoCreateInstance', @CoCreateInstance_cb);
      
      CopyFileA_np := InterceptCreate('Kernel32.dll', 'CopyFileA', @CopyFileA_cb);
      CopyFileW_np := InterceptCreate('Kernel32.dll', 'CopyFileW', @CopyFileW_cb);
      CopyFileExA_np := InterceptCreate('Kernel32.dll', 'CopyFileExA', @CopyFileExA_cb);
      CopyFileExW_np := InterceptCreate('Kernel32.dll', 'CopyFileExW', @CopyFileExW_cb);
      ReplaceFileA_np := InterceptCreate('Kernel32.dll', 'ReplaceFileA', @ReplaceFileA_cb);
      ReplaceFileW_np := InterceptCreate('Kernel32.dll', 'ReplaceFileW', @ReplaceFileW_cb);
      CopyFileTransactedA_np := InterceptCreate('Kernel32.dll', 'CopyFileTransactedA', @CopyFileTransactedA_cb);
      CopyFileTransactedW_np := InterceptCreate('Kernel32.dll', 'CopyFileTransactedW', @CopyFileTransactedW_cb);
      MoveFileA_np := InterceptCreate('Kernel32.dll', 'MoveFileA', @MoveFileA_cb);
      MoveFileW_np := InterceptCreate('Kernel32.dll', 'MoveFileW', @MoveFileW_cb);
      MoveFileExA_np := InterceptCreate('Kernel32.dll', 'MoveFileExA', @MoveFileExA_cb);
      MoveFileExW_np := InterceptCreate('Kernel32.dll', 'MoveFileExW', @MoveFileExW_cb);
      MoveFileWithProgressA_np := InterceptCreate('Kernel32.dll', 'MoveFileWithProgressA', @MoveFileWithProgressA_cb);
      MoveFileWithProgressW_np := InterceptCreate('Kernel32.dll', 'MoveFileWithProgressW', @MoveFileWithProgressW_cb);

      SHFileOperationA_np := InterceptCreate('Shell32.dll', 'SHFileOperationA', @SHFileOperationA_cb);
      SHFileOperationW_np := InterceptCreate('Shell32.dll', 'SHFileOperationW', @SHFileOperationW_cb);
    end;
    DLL_PROCESS_DETACH:
    begin
      InterceptRemove(@CoCreateInstance_np);

      InterceptRemove(@CopyFileA_np);
      InterceptRemove(@CopyFileW_np);
      InterceptRemove(@CopyFileExA_np);
      InterceptRemove(@CopyFileExW_np);
      InterceptRemove(@ReplaceFileA_np);
      InterceptRemove(@ReplaceFileW_np);
      InterceptRemove(@CopyFileTransactedA_np);
      InterceptRemove(@CopyFileTransactedW_np);
      InterceptRemove(@MoveFileA_np);
      InterceptRemove(@MoveFileW_np);
      InterceptRemove(@MoveFileExA_np);
      InterceptRemove(@MoveFileExW_np);
      InterceptRemove(@MoveFileWithProgressA_np);
      InterceptRemove(@MoveFileWithProgressW_np);

      InterceptRemove(@SHFileOperationA_np);
      InterceptRemove(@SHFileOperationW_np);
    end;
  end;
end;

begin
  DLLProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.