home *** CD-ROM | disk | FTP | other *** search
/ Softwarová Záchrana 3 / Softwarova-zachrana-3.bin / ArsClip / source.zip / UnitFrmChainWatcher.pas < prev    next >
Pascal/Delphi Source File  |  2003-09-29  |  12KB  |  411 lines

  1. unit UnitFrmChainWatcher;
  2. {
  3.     Purpose:
  4.         Monitor the clipboard problems caused by other peoples
  5.         f*cked up programs. *sigh*
  6.  
  7.     Updates:
  8.         option to disable watcher (used by Clipboard Manager)
  9.  
  10.         Disabled Clipboard chain monitor no longer running
  11.         error reporting by default.
  12.  
  13.         --------------------
  14.         Re-wrote "get parent" routine
  15.         Always clear previous errors
  16.         
  17.         ---------------
  18.         Handle EXE Name retreive errors
  19.         --------------
  20.         Keep track of last known program name for reporting if
  21.         current owner is no longer running
  22.         
  23.         -----------------
  24.         New option to report problem program
  25.         Watcher re-written
  26.         ---------------
  27.         I was refreshing the chain wether it needed it or not
  28. }
  29.  
  30. interface
  31.  
  32. uses
  33.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  34.   Dialogs, ExtCtrls, UnitClipQueue;
  35.  
  36. type
  37.   TFrmChainWatcher = class(TForm)
  38.     Timer1: TTimer;
  39.     procedure Timer1TimerNew(Sender: TObject);
  40.     procedure FormCreate(Sender: TObject);
  41.   private
  42.     { Private declarations }
  43.  
  44.     LastClipItem : TClipItem;
  45.     LastClipboardOwner : string;
  46.     DialogShownOnce : boolean;
  47.   public
  48.     { Public declarations }
  49.     procedure NotifyOfClipboardActivity;
  50.     procedure Disable;
  51.     procedure Enable;
  52.   end;
  53.  
  54. var
  55.   FrmChainWatcher: TFrmChainWatcher;
  56.  
  57. {////////////////////}
  58. {//}implementation{//}
  59. {////////////////////}
  60.  
  61. uses Clipbrd, UnitFrmClipboardManager, UnitFrmMainPopup, 
  62.   UnitReportError, UnitMisc, UnitFrmConfig;
  63. {$R *.dfm}
  64.  
  65. type ByteArray = array of byte;
  66.  
  67. procedure TFrmChainWatcher.Disable;
  68. begin
  69.     timer1.Enabled := false;
  70. end;
  71.  
  72. procedure TFrmChainWatcher.Enable;
  73. begin
  74.     timer1.Enabled := true;
  75. end;
  76.  
  77. procedure TFrmChainWatcher.FormCreate(Sender: TObject);
  78. begin
  79.     self.LastClipItem := nil;
  80.     DialogShownOnce := false;
  81.  
  82.     //
  83.     // get me started
  84.     //
  85.     self.Timer1TimerNew(self);
  86. end;
  87.  
  88.  
  89. procedure TFrmChainWatcher.NotifyOfClipboardActivity;
  90. begin
  91.     // Reset the timer to not trigger until later
  92.     // update: make sure timer does not trigger here
  93.     timer1.Enabled := false;
  94.  
  95.     MyFree(self.LastClipItem);
  96.  
  97.     timer1.Enabled := true;
  98. end;
  99.  
  100.  
  101. //
  102. // I should be shot for this.
  103. //
  104. procedure TFrmChainWatcher.Timer1TimerNew(Sender: TObject);
  105. var
  106.     ba1, ba2 : pointer;
  107.     sz : cardinal;
  108.     ChainBroken : boolean;
  109.     ci : TClipItem;
  110.     problem : THandle;
  111.     ownerTitle : string;
  112.  
  113.     procedure HandleBrokenChain;
  114.     begin
  115.         if not (DialogShownOnce or
  116.             FrmConfig.cbDisableChainNotification.checked)  then begin
  117.  
  118.             UnitMisc.AppendLog('Watcher: chain broken');
  119.  
  120.             Timer1.Enabled := false;
  121.  
  122.             Windows.SetForegroundWindow(self.handle);
  123.  
  124.             if (ownerTitle <> '') then begin
  125.                 FrmReportError.ShowForm( ownerTitle );
  126.                 DialogShownOnce :=  true;
  127.             end else if (LastClipboardOwner <> '') then begin
  128.  
  129.                 FrmReportError.ShowForm( LastClipboardOwner );
  130.                 DialogShownOnce :=  true;
  131.  
  132.             end else begin
  133.                 Dialogs.ShowMessage(
  134.                 'ERROR: The Clipboard chain has been broken.' + #13#10 +
  135.                 'Please note which programs are running that may have caused this problem.' + #13#10 +
  136.                 #13#10 +
  137.                 'The Clipboard Monitor will automatically be refreshed and this message'+#13#10+
  138.                 'will not be shown again this session.');
  139.                 DialogShownOnce :=  true;
  140.             end;
  141.         end;
  142.  
  143.         FrmClipboardManager.RefreshClipboardMonitor;
  144.         
  145.         // If this is successful, the timer will be enabled by
  146.         // NotifyClipboardActivity
  147.     end;
  148. var h : THandle;
  149. begin
  150.     Windows.SetLastError(ERROR_SUCCESS);
  151.  
  152.     if not frmClipboardManager.GetIsOnChain then begin
  153.         UnitMisc.AppendLog('Watcher: ClipMonitor not attached - refreshing');
  154.         frmClipboardManager.RefreshClipboardMonitor;
  155.         EXIT;
  156.     end;
  157.     //ChainBroken := false;
  158.  
  159.     UnitMisc.AppendLog('Watcher: getting current clipboard item');
  160.     ci := TClipItem.Create;
  161.     if ci.GetClipboardItem(0) = 0 then begin
  162.         UnitMisc.AppendLog('Watcher: current item failed');
  163.         MyFree(ci);
  164.         MyFree(LastClipItem);
  165.  
  166.         EXIT;
  167.     end;
  168.     UnitMisc.AppendLog('Watcher probe: ' + SysErrorMessage(GetLastError));
  169.     SetLastError(ERROR_SUCCESS);
  170.  
  171.     // First time here?
  172.     if (LastClipItem = nil) then begin
  173.         LastClipItem := ci;
  174.         UnitMisc.AppendLog('Watcher: initing');
  175.     end else begin
  176.         if (LastClipITem.GetDataSize <> ci.GetDataSize) then begin
  177.             // size must be equal or we know a break has happened
  178.             ChainBroken := true;
  179.         end else begin
  180.             sz := ci.GetDataSize;
  181.             ba1 := Windows.GlobalLock(LastClipItem.GetHandle);
  182.             if (ba1 = nil) then begin
  183.                 UnitMisc.AppendLog('Lock failed ' + SysErrorMessage(GetLastError));
  184.                 EXIT;
  185.             end;
  186.             ba2 := Windows.GlobalLock(ci.GetHandle);
  187.             if (ba1 = nil) then begin
  188.                 Windows.GlobalUnlock(LastClipItem.GetHandle);
  189.                 UnitMisc.AppendLog('Lock2 failed ' + SysErrorMessage(GetLastError));
  190.             end;
  191.             chainbroken := not CompareMem(ba1, ba2, sz);
  192.  
  193.             Windows.GlobalUnlock(ci.GetHandle);
  194.             Windows.GlobalUnlock(LastClipItem.GetHandle);
  195.         end;
  196.  
  197.  
  198.         //
  199.         // Gather info about the current owner of the clipboard
  200.         //
  201.         {if not Windows.OpenClipboard(Application.Handle) then begin
  202.             UnitMisc.AppendLog('GetClipboardViewer Open failed: ' + SysErrorMessage(GetLastError));
  203.             EXIT;
  204.         end;}
  205.         // requires Win98 or above for GetAncestor
  206.         {problem := Windows.GetAncestor(Windows.GetClipboardViewer,
  207.             GA_ROOTOWNER  );}
  208.         problem := Windows.GetClipboardViewer;
  209.         if (problem <> 0) then begin
  210.             h := problem;
  211.             while (h <> 0) do begin
  212.                 problem := h;
  213.                 h := GetWindowLong(h, GWL_HWNDPARENT);
  214.             end;
  215.             if (GetLastError <> ERROR_SUCCESS) then begin
  216.                 UnitMisc.AppendLog('Get parent failed: ' + SysErrorMessage(GetLastError));
  217.                 EXIT;
  218.             end;
  219.         end else begin
  220.             UnitMisc.AppendLog('No viewer found: ' + SysErrorMessage(GetLastError));
  221.         end;
  222.  
  223.         {Windows.CloseClipboard;}
  224.  
  225.         ownerTitle := lowercase(ExtractFileName(WindowHandleToEXEName(problem)));
  226.         if (GetLastError <> ERROR_SUCCESS) then begin
  227.             UnitMisc.AppendLog('EXEName error: ' + SysErrorMessage(GetLastError));
  228.         end;
  229.  
  230.         UnitMisc.AppendLog('Clipboard Owner = ' + ownerTitle);
  231.         if (ownerTitle <> '') then begin
  232.             if (ownerTitle <> 'arsclip.exe') and (ownerTitle <> EXENAME_ERROR) then begin
  233.                 LastClipboardOwner := ownerTitle;
  234.             end;
  235.         end;
  236.  
  237.         // If the clipboard owner is AWOL and configured to check this,
  238.         // or the clip has changed and we don't know about it, then
  239.         // the chain has been broken
  240.  
  241.         if (ChainBroken or
  242.             ((ownerTitle = '') and frmConfig.cbEnableExtendedChainChecking.Checked) and
  243.             (ownerTitle <> EXENAME_ERROR)) then begin
  244.             if (ownerTitle = 'arsclip.exe') then begin
  245.                 ownerTitle := '';
  246.             end;
  247.             if (LastClipboardOwner = 'arsclip.exe') then begin
  248.                 LastClipboardOwner := '';
  249.             end;
  250.  
  251.             HandleBrokenChain;
  252.         end;
  253.  
  254.         // clean up the previous copy
  255.         // store for next time this event fires
  256.         MyFree(LastClipItem);
  257.         LastClipItem := ci;
  258.     end;
  259. end;
  260.  
  261. {
  262. procedure TFrmChainWatcher.Timer1TimerNew(Sender: TObject);
  263.     function DupHandle(h : Thandle; var sizeh : cardinal) : Thandle;
  264.     var
  265.         newh : Thandle;
  266.         p1, p2 : pointer;
  267.     begin
  268.         result := 0;
  269.         if (h = 0) then
  270.             EXIT;
  271.         //
  272.         // make sure size is non-zero
  273.         // and not bigger than size restrictions
  274.         //
  275.         sizeh := Windows.GlobalSize(h);
  276.         if (sizeh = 0) then
  277.             EXIT;
  278.  
  279.         //
  280.         // Lock and copy
  281.         //
  282.  
  283.         newh := Windows.GlobalAlloc(GMEM_MOVEABLE, sizeh);
  284.         if (newh=0) then EXIT;
  285.         p1 := Windows.GlobalLock(newh);
  286.         p2 := Windows.GlobalLock(h);
  287.         if ((p1=nil) or (p2=nil)) then EXIT;
  288.  
  289.         CopyMemory(p1, p2, sizeh);
  290.  
  291.         Windows.GlobalUnlock(h);
  292.         Windows.GlobalUnlock(newh);
  293.  
  294.         result := newh;
  295.     end;
  296.  
  297. var i : integer;
  298.     h : THandle;
  299.  
  300.     clipSize : cardinal;
  301.     ClipformatPop : word;
  302.     CliphandlePop : THandle;
  303.     ba1, ba2 : ^ByteArray;
  304.     ChainBroken : boolean;
  305. begin
  306.     if not frmClipboardManager.GetIsOnChain then begin
  307.         UnitMisc.AppendLog('Watcher: ClipMonitor not attached - refreshing');
  308.         frmClipboardManager.RefreshClipboardMonitor;
  309.         EXIT;
  310.     end;
  311.     ChainBroken := false;
  312.  
  313.  
  314.     // find the current format
  315.     // must be non-zero
  316.     ClipformatPop := 0;
  317.     if not Windows.OpenClipboard(Application.Handle) then begin
  318.         UnitMisc.AppendLog('Watcher: can''t open clipboard');
  319.         EXIT;
  320.     end;
  321.  
  322.     for i := 0 to clipboard.FormatCount - 1 do begin
  323.         if (clipboard.HasFormat(Clipboard.Formats[i])) then begin
  324.             ClipFormatPop := Clipboard.Formats[i];
  325.             //BREAK;
  326.         end;
  327.     end;
  328.  
  329.     if (ClipFormatPop  = 0) then begin
  330.         UnitMisc.AppendLog('Watcher: format not found');
  331.         Windows.CloseClipboard;
  332.         EXIT;
  333.     end;
  334.  
  335.  
  336.     //
  337.     // Dupe the handle, exit on error
  338.     // (aka copy what's on the clipboard)
  339.  
  340.     h := clipboard.GetAsHandle(ClipFormatPop);
  341.     CliphandlePop := DupHandle(h, ClipSize);
  342.     Windows.CloseClipboard;
  343.     if (CliphandlePop = 0) then begin
  344.         UnitMisc.AppendLog('Watcher: dup failed');
  345.         EXIT;
  346.     end;
  347.  
  348.     // First time here?
  349.     if (self.LastHandle = 0) then begin
  350.         LastHandle := CliphandlePop;
  351.         LastSize := ClipSize;
  352.         UnitMisc.AppendLog('Watcher: initing');
  353.     end else begin
  354.         if (LastSize <> ClipSize) then begin
  355.             // size must be equal or we know a break has happened
  356.             ChainBroken := true;
  357.         end else begin
  358.             // compare the contents of each memory location
  359.             // becuase the size is the same
  360.             UnitMisc.AppendLog('Watcher: Testing clip');
  361.             ba1 := Pointer(LastHandle);
  362.             ba2 := Pointer(ClipHandlePop);
  363.  
  364.             for i := 0 to ClipSize - 1 do begin
  365.                 if (ba1^[i] <> ba2^[i]) then begin
  366.                     ChainBroken := true;
  367.                     BREAK;
  368.                 end;
  369.             end;
  370.         end;
  371.  
  372.  
  373.         // Fix the chain and/or Warn about it
  374.         // GRR - bad bad bad me
  375.         // I was refreshing the chain wether it needed it or not
  376.  
  377.         if (ChainBroken) then begin
  378.             if (not DialogShownOnce) then begin
  379.                 DialogShownOnce :=  true;
  380.                 UnitMisc.AppendLog('Watcher: chain broken');
  381.                 Windows.SetForegroundWindow(self.handle);
  382.                 Timer1.Enabled := false;
  383.                 Dialogs.ShowMessage(
  384.                     'ERROR: The Clipboard chain has been broken.' + #13#10 +
  385.                     'Please note which programs are running that may have caused this problem.' + #13#10 +
  386.                     #13#10 +
  387.                     'The Clipboard Monitor will automatically be refreshed and this message'+#13#10+
  388.                     'will not be shown again this session.');
  389.                 Timer1.Enabled := true;
  390.             end;
  391.  
  392.             FrmClipboardManager.RefreshClipboardMonitor;
  393.         end;
  394.  
  395.         // clean up the previous copy
  396.         // store for next time this event fires
  397.  
  398.         if (Windows.GlobalFree(LastHandle) <> 0) then begin
  399.             UnitMisc.AppendLog('Watcher: Can''t free old clip');
  400.         end;
  401.  
  402.         LastHandle := CliphandlePop;
  403.         LastSize := ClipSize;
  404.  
  405.     end;
  406. end;
  407. }
  408.  
  409.  
  410. end.
  411.