1

我喜欢使用 G1ANT 的“宏”功能来调用非托管代码,但非托管对象当然不会被自动垃圾收集,没有代码来执行此操作。

我的请求专门针对在这些 G1ANT C# 宏中处理非托管代码的最佳实践,而不是在 C# 中处理相同的代码,也不是修复以下代码的请求,它运行得很好。

如果我使用 Visual Studio 在 C# 中进行编码,我可能会使用 System.Runtime.InteropServices.SafeHandle 类,覆盖 Finalize 方法,或使用其他常用方法之一(另请参阅这篇关于在C#)。

但是这些方法似乎都不适合 G1ANT 宏本身,至少以我的新手经验来看。

出于说明目的,我指的是这个 G1ANT 代码,但没有宏 ( ) 中的最后一行ahk.Reset(),因为它在该行中运行良好,不止一次。(我痛苦地意识到必须有一个更好的例子,但由于我是 G1ANT 的新手,这是我目前唯一拥有的东西。)我所追求的是在 G1ANT 中工作的 C#代码未明确处置非托管对象:

addon core version 4.100.19170.929
addon language version 4.100.19170.929
-dialog ♥macrodlls
♥macrodlls = System.dll,System.Drawing.dll,System.Windows.Forms.dll,AutoHotkey.Interop.dll,System.Runtime.InteropServices.dll
-dialog ♥macrodlls
♥macronamespaces = System,AutoHotkey.Interop,System.Windows.Forms
⊂
var ahk = AutoHotkeyEngine.Instance;
//Load a library or exec scripts in a file
ahk.LoadFile("functions.ahk");

//execute a specific function (found in functions.ahk), with 2 parameters
ahk.ExecFunction("MyFunction", "Hello", "World");

string sayHelloFunction = "SayHello(name) \r\n { \r\n MsgBox, Hello %name% \r\n return \r\n }";
ahk.ExecRaw(sayHelloFunction);

//execute's newly made function\
ahk.ExecRaw(@"SayHello(""Mario"") ");

var add5Results = ahk.ExecFunction("Add5", "5");
MessageBox.Show("ExecFunction: Result of 5 with Add5 func is" + add5Results);
addon core version 4.100.19170.929
addon language version 4.100.19170.929
-dialog ♥macrodlls
♥macrodlls = System.dll,System.Drawing.dll,System.Windows.Forms.dll,AutoHotkey.Interop.dll,System.Runtime.InteropServices.dll,System.Reflection.dll,Microsoft.CSharp.dll
-dialog ♥macrodlls
♥macronamespaces = System,AutoHotkey.Interop,System.Windows.Forms,System.Reflection
⊂
var ahk = AutoHotkeyEngine.Instance;
//Load a library or exec scripts in a file
ahk.LoadFile("functions.ahk");

//execute a specific function (found in functions.ahk), with 2 parameters
ahk.ExecFunction("MyFunction", "Hello", "World");

string sayHelloFunction = "SayHello(name) \r\n { \r\n MsgBox, Hello %name% \r\n return \r\n }";
ahk.ExecRaw(sayHelloFunction);

//executes new function
ahk.ExecRaw(@"SayHello(""Mario"") ");

var add5Results = ahk.ExecFunction("Add5", "5");
MessageBox.Show("ExecFunction: Result of 5 with Add5 func is" + add5Results);
ahk.Reset();
⊃
⊃

它几乎是从AutoHotkey.Interop github 页面逐字记录的。

没有宏中的最后一行('ahk.Reset()),代码第一次运行完美,但在第二次运行时,G1ANT 仍然看到包含的 AutoHotkey 文件,并警告重复的函数定义,但继续运行并且仍然有效适当地。as-far-as-I-can-tell-undocumented AutoHotkey.Interop 命令Reset()通过调用处理垃圾收集问题

        public void Terminate()
        {
                AutoHotkeyDll.ahkTerminate(1000);
        }

        public void Reset() {
                Terminate();
                AutoHotkeyDll.ahkReload();
                AutoHotkeyDll.ahktextdll("", "", "");
        }

因此,即使没有 , AutoHotkeyEngine 实例本身似乎也已被垃圾回收ahk.Reset();,但它加载到对象中的 AutoHotkey 脚本却不是。

停止 G1ANT.Robot 应用程序并重新启动,然后重新加载上面的脚本(如前所述,没有行ahk.Reset();,工作正常,但再次仅用于单次运行。

编辑:给定答案关于单例处理的建议是我以后在加载 AutoHotkey 函数脚本和 DLL 本身时将使用的。检查 DLL 或函数文件是否已加载,是否存在问题,这似乎是一种谨慎且良好的做法。“一盎司的预防”等。此外,我在这里分叉了 AutoHotkey.Interop 存储库,添加了一个布尔检查以查看 AutoHotkeyEngine 实例是否已准备好。

此致,

burque505

4

1 回答 1

3

你使用AutoHotkeyEngine.Instance,所以我猜它是一个单例。只要相应的 dll 保存在内存中,它就会一直加载在内存中,并且只要其域存在,后者就会被加载并存在。宏应用程序域(放置脚本内容的地方)当前与 Robot 的应用程序域一样长,因此实际上您的单例实例与 Robot 一样长。任何一个:

  • 不要使用单例,
  • 或在获得实例后立即重置它(有点像你已经做过的),
  • 或将其视为寿命比您的应用程序更长的单例。在这种情况下,在获得单例实例后,请检查您的函数文件是否已加载,并且仅在尚未加载时才加载它。
于 2019-07-15T10:54:05.263 回答