DuByD Posted August 1, 2013 Share Posted August 1, 2013 I have written a script that works with one client window and I was trying to branch it out to handle more than one. Here is a sample of what I am doing... Simplified... I get runtime errors when calling a procedure with a different client (ColorSomething in this example). Hope this makes sense.... program new; var Wnds: THwndArray; Client1,Client2 : TSCARWindowClient; // 2 clients Client1Width, Client1Height : Integer; Client2Width, Client2Height : Integer; RatioX1,RatioX2,RatioY1,RatioY2 : Single; const ColorTol : 2; Color : 123456; // used to create a tbox that focuses on a certain area of a windows and adjusts for size. function CreateTBox(X,Y : Integer; RX1,RY1,RX2,RY2 : Single) : TBox; var tb : TBox; X1,X2,Y1,Y2 : Integer; begin X1 := Floor(X * RX1); X2 := Floor(X * RX2); Y1 := Floor(Y * RY1); Y2 := Floor(Y * RY2); tb := Box(X1,Y1,X2,Y2); Result := tb; end; // sample procedure to look for a color and do something procedure ColorSomething(Client : TSCARWindowClient; tb : TBox) : Boolean; var X,Y : Integer; begin Client.Activate; Client.ClientArea := True; FindColorTol(X,Y,Color,tb.X1,tb.Y1,tb.X2,tb.Y2,ColorTol); MoveMouse(X,Y); // Do Some Stuff end; procedure SetupClient1; begin Wnds := FindWindowsPreg(GetDesktopWindow,Client1Title,'', False); Client1 := TSCARWindowClient.Create(Wnds[0]); SetClient(Client1).Free(); Client1.Activate; Client1.ClientArea := True; Client1Width := Client1.ImageArea.X2 + 1; Client1Height := Client1.ImageArea.Y2 + 1; end; procedure SetupClient2; begin Wnds := FindWindowsPreg(GetDesktopWindow,Client2Title,'', False); Client2 := TSCARWindowClient.Create(Wnds[0]); SetClient(Client2).Free(); Client2.Activate; Client2.ClientArea := True; Client2Width := Client2.ImageArea.X2 + 1; Client2Height := Client2.ImageArea.Y2 + 1; end; procedure SetupBoxes; begin Client1TB := CreateTBox(Client1Width,Client1Height,RatioX1,RatioY1,RatioX2,RatioY2); Client2TB := CreateTBox(Client2Width,Client2Height,RatioX1,RatioY1,RatioX2,RatioY2); end; begin RatioX1 := 0.2; RatioY1 := 0.2; RatioX2 := 0.8; RatioY2 := 0.8; SetupClient1; SetupClient2; SetupRatios; SetupBoxes; ColorSomething(Client1,Client1TB); ColorSomething(Client2,Client2TB); ColorSomething(Client1,Client1TB); end. Quote Link to comment Share on other sites More sharing options...
LordJashin Posted August 2, 2013 Share Posted August 2, 2013 (edited) Constants are set with = not : const ColorTol = 2; Color = 123456; I tried to compile that code, and a bunch of different things were wrong. Are you porting this over from Delphi/Free Pascal? What you want to achieve isn't too hard. You need an array of some sort to keep all the clients (windows) in. Then say, you want to run Example() on every client, then you just look through the array and do Client[index].Example();. This is just a concept, an example if you will. In Your Case: Use SetClient function, to change which Window is the Targeted Client. THEN use GetClient.Activate; to bring the window into view, so your functions can work on it. e.g. // Updated by LordJashin procedure ColorSomething(Client : TSCARWindowClient; tb : TBox) : Boolean; var X,Y : Integer; begin SetClient(Client); Client.Activate; // or you can use GetClient.Activate; Client.ClientArea := True; // Sure if you need this if FindColorTol(X,Y,Color,tb.X1,tb.Y1,tb.X2,tb.Y2,ColorTol) then // you need if..then otherwise Mouse(X, Y) always executes MoveMouse(X,Y); // Do Some Stuff end; Edited August 2, 2013 by LordJashin Quote Link to comment Share on other sites More sharing options...
DuByD Posted August 2, 2013 Author Share Posted August 2, 2013 Thanks... I just typed that up real quick for an example... sry about the errors... I added "SetClient(Client);" in front of the "Client.Activate;" throughout the script and I am still getting a runtime error placing the error right at "Client.Activate". Any other ideas? Quote Link to comment Share on other sites More sharing options...
LordJashin Posted August 2, 2013 Share Posted August 2, 2013 (edited) You didn't find ANY windows, then your trying to Wnds[0] to it. What if it didn't find any? Then Length(Wnds) = 0; Meaning you can't do Wnds[0]. Also, you never set the ClientTitles as far as I can tell. Which is what your searching for in FindWindowPreg. This is how it should be done: var Client2_IsNull: Boolean; procedure SetupClient2; begin Wnds := FindWindowsPreg(GetDesktopWindow,Client2Title,'', False); if Length(Wnds) < 1 then begin Client2_IsNull := True; // Meaning Client2 := TSCARWindowClient.Create WAS NOT CALLED. So it isn't created WriteLn('No windows were found for client 2 Exiting the Setup procedure for CLient2'); Exit; end; Client2 := TSCARWindowClient.Create(Wnds[0]); SetClient(Client2).Free(); Client2.Activate; Client2.ClientArea := True; Client2Width := Client2.ImageArea.X2 + 1; Client2Height := Client2.ImageArea.Y2 + 1; end; Use something like that to Check the array, and then act from there. Length(s): LongInt; : This returns the length of strings. OR the length of Arrays (Including THwndArray) Refer to the tutorials section to learn more: http://forums.scar-divi.com/tutorials-faq/ Edited August 2, 2013 by LordJashin Quote Link to comment Share on other sites More sharing options...
DuByD Posted August 2, 2013 Author Share Posted August 2, 2013 OK... totally baffled now.. I rewrote the sample i gave to a compilable version that uses two notepad windows... I do know that the windows are being found and that isn't the reason for the errors as I see them get activated one by one and pop up over the editor. I did add the SetClient(Client); to the procedures and was still having the issue... This time I noticed that the var for Client1 was showing a blank after the .free and activate for client two. Interestingly enough, this did not happen in my test script and there is no logical difference which is why I am baffled. I do need to go back and do some error handling with some try statements and checking of the variables as in your example. I did however get it to work... In the setup procedure, i changed the SetClient(Client1).Free(); to SetClient(Client1); without the .Free(). Not sure why it works in the example in this post and doesn't in my main script but it seems as though it isn't needed. It looks like Client1 is losing its settings when the 2nd, 3rd, etc. clients are being set and thus the procedure is trying to operate on "nothing". Below is the sample that i made using two notepad documents. One titled test1 and the other test2. My comments mark the points and changes in relation to my full script. program new; var Wnds: THwndArray; Client1,Client2 : TSCARWindowClient; const Client1Title = '/test1.*/i'; Client2Title = '/test2.*/i'; procedure TypeSomething(Client : TSCARWindowClient; s : String); begin SetClient(Client); Client.Activate; Client.ClientArea := True; // needed for my purposes not this example TypeText(s); end; procedure SetupClient1; begin Wnds := FindWindowsPreg(GetDesktopWindow,Client1Title,'', False); Client1 := TSCARWindowClient.Create(Wnds[0]); SetClient(Client1).Free(); // in main script changed to SetClient(Client1); Client1.Activate; Client1.ClientArea := True; end; procedure SetupClient2; begin Wnds := FindWindowsPreg(GetDesktopWindow,Client2Title,'', False); Client2 := TSCARWindowClient.Create(Wnds[0]); SetClient(Client2).Free(); // in main script changed to SetClient(Client1); Client2.Activate; Client2.ClientArea := True; // this is where i lose client 1 in my real script end; // cursor sitting before this line begin SetupClient1; SetupClient2; TypeSomething(Client1,'This Is Test1'); TypeSomething(Client1,'This Is Test1 Again'); TypeSomething(Client2,'This Is Test2'); TypeSomething(Client1,'This Is Test1 Again'); end. Quote Link to comment Share on other sites More sharing options...
LordJashin Posted August 2, 2013 Share Posted August 2, 2013 (edited) I've seen SetClient(Client).Free(); a lot. I never preferred doing this. I could be wrong, but I think that is "chaining" in action. Instead of doing this: SetClient(Client); Client.Free(); You can do this: SetClient(Client).Free(); Thus this is the error as you have indicated. My bad for not picking up on it. Change SetClient(Client).Free(); to just SetClient(Client); Since this is a variable you created yourself (e.g. Client1), you also need to Free it, when your done with it. E.g. like if you create a GUI application, once some1 closes it, everything has to be freed from the memory. So after you do the last TypeSomething, do Client1.Free;, Client2.Free;. Try restarting SCAR. And should be good. So the reason this code: Client1.Activate; Client1.ClientArea := True; Doesn't run, is because Client1 was freed early. EDIT: Weird. Well, I think wrapping the FindWindow, and Client stuff in some functions would make this a lot cleaner. Edited August 2, 2013 by LordJashin Quote Link to comment Share on other sites More sharing options...
FHannes Posted August 6, 2013 Share Posted August 6, 2013 @LordJashin: SetClient returns the active client, not the client you set, so SetClient(Client);Client.Free; does not equal SetClient(Client).Free; Quote Link to comment Share on other sites More sharing options...
LordJashin Posted August 8, 2013 Share Posted August 8, 2013 @LordJashin: SetClient returns the active client, not the client you set, so SetClient(Client);Client.Free; does not equal SetClient(Client).Free; So SetClient(Client).Free; = PrevActiveClient := SetClient(Client); PrevActiveClient.Free; Does that do anything to the client system? Or does it just "refresh" it? Quote Link to comment Share on other sites More sharing options...
FHannes Posted August 9, 2013 Share Posted August 9, 2013 So SetClient(Client).Free; = PrevActiveClient := SetClient(Client); PrevActiveClient.Free; Does that do anything to the client system? Or does it just "refresh" it? It just changes what client object is active and free the previous one. Think: OldClient := GetClient; SetClient(NewClient); OldClient.Free; Quote Link to comment Share on other sites More sharing options...