Jump to content

How generate a error code from C# dll to macro @error in AutoIt?

Recommended Posts


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

Visit my repository

Share this post

Link to post
Share on other sites

@Jos, thank you for reply, this is the code:

Obs: this is not game automation, this is my game writed in AutoIt.


I want re-write some code in C#/dll.


Global Const $sNameSpace = "Borius"
Global Const $sClass = "Engine"
Global Const $BORIUS_DLL = """" & @ScriptDir & "\borius.dll"""
ConsoleWrite($BORIUS_DLL & @LF)
Global Const $REGASM = "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe"
;~ RunWait($REGASM & " /unregister " & $BORIUS_DLL, @ScriptDir, @SW_HIDE)

;~ Global $PID = RunWait($REGASM & " /register /codebase /tlb " & $BORIUS_DLL, @ScriptDir, @SW_HIDE)
;~ Global $PID = RunWait($REGASM & "  /codebase " & $BORIUS_DLL, @ScriptDir, @SW_HIDE)
Global $PID = Run(@ComSpec & " /c " & $REGASM & " /register /codebase /tlb " & $BORIUS_DLL, @ScriptDir,  @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD + $STDERR_CHILD + $STDERR_MERGED)

Local $sOutput = StdoutRead($PID)
ConsoleWrite($sOutput & @LF)

Global $wer = ObjCreate($sNameSpace & "." & $sClass)
If @error Or Not IsObj($wer) Then
    Local $sOutput = StdoutRead($PID)
    ConsoleWrite($sOutput & @LF)
    ConsoleWrite($sNameSpace & "." & $sClass & " @error[" & @error & "]" & @LF)
    ConsoleWrite($sNameSpace & "." & $sClass & " @ok" & @LF)

The dll:

 * Criado por SharpDevelop.
 * Usuário: master
 * Data: 14/09/2017
 * Hora: 18:21
 * Para alterar este modelo use Ferramentas | Opções | Codificação | Editar Cabeçalhos Padrão.
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Web.Script.Serialization;
using System.Text.RegularExpressions;

namespace borius{
    /// <summary>
    /// Description of MyClass.
    /// </summary>
    public class Engine{
    private string _map;
    private int height;
    //private int layers;
    private int nextobjectid;
    private string orientation;
    //private int properties;
    //private int propertytypes;
    private int renderorder;
    private int tiledversion;
    private int tileheight;
    //private int tilesets;
    private int tilewidth;
    private string type;
    private int version;
    private int width;
        dynamic json;
        public string map{
            get{ return _map; }
                value = value.Replace("\\", "\\\\");
                if( !File.Exists(value) ){
                    throw new ArgumentException("arquivo map não existe", "value" );
                JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
                using (StreamReader r = new StreamReader(value)) {
                    string str = r.ReadToEnd();
                    json = serializer.DeserializeObject(str);
                _map = value;

        public void _map_build(){
            foreach (KeyValuePair<string, object> entry in json){
                var key = entry.Key;
                switch( key ){
                    case "height" :
                        height = Int32.Parse(entry.Value as string);
                    case "layers" :
                    case "nextobjectid" :
                        nextobjectid = Int32.Parse(entry.Value as string);
                    case "orientation" : 
                    case "properties" : 
                    case "propertytypes" : 
                    case "renderorder" : 
                    case "tiledversion" :
                    case "tileheight" :
                        tileheight = Int32.Parse(entry.Value as string);
                    case "tilesets" : 
                    case "tilewidth" : 
                        tilewidth = Int32.Parse(entry.Value as string);
                    case "type" :
                    case "version" :
                        version = Int32.Parse(entry.Value as string);
                    case "width" :
                        width = Int32.Parse(entry.Value as string);

                var value = entry.Value as string;
                Console.WriteLine(String.Format("{0} : {1}",key, value));


Visit my repository

Share this post

Link to post
Share on other sites

Instead of a void dll function, make it return an int to AutoIt containing a status code, e.g., 0=success, 1-n = various error codes. Capture this in your dllcall from autoit ($return=DllCall(...), $myErrorCode=$return[0]), and use SetError to fill the @error macro). Letting your dll write to console and AutoIt capturing that seems needlessly circuitous (and potentially error-prone), since dllcalls are designed to return information to the caller.

Share this post

Link to post
Share on other sites

Thank you for your reply @RTFC, but I thinking dll writed in C++, you work like you say.

I my opinion, dll writed in C#, work throug COM (componente object model), see this:


Any "throw new xxxxxx" break the script, and not set AutoIt's @error.

Your way is smart, but I still unknow hos set @error code.

If I wrong, apologize-me, it's new for me.

Edited by Luigi

Visit my repository

Share this post

Link to post
Share on other sites

Luigi, You are right. C# code is managed .NET code and a C# DLL-file is a .NET assembly DLL-file and can as such not be used by DllCall. DllCall can be used to call functions implemented in unmanaged code in conventional DLL-files like the DLL-files in the Windows operating system that implements Windows API functions.

C# is an object oriented language and everything is done through objects, properties and methods. To call a method in a C# DLL-file you create an object and executes the object method.

A general and easy way to set the @error macro when an error occurs in C# code is demonstrated in this pseudocode (cannot be run):

// Use a global variable and a separate
// function to pass an error code to AutoIt.

using System;
class Au3Class {
  int iErrorCode = 0;

  public int GetErrorCode() {
    return iErrorCode;

  public void Method1() {
    iErrorCode = 0; // Initialize iErrorCode
    Console.WriteLine( "Method1 without errors" );

  public void Method2() {
    iErrorCode = 0; // Initialize iErrorCode
    Console.WriteLine( "Method2 with an error" );
    iErrorCode = 1; // Set iErrorCode on error
If @error Then
  ConsoleWrite( "@error = " & @error & @CRLF )
  Exit ; Exit on error

Func Example()
  Local $iError

  $oAu3Class.Method1() ; Call the actual method
  $iError = $oAu3Class.GetErrorCode() ; Check error code
  If $iError Then Return SetError( $iError, 0, -1 )
  ; No errors, continue Example()
  ConsoleWrite( "No Errors" & @CRLF & @CRLF )

  $oAu3Class.Method2() ; Call the actual method
  $iError = $oAu3Class.GetErrorCode() ; Check error code
  If $iError Then Return SetError( $iError, 0, -1 )
  ; No errors, continue Example()
  ConsoleWrite( "No Errors" & @CRLF & @CRLF )


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

  • Similar Content

    • IgImAx
      By IgImAx
      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

    • JLogan3o13
      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?
    • Earthshine
      By Earthshine
      This baby can do almost any language! I found Gleany on this site and set it up on a fresh win10 install. all i would need to do to make it build an exe of the search files app we discovered is the .NET Target Framework download to build 100 % but the exe works and generates! You also need to add the path the the version of csc.exe that you want to run. MSBuild is part of .NET and can read your .csproj file.
      YOU can develop .NET OR C/C++ on this baby!
      Super lightweight (fit for crappy laptops), and you can use any dev compilers you wish, Ming, MS, etc, whatever.
      To use the build, you need to open the csproj file, else, to check your syntax it can compile individual files as well. The warning are because I do not have the .NET 4.6 Targeting Pack installed... LOL, and I could get rid of the Core warning, yes, I did not want to build a .NET Core.dll I wanted a live x64 exe! Told you MSBUILD could handle .CSPROJ, .VBPROJ, and all others Microsoft. Don't let Visual Code or Visual Studio slow you down, although, this works with Visual Code as well but there is only debugging in CORE.DLL projects

      ListFiles Example.zip

    • nss
      By nss
      Hi all,
      I am making a program in which I use Bass audio library (with the wrapper for autoit that I found here on forums I think) because of its support for dx effects.
      My problem, though, is that when effects as reverb or echo/delay are added, the channel length is not extended as to fit the tail of the effect, so if the file was really short, you wouldn't even hear the reverb at all.
      I've tried setting the  buffer parameter even to 60k ms, updating the channel length to 60k ms, but nothing makes it so that the effects aren't being cut off.
      I've heard that I could add silence manually to wave files by adding the chr(0) characters, but haven't had any luck doing that, either.
      What I'm doing:
      initialize bass use streamCreateFile to load the wave file with the fx flag and length parameter set to 60000 set the config buffer to 60000 use channel set fx to add dx8 reverb use channel play to play the sound use bass update to update the length to 60000  
      I even tried having only silence in one wave file and tried joining two wave files together, but that didn't work either.
      Any help would be very much appreciated.
    • breakbadsp
      By breakbadsp
      AutoIT AU3info doeas not detect all gui objects uniquely for .NET GUIs developed in C#.
      this is not working now i am using COM windows approach for this, But its very difficult.
      Please let me know if anyone has done it before.

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.