Jump to content

Recommended Posts

I didn't like the search time of Simple Native Image Search, and being on windows 10 64bit, I couldn't get ImageSearchDll.dll to work properly.

So I started researching image search routines and found this excellent post and set of replies find-a-bitmap-within-another-bitmap.

I really liked the pattern that the Simple Native Image Search used, the clipboard usage and the method of searching. Although I think it could be improved by using some short circuit techniques to return sooner, like consecutive matched > 65% return | matched total > 85% return) , and I wanted the function to manage the click on the found image as well.

So I just did a bit more research and a few trips to MSDN and stackoverflow, these two snippets allow me to replicate KyleJustKnows code, and click.  Another feature is that it also saves the image it captures to disk, so that if the image is not found you can check what was captured, and alternatively cut out a new search image to use.

private void PrintScreen()
        {
            keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY, 0);
            keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_KEYUP, 0);
        }

        public Bitmap CaptureScreenPrtSc()
        {

            PrintScreen();
            if (Clipboard.ContainsImage())
            {
                using (Image img = Clipboard.GetImage())
                {
                    img.Save("ClipBoard.PNG", ImageFormat.Png);
                    return new Bitmap(img);
                }
            }
            return default;
        }
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetCursorPos(out MousePoint lpMousePoint);

        [DllImport("user32.dll")]
        private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);

        private MousePoint GetCursorPosition()
        {
            var gotPoint = GetCursorPos(out MousePoint currentMousePoint);
            if (!gotPoint) { currentMousePoint = new MousePoint(0, 0); }
            return currentMousePoint;
        }

        private void MouseEvent(MouseEvents value)
        {
            MousePoint position = GetCursorPosition();

            mouse_event
                ((int)value,
                 position.X,
                 position.Y,
                 0,
                 0)
                ;
        }


So after managing to compile the dll with COM support, with much reading of this forum and many posts from paulpmeierptrexLarsJ, and others about loading .net, I managed to get this all working.

Here is the BotIt Core:

;   BotIt Core


Global $sPath = "BotIt.dll"

Global $RegAsmPath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe"

Func BotIt_StartUp()
    RegisterBotIt()
    OnAutoItExitRegister("UnregisterBotIt")
EndFunc   ;==>BotIt_StartUp

Func RegisterBotIt()
    RunWait($RegAsmPath & " /register /codebase /tlb " & $sPath, @ScriptDir, @SW_HIDE)
EndFunc   ;==>RegisterBotIt

Func UnregisterBotIt()
    FileDelete("Step.txt")
    RunWait($RegAsmPath & " /unregister " & $sPath, @ScriptDir, @SW_HIDE)
EndFunc   ;==>UnregisterBotIt

Func ActivateAndSearch($sTitle, $sImgPath, $bClick = True)
    WinActivate($sTitle)
    Sleep(1000)
    $oBotIt = ObjCreate("BotIt.DetectImageAndClick")
    ConsoleWrite($sImgPath & @CRLF & $bClick & @CRLF)
    $bRet = $oBotIt.FindAndClick($sImgPath, $bClick)
    Return $bRet
EndFunc   ;==>ActivateAndSearch

 

Usage:

Do
        Sleep(500)
    Until ActivateAndSearch("Window Title", "PathToFile")



I hope you enjoy!

Regards,

ScrapeYourself
 

 

BotIt.cs

Edited by ScrapeYourself
spelling / wording

Share this post


Link to post
Share on other sites

This thread will be closed 99% anyway (forum rules), but that is not the reason for my contribution.

Warning : Never download and execute a .dll from an unknown source.


Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Share this post


Link to post
Share on other sites

After reading the rules this is not about botting a game, or has anything to do with a game.

rules as I see them.

  • Malware of any form - trojan, virus, keylogger, spam tool, "joke/spoof" script, etc.
  • Bypassing of security measures - log-in and security dialogs, CAPTCHAs, anti-bot agents, software activation, etc.
  • Automation of software/sites contrary to their EULA (see Reporting bullet below).
  • Launching, automation or script interaction with games or game servers, regardless of the game.
  • Running or injecting any code (in any form) intended to alter the original functionality of another process.
  • Decompilation of AutoIt scripts or details of decompiler software

This tool is not used for anything more then what it is intended to do..Find and click a image on the screen.

I provided source code for self compilation in first post.

 

 

Edited by ScrapeYourself

Share this post


Link to post
Share on other sites

 

9 minutes ago, ScrapeYourself said:

After reading the rules this is not about botting a game, or has anything to do with a game.

Fortunately, that's not my decision. I just wanted to inform (especially inexperienced) users not to start executables, if the origin is possibly uncertain ;).


Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Share this post


Link to post
Share on other sites
13 minutes ago, ScrapeYourself said:

I still want to understand further, why you think 99 % it will be closed :( 
what can i do to change that?

It is best to wait and see how a moderator judges this issue. If there are no objections, the thread will not be closed ;). But I have experienced in the past that threads about "Pixelsearch", "Imagesearch" and similar operations are considered very strictly.

Edited by Musashi

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Share this post


Link to post
Share on other sites

We leave this thread open for now, but make sure it will adhere to our forum rules. :) 

Jos


SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

Thank you Jos,

 

To clear any misunderstanding in my names of images searched, I am working on a deductions processing website as a side job. All parties are aware of automation.

One of the issues I experience isI search these 2 images in sequence to ensure I end on the SIS inquery tab and search.
 

If not Automation Scripts\SISInquiry.PNG then
    If Automation Scripts\PaymentInquiry.PNG then
        Automation Scripts\SISInquiry.PNG
    EndIf
EndIf

Automation Scripts\RegisterBotIt.au3" (56) : ==> Variable must be of type "Object".:

$bRet = $oBotIt.FindAndClick($sImgPath,    $Region, $bClick)
$bRet = $oBotIt^ ERROR


But it occassionally fails on the 2nd search with the error above, how can i detect that before it occurs, would IsObj Work?

 

My next question is what pattern could we use to compress the searched for image to a small set of coords and values to identify?

Edited by ScrapeYourself
spelling / wording

Share this post


Link to post
Share on other sites

You need to do much more error checking!
Means: When you call a function that creates an object make sure, the result is an object. Most of the time this is being done by implementing a COM error handler (see ObjEvent in the help file).

For examples check the Excel or Word UDF.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2020-09-05 - Version 1.5.1.1) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2020-06-27 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (NEW 2020-06-27 - Version 1.3.2.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
PowerPoint (2017-06-06 - Version 0.0.5.0) - Download - General Help & Support
Excel - Example Scripts - Wiki
Word - Wiki
Task Scheduler (2019-12-03 - Version 1.5.1.0) - Download - General Help & Support - Wiki

Tutorials:
ADO - Wiki, WebDriver - Wiki

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Aelc
      Hey there,
      I'm trying to create an DLL callback loop to get an updated screen (actually just 1 pic that should refresh because i already got a screencapturetool to get a pic from my game every sec)
      i want to bring that pic on a mobile phone. the dll can connect with the program i'm using to get the connection so that's fine.
      The prob is: it's my first DLL project so i don't even get 1 call or other returns of it. I tried much with the examples but i can't compare it that much with it.
      The calls shall be with c# where i'm not familiar with... i just searched much in forums and programsites but i didn't get a reference point.
      could someone have a tip to start please?
       
      there are calls like
      [DllImport("file.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] public static extern bool $funcname1(String identifier, String friendlyName, ref CbConext callback);
      [DllImport("file.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] public static extern bool $funcname2(String identifier, String friendlyName, ref logiArxCbContext callback, byte [] iconBitmap);
      [DllImport("file.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] public static extern bool $funcname3(String filePath, String fileName, String mimeType = "");
      tried something like
      $dll = DllOpen ("file.dll")
      $call = DllCall ( $dll,"bool","$funcname1","str","indetifier","str","test","int","CbContext callback" )
       
      or have i work with dllstructcreate or dllcallbackregister? 
      it would be enough for me if someone just could explain me how to get the imports with the params/funcs/types in autoit.
       
      i don't know if it's important but u shall call 
      public classes and public constants in c# before such as using.system make this sense?
       
      sry for my bad english 
      and thank you in advance
    • By DiegoCorradini
      Hi all,
      I have a problem to handle the controls of an application.
      Using AutoIT Windows Tool I can get only the Window (see Summary of the picture).
      Any tips to get the controls without knowing the name?
      (PS Using TestStack.White everything works, however I want the HIDE application feature of AutoIT). 
       
      Many thanks

    • By IgImAx
      Hi
       
      UPDATED Notes: ===============================================================================
      UPDATED: My main and second questions answered. Here the answers:
      To add/access WinMenuSelectItem you need to [Thanks to Fernando_Marinho]: Add AutoItX.Dotnet in Manage NuGet Packages Right Click in your Project -> Add -> Reference... -> COM ( Type Libraries )than, check the option AutoItX3 1.0 Type Library  using AutoItX3Lib; AutoItX3 au3 = new AutoItX3(); au3.WinMenuSelectItem("", ...) My full source code in C# exists in 11 posts in below. How to access those overloaded methods in AutoitX3 that are not accessible via above method!? Or how to fix AutoitX3 DLL Registration need in target computers without Autoit pre-installed on them!? Please check my post at 14 posts below!
      =============================================================================== Original Post:
       
       
      I was writing a small app in Autoit to close µTorrent app. It was working. Then I try to import AutoItX into C#, but unfortunately this method
      WinMenuSelectItem Couldn't find by IntelliSense and If I typed completely it still give me this message:
      Please check the image. I Google it and I found this QA at stackoverflow: Autoit error within C# application I saw they use this line:
      au = new AutoItX3Lib.AutoItX3Class(); I figure it how to add 'AutoItX3Lib' to project (by adding 'AutoItX3.dll' to reference) but again! When I use this line:
      var au = new AutoItX3Class(); I got this error message: Interop type 'AutoItX3Class' cannot be embedded. Use the applicable interface instead.
      My system info:
      Visual Studio 2017 Enterprise - v15.5.4
      X64 Windows 10 Enterprise 1607
      Thanks in advanced
      IgImAx

    • By JLogan3o13
      Not one usually to post non-AutoIt things, but as I have this question on StackExchange I thought I would throw it up here as well for any of our C# folks:
      I currently have an AutoIt GUI that calls a powershell script; the intent is to allow low-level technicians to batch create VMs in vSphere. Due to some changes in requirements from the customer, I am re-writing as a wpf app. The app itself is complete and working; this is more of a curiosity question.
      I have two methods attached to buttons on the GUI - one to pull all the data out of a listview and export to csv and another to do the reverse; importing from csv to the listview element. I wrote the export first, and went with manipulating the Excel application:
      private void Launch(object sender, RoutedEventArgs e) { Microsoft.Office.Interop.Excel.Application oExcel = new Microsoft.Office.Interop.Excel.Application(); oExcel.Visible = true; Microsoft.Office.Interop.Excel.Workbook oWorkBook = oExcel.Workbooks.Add(Microsoft.Office.Interop.Excel.XlSheetType.xlWorksheet); Microsoft.Office.Interop.Excel.Worksheet oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oExcel.ActiveSheet; int row = 2; //allow for header row int column = 1; oSheet.Cells[1, 1] = "Name"; oSheet.Cells[1, 2] = "CPU"; oSheet.Cells[1, 3] = "RAM"; oSheet.Cells[1, 4] = "IP Address"; oSheet.Cells[1, 5] = "Subnet Mask"; oSheet.Cells[1, 6] = "Port Group"; oSheet.Cells[1, 7] = "Default Gateway"; oSheet.Cells[1, 8] = "DNS"; oSheet.Cells[1, 9] = "Description"; oSheet.Cells[1, 10] = "Template"; oSheet.Cells[1, 11] = "Host"; oSheet.Cells[1, 12] = "Site"; oSheet.Cells[1, 13] = "Folder"; oSheet.Cells[1, 14] = "DataStore"; oSheet.Cells[1, 15] = "Patch Method"; oSheet.Cells[1, 16] = "HDD1Size"; oSheet.Cells[1, 17] = "HDD1Format"; oSheet.Cells[1, 18] = "HDD2Size"; oSheet.Cells[1, 19] = "HDD2Format"; oSheet.Cells[1, 20] = "HDD3Size"; oSheet.Cells[1, 21] = "HDD3Format"; oSheet.Cells[1, 22] = "HDD4Size"; oSheet.Cells[1, 23] = "HDD4Format"; oSheet.Cells[1, 24] = "HDD5Size"; oSheet.Cells[1, 25] = "HDD5Format"; foreach (var oVM in MyItems) { oSheet.Cells[row, column] = oVM.Name; oSheet.Cells[row, (column + 1)] = oVM.CPU; oSheet.Cells[row, (column + 2)] = oVM.RAM; oSheet.Cells[row, (column + 3)] = oVM.IP; oSheet.Cells[row, (column + 4)] = oVM.Subnet; oSheet.Cells[row, (column + 5)] = oVM.PortGroup; oSheet.Cells[row, (column + 6)] = oVM.Gateway; oSheet.Cells[row, (column + 7)] = oVM.DNS; oSheet.Cells[row, (column + 8)] = oVM.Description; oSheet.Cells[row, (column + 9)] = oVM.Template; oSheet.Cells[row, (column + 10)] = oVM.Host; oSheet.Cells[row, (column + 11)] = oVM.Site; oSheet.Cells[row, (column + 12)] = oVM.Folder; oSheet.Cells[row, (column + 13)] = oVM.Datastore; oSheet.Cells[row, (column + 14)] = oVM.Patch; oSheet.Cells[row, (column + 15)] = oVM.HDD1Size; oSheet.Cells[row, (column + 16)] = oVM.HDD1Format; oSheet.Cells[row, (column + 17)] = oVM.HDD2Size; oSheet.Cells[row, (column + 18)] = oVM.HDD2Format; oSheet.Cells[row, (column + 19)] = oVM.HDD3Size; oSheet.Cells[row, (column + 20)] = oVM.HDD3Format; oSheet.Cells[row, (column + 21)] = oVM.HDD4Size; oSheet.Cells[row, (column + 22)] = oVM.HDD4Format; oSheet.Cells[row, (column + 23)] = oVM.HDD5Size; oSheet.Cells[row, (column + 24)] = oVM.HDD5Format; row++; } oExcel.Application.ActiveWorkbook.SaveAs(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\example", 6); } It works, but it is slow. I have Excel set to visible for testing, and it is a good 6 or 7 seconds on a pretty high end box before the app even pops up.  It then takes another 2 seconds to populate 11 rows (this could be in the hundreds of rows at some point).
      I then wrote the code for the reverse, and decided to try a StreamReader object. The result, surprisingly, was almost immediate:
      OpenFileDialog xls = new OpenFileDialog(); xls.Multiselect = false; xls.Filter = "CSV files (*.csv)|*.csv"; xls.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); xls.ShowDialog(); string ins; if (xls.FileName != null) { FileStream srcFS; srcFS = new FileStream(xls.FileName, FileMode.Open); StreamReader srcSR = new StreamReader(srcFS, System.Text.Encoding.Default); do { ins = srcSR.ReadLine(); if (ins != null) { string[] parts = ins.Split(','); MyItems.Add(new MyItem { Name = parts[0], CPU = parts[1], RAM = parts[2], IP = parts[3], Subnet = parts[4], PortGroup = parts[5], Gateway = parts[6], DNS = parts[7], Description = parts[8], Template = parts[9], Host = parts[10], Site = parts[11], Folder = parts[12], Datastore = parts[13], Patch = parts[14], HDD1Size = parts[15], HDD1Format = parts[16], HDD2Size = parts[17], HDD2Format = parts[18], HDD3Size = parts[19], HDD3Format = parts[20], HDD4Size = parts[21], HDD4Format = parts[22], HDD5Size = parts[23], HDD5Format = parts[24] }); } } while (ins != null); srcSR.Close(); } }  
      So, I thought I would go back and change the export to use the same method:
      FileStream srcFS; srcFS = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\testingout.csv", FileMode.CreateNew, FileAccess.Write); StreamWriter srcWrt = new StreamWriter(srcFS, System.Text.Encoding.Default); StringBuilder header = new StringBuilder(); header.Append("Name").Append(',') .Append("CPU").Append(',') .Append("RAM").Append(',') .Append("IP Address").Append(',') .Append("Port Group").Append(',') .Append("Default Gateway").Append(',') .Append("DNS").Append(',') .Append("Description").Append(',') .Append("Template").Append(',') .Append("Host").Append(',') .Append("Site").Append(',') .Append("Folder").Append(',') .Append("Datastore").Append(',') .Append("Patch").Append(',') .Append("HDD1Size").Append(',') .Append("HDD1Format").Append(',') .Append("HDD2Size").Append(',') .Append("HDD2Format").Append(',') .Append("HDD3Size").Append(',') .Append("HDD3Format").Append(',') .Append("HDD4Size").Append(',') .Append("HDD4Format").Append(',') .Append("HDD5Size").Append(',') .Append("HDDFormat").Append(','); srcWrt.WriteLine(header); foreach (MyItem item in MyItems) { StringBuilder builder = new StringBuilder(); builder.Append(item.Name).Append(',') .Append(item.CPU).Append(',') .Append(item.RAM).Append(',') .Append(item.IP).Append(',') .Append(item.Subnet).Append(',') .Append(item.PortGroup).Append(',') .Append(item.Gateway).Append(',') .Append(item.DNS).Append(',') .Append(item.Description).Append(',') .Append(item.Template).Append(',') .Append(item.Host).Append(',') .Append(item.Site).Append(',') .Append(item.Folder).Append(',') .Append(item.Datastore).Append(',') .Append(item.Patch).Append(',') .Append(item.HDD1Size).Append(',') .Append(item.HDD1Format).Append(',') .Append(item.HDD2Size).Append(',') .Append(item.HDD2Format).Append(',') .Append(item.HDD3Size).Append(',') .Append(item.HDD3Format).Append(',') .Append(item.HDD4Size).Append(',') .Append(item.HDD4Format).Append(',') .Append(item.HDD5Size).Append(',') .Append(item.HDD5Format); srcWrt.WriteLine(builder); } MessageBox.Show("Task Complete"); What surprised me is this method is exponentially slower; on the order of 40 seconds to return the MsgBox. I also noticed that even though the loop is complete and shows the message, is seems the stream is still writing. If I open the file too quickly it shows that it is still in use by "Another User". So by the time the file is available to me it is actually closer to a minute for an 11-line csv.
      I'm just curious at the difference in speed read vs write using FileStream. Is it something I borked on implementation (eminently possible) or is this a known issue? If interacting with Excel is the way to go (not ideal) is there something I could do to shorten the initial lag?
    • By Luigi
      Greetings, someone can give a exemple, how send a error from a C#'s dll to AutoIt?
      I use this line, to send an error... but, I want get a error code In AutoIt with macro @error, it's possible?
       
      throw new ArgumentException("arquivo map não existe", "value" ); In this way, work, I know ther are error, but, @errror always is zero.
      I don't want this, I want a number as error code.
      Can you help me?
       
      Best regards
×
×
  • Create New...