AlanMar

UNIT_ShellNotify

Mar 8th, 2011
281
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 11.24 KB | None | 0 0
  1. {********************************************************}
  2. {                                                        }
  3. {    Firesoft Utils Package                              }
  4. {    ShellNotify Component                               }
  5. {                                                        }
  6. {    Copyright (c) Federico Firenze                      }
  7. {    Buenos Aires, Argentina                             }
  8. {                                                        }
  9. {********************************************************}
  10.  
  11. unit ShellNotify;
  12.  
  13. {$IFNDEF VER110}
  14.   {$IFNDEF VER120}
  15.     {$IFNDEF VER130}
  16.       {$WARN SYMBOL_PLATFORM OFF}
  17.       {$DEFINE DELPHICLX}
  18.     {$ENDIF}
  19.   {$ENDIF}
  20. {$ENDIF}
  21.  
  22. interface
  23.  
  24. uses
  25.   Windows, Messages, Classes, ShlObj;
  26.  
  27. {
  28.  Referencias MSDN:
  29.  
  30.  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/structures/SHChangeNotifyEntry.asp
  31.  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/Functions/SHChangeNotifyRegister.asp
  32.  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/SHChangeNotifyDeregister.asp
  33.  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shilcreatefrompath.asp
  34.  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/structures/SHGetPathFromIDList.asp
  35. }
  36.  
  37. const
  38.   SHCNF_ACCEPT_INTERRUPTS = $0001;
  39.   SHCNF_ACCEPT_NON_INTERRUPTS = $0002;
  40.  
  41.   { Mensaje de Notificación de Cambios }
  42.   WM_SHELLNOTIFY = WM_USER + $5000;
  43.  
  44. type
  45.   SHChangeNotifyEntry = record
  46.     pidl: PItemIDList;
  47.     fRecursive: Boolean;
  48.   end;
  49.   PSHChangeNotifyEntry = ^SHChangeNotifyEntry;
  50.  
  51.   TItemIDArray = record
  52.     pidl: array[0..1] of PItemIDList
  53.   end;
  54.   PItemIDArray = ^TItemIDArray;
  55.  
  56. {$EXTERNALSYM SHChangeNotifyRegister}
  57. function SHChangeNotifyRegister(hWnd: HWND; fSources: Integer; fEvents: Longint; wMsg: UINT; cEntries: Integer; pfsne: PSHChangeNotifyEntry): ULONG; stdcall;
  58. {$EXTERNALSYM SHChangeNotifyDeregister}
  59. function SHChangeNotifyDeregister(ulID: ULONG): Boolean; stdcall;
  60. {$EXTERNALSYM SHILCreateFromPath}
  61. function SHILCreateFromPath(pszPath: PChar; ppidl: PSHChangeNotifyEntry; var rgflnOut: PDWORD): HRESULT; stdcall;
  62. {$EXTERNALSYM SHILCreateFromPath}
  63. function SHILCreateFromPathNT(pszPath: LPCWSTR; ppidl: PSHChangeNotifyEntry; var rgflnOut: PDWORD): HRESULT; stdcall;
  64.  
  65.  
  66. type
  67.   TShellNotifyEvent = (neAssocChanged, neAttributes, neCreate, neDelete, neDriveAdd, neDriveAddGUI, neDriveRemoved,
  68.                        neMediaInserted, neMediaRemoved, neMkDir, neNetShare, neNetUnshare, neRenameFolder, neRenameItem,
  69.                        neRmDir, neServerDisconnect, neUpdateDir, neUpdateImage, neUpdateItem, neOther);
  70.   TShellNotifyEvents = set of TShellNotifyEvent;
  71.   TSHNotifyEvent = procedure(Sender: TObject; Event: TShellNotifyEvent; Path1, Path2: AnsiString) of object;
  72.  
  73.   TShellNotify = class(TComponent)
  74.   private
  75.     FActive: Boolean;
  76.     FHandle: THandle;
  77.     FNotifyEvents: TShellNotifyEvents;
  78.     FPathList: TStrings;
  79.     FOnNotify: TSHNotifyEvent;
  80.     procedure SetActive(const Value: Boolean);
  81.     procedure SetShellNotifyEvents(const Value: TShellNotifyEvents);
  82.     procedure SetPathList(const Value: TStrings);
  83.   protected
  84.     hNotify: ULONG; // Handle
  85.     procedure WndProc(var Message: TMessage);
  86.   public
  87.     constructor Create(AOwner: TComponent); override;
  88.     destructor Destroy; override;
  89.     procedure Open;
  90.     procedure Close;
  91.     property Handle: THandle read FHandle;
  92.   published
  93.     property NotifyEvents: TShellNotifyEvents read FNotifyEvents write SetShellNotifyEvents default [neCreate, neDelete, neMkDir, neRenameFolder, neRenameItem, neRmDir];
  94.     property PathList: TStrings read FPathList write SetPathList;
  95.     property Active: Boolean read FActive write SetActive default False; // Tiene que estar por debajo de NotifyEvents y PathList
  96.     property OnNotify: TSHNotifyEvent read FOnNotify write FOnNotify;
  97.   end;
  98.  
  99. {$IFNDEF FSUTILS}
  100. procedure Register;
  101. {$ENDIF}
  102.  
  103. implementation
  104.  
  105. uses
  106.   SysUtils, ShellApi, Consts{$IFNDEF DELPHICLX}, Forms{$ENDIF};
  107.  
  108. {$IFNDEF FSUTILS}
  109. procedure Register;
  110. begin
  111.   RegisterComponents('FireSoft', [TShellNotify]);
  112. end;
  113. {$ENDIF}
  114.  
  115. function SHChangeNotifyRegister;  external shell32 index 2;
  116. function SHChangeNotifyDeregister; external shell32 index 4;
  117. function SHILCreateFromPathNT; external shell32 index 28;
  118. function SHILCreateFromPath; external shell32 index 28;
  119.  
  120.  
  121. function NotifyEventsToLongint(ANotifyEvents: TShellNotifyEvents): Longint;
  122. begin
  123.   Result := 0;
  124.  
  125.   if neAssocChanged in ANotifyEvents Then
  126.     Result := Result or SHCNE_ASSOCCHANGED;
  127.  
  128.   if neAttributes in ANotifyEvents Then
  129.     Result := Result or SHCNE_ATTRIBUTES;
  130.  
  131.   if neCreate in ANotifyEvents Then
  132.     Result := Result or SHCNE_CREATE;
  133.  
  134.   if neDelete in ANotifyEvents Then
  135.     Result := Result or SHCNE_DELETE;
  136.  
  137.   if neDriveAdd in ANotifyEvents Then
  138.     Result := Result or SHCNE_DRIVEADD;
  139.  
  140.   if neDriveAddGUI in ANotifyEvents Then
  141.     Result := Result or SHCNE_DRIVEADDGUI;
  142.  
  143.   if neDriveRemoved in ANotifyEvents Then
  144.     Result := Result or SHCNE_DRIVEREMOVED;
  145.  
  146.   if neMediaInserted in ANotifyEvents Then
  147.     Result := Result or SHCNE_MEDIAINSERTED;
  148.  
  149.   if neMediaRemoved in ANotifyEvents Then
  150.     Result := Result or SHCNE_MEDIAREMOVED;
  151.  
  152.   if neMkDir in ANotifyEvents Then
  153.     Result := Result or SHCNE_MKDIR;
  154.  
  155.   if neNetShare in ANotifyEvents Then
  156.     Result := Result or SHCNE_NETSHARE;
  157.  
  158.   if neNetUnshare in ANotifyEvents Then
  159.     Result := Result or SHCNE_NETUNSHARE;
  160.  
  161.   if neRenameFolder in ANotifyEvents Then
  162.     Result := Result or SHCNE_RENAMEFOLDER;
  163.  
  164.   if neRenameItem in ANotifyEvents Then
  165.     Result := Result or SHCNE_RENAMEITEM;
  166.  
  167.   if neRmDir in ANotifyEvents Then
  168.     Result := Result or SHCNE_RMDIR;
  169.  
  170.   if neServerDisconnect in ANotifyEvents Then
  171.     Result := Result or SHCNE_SERVERDISCONNECT;
  172.  
  173.   if neUpdateDir in ANotifyEvents Then
  174.     Result := Result or SHCNE_UPDATEDIR;
  175.  
  176.   if neUpdateImage in ANotifyEvents Then
  177.     Result := Result or SHCNE_UPDATEIMAGE;
  178.  
  179.   if neUpdateItem in ANotifyEvents Then
  180.     Result := Result or SHCNE_UPDATEITEM;
  181. end;
  182.  
  183. function LongintToNotifyEvent(AValue: Longint): TShellNotifyEvent;
  184. begin
  185.   case AValue of
  186.     SHCNE_ASSOCCHANGED:
  187.       Result := neAssocChanged;
  188.     SHCNE_ATTRIBUTES:
  189.       Result := neAttributes;
  190.     SHCNE_CREATE:
  191.       Result := neCreate;
  192.     SHCNE_DELETE:
  193.       Result := neDelete;
  194.     SHCNE_DRIVEADD:
  195.       Result := neDriveAdd;
  196.     SHCNE_DRIVEADDGUI:
  197.       Result := neDriveAddGui;
  198.     SHCNE_DRIVEREMOVED:
  199.       Result := neDriveRemoved;
  200.     SHCNE_MEDIAINSERTED:
  201.       Result := neMediaInserted;
  202.     SHCNE_MEDIAREMOVED:
  203.       Result := neMediaRemoved;
  204.     SHCNE_MKDIR:
  205.       Result := neMkDir;
  206.     SHCNE_NETSHARE:
  207.       Result := neNetShare;
  208.     SHCNE_NETUNSHARE:
  209.       Result := neNetUnShare;
  210.     SHCNE_RENAMEFOLDER:
  211.       Result := neRenameFolder;
  212.     SHCNE_RENAMEITEM:
  213.       Result := neRenameItem;
  214.     SHCNE_RMDIR:
  215.       Result := neRmDir;
  216.     SHCNE_SERVERDISCONNECT:
  217.       Result := neServerDisconnect;
  218.     SHCNE_UPDATEDIR:
  219.       Result := neUpdateDir;
  220.     SHCNE_UPDATEIMAGE:
  221.       Result := neUpdateImage;
  222.     SHCNE_UPDATEITEM:
  223.       Result := neUpdateItem;
  224.   else
  225.     Result := neOther;
  226.   end;
  227. end;
  228.  
  229. function PidlToStr(pidl: PItemIDList): AnsiString;
  230. var
  231.   PResult: PAnsiChar;
  232. begin
  233.   PResult := StrAlloc(MAX_PATH);
  234.   try
  235.     if not ShlObj.SHGetPathFromIDListA(pidl, PResult) then
  236.       Result := ''
  237.     else
  238.       Result := StrPas(PResult);
  239.   finally
  240.     StrDispose(PResult);
  241.   end;
  242. end;
  243.  
  244. //------------------------------------------------------------------------------
  245. // TShellNotify
  246. //------------------------------------------------------------------------------
  247. procedure TShellNotify.Close;
  248. begin
  249.   if hNotify > 0 Then
  250.     SHChangeNotifyDeregister(hNotify);
  251.  
  252.   if FHandle > 0 Then
  253.     DeallocateHWnd(FHandle);
  254. end;
  255.  
  256. constructor TShellNotify.Create(AOwner: TComponent);
  257. begin
  258.   inherited Create(AOwner);
  259.   FPathList := TStringList.Create;
  260.   FActive := False;
  261.   FNotifyEvents := [neCreate, neDelete, neMkDir, neRenameFolder, neRenameItem, neRmDir];
  262. end;
  263.  
  264. destructor TShellNotify.Destroy;
  265. begin
  266.   Active := False;
  267.   FPathList.Free;
  268.   FPathList := nil;
  269.   inherited Destroy;
  270. end;
  271.  
  272. procedure TShellNotify.Open;
  273. var
  274.   BuffPath: array[0..MAX_PATH] of WideChar;
  275.   iPath, cEntries: Integer;
  276.   fEvents: Longint;
  277.   Attr: PDWORD;
  278.   NotifyEntrys: array[0..1023] of SHChangeNotifyEntry; // Si uso un Array dinámico Falla
  279.  
  280.   {$IFNDEF DELPHICLX}
  281.   procedure RaiseLastOsError;
  282.   begin
  283.     RaiseLastWin32Error;
  284.   end;
  285.   {$ENDIF}
  286.  
  287. begin
  288.   if FNotifyEvents = [] Then
  289.     fEvents := SHCNE_ALLEVENTS
  290.   else
  291.     fEvents := NotifyEventsToLongint(FNotifyEvents);
  292.  
  293.  
  294.   FHandle := AllocateHWnd(WndProc);
  295.   try
  296.     if FPathList.Count = 0 Then begin
  297.       // Notifica cambios de todo el FileSystem
  298.       cEntries := 1;
  299.       with NotifyEntrys[0] do begin
  300.         pidl := nil;
  301.         fRecursive := True;
  302.       end;
  303.     end else begin
  304.       cEntries := FPathList.Count;
  305.       for iPath := 0 to cEntries - 1 do begin
  306.         if Win32Platform <> VER_PLATFORM_WIN32_WINDOWS Then begin
  307.           StringToWideChar(FPathList[iPath], BuffPath, SizeOf(BuffPath));
  308.           if SHILCreateFromPathNT(BuffPath, @NotifyEntrys[iPath], Attr) <> S_OK Then
  309.             RaiseLastOsError;
  310.         end else begin
  311.           if SHILCreateFromPath(PAnsiChar(FPathList[iPath]), @NotifyEntrys[iPath], Attr) <> S_OK Then
  312.             RaiseLastOsError;
  313.         end;
  314.  
  315.         NotifyEntrys[iPath].fRecursive := True;
  316.       end;
  317.     end;
  318.  
  319.     hNotify := SHChangeNotifyRegister(FHandle, SHCNF_ACCEPT_INTERRUPTS + SHCNF_ACCEPT_NON_INTERRUPTS, fEvents, WM_SHELLNOTIFY, cEntries, @NotifyEntrys);
  320.     if hNotify = 0 then
  321.       RaiseLastOsError;
  322.   except
  323.     Close;
  324.     raise;
  325.   end;
  326. end;
  327.  
  328. procedure TShellNotify.SetActive(const Value: Boolean);
  329. begin
  330.   if FActive <> Value then begin
  331.     if not (csDesigning in ComponentState) then begin
  332.       if Value then
  333.         Open
  334.       else
  335.         Close;
  336.     end;
  337.     FActive := Value;
  338.   end;
  339. end;
  340.  
  341. procedure TShellNotify.SetShellNotifyEvents(const Value: TShellNotifyEvents);
  342. begin
  343.   if FNotifyEvents <> Value Then begin
  344.     Active := False; // TODO : Falta Código
  345.     FNotifyEvents := Value;
  346.   end;
  347. end;
  348.  
  349. procedure TShellNotify.SetPathList(const Value: TStrings);
  350. begin
  351.   Active := False; // TODO : Falta Código
  352.   FPathList.Assign(Value);
  353. end;
  354.  
  355. procedure TShellNotify.WndProc(var Message: TMessage);
  356. var
  357.   NotifyEvent: TShellNotifyEvent;
  358.   pItem: PItemIDArray;
  359.   Path1, Path2: AnsiString;
  360. begin
  361.   if Message.Msg = WM_SHELLNOTIFY Then begin
  362.     NotifyEvent := LongintToNotifyEvent(Message.LParam and SHCNE_ALLEVENTS);
  363.     pItem := PItemIDArray(Message.wParam);
  364.     Path1 := PidlToStr(pItem^.pidl[0]);
  365.  
  366.     if NotifyEvent in [neRenameFolder, neRenameItem, neUpdateImage] then
  367.       Path2 := PidlToStr(pItem^.pidl[1])
  368.     else
  369.       Path2 := '';
  370.  
  371.     if Assigned(FOnNotify) Then
  372.       FOnNotify(Self, NotifyEvent, Path1, Path2);
  373.   end else
  374.     Message.Result := DefWindowProc(FHandle, Message.Msg, Message.wParam, Message.lParam);
  375. end;
  376.  
  377. end.
Advertisement
Add Comment
Please, Sign In to add comment