brb*_*sby 5 dll powershell delegates interopservices
我有一个 DLL,导出了以下函数。
extern void Finalize(void (*WriteEntry)(const char* entry));
Run Code Online (Sandbox Code Playgroud)
我正在使用 P-Invoke 从 PowerShell 调用 DLL。
在 PowerShell 脚本中,我定义了一个函数,每当调用函数指针WriteEntry时都需要调用该函数。FinalizeWriteEntry
似乎正确的方法是围绕WriteEntryPowerShell 函数创建一个 C 风格的包装器,其中包装器Finalize作为函数指针传递到其中。
经过一些调查后,我发现可以创建一个可以与非托管代码互操作的委托(请参阅如何将函数指针从 C# 传递到 C++ Dll?)。我创建了以下CallbackDelegate类型。我能够将它从 C# 代码传递到 DLL。现在,我需要一种方法让 PowerShell 应用程序能够构造委托并将其传递给 DLL。
$delegateTypeDefinition = @'
[System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
public delegate void CallbackDelegate([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)] string entry);
'@
Run Code Online (Sandbox Code Playgroud)
我不确定如何将 CallbackDelegate 委托包装在WriteEntryPowerShell 函数中。
因此,我认为需要回答的问题是,我们如何从 PowerShell 函数构造委托。如果事实证明这是一个 XY 问题,我希望我已经提供了足够的细节来指出正确的方向。
不幸的是,我不相信你可以单独使用 PowerShell 来完成你所要求的事情,至少不能跳过一系列的步骤来创建一个继承它的类MulticastDelegate,然后尝试注册它。PowerShell 没有与delegate关键字等效的关键字来轻松定义它。
我们可以定义 C# 源来执行此操作,并最终从 PowerShell 本身执行调用。我们已经需要P/Invoke从 PowerShell 进行此操作,因此我们将仅保留delegate以 C# 形式提供的定义。
C# 中的Adelegate在功能上等同于 C++ 中的回调(无双关语)。AMethod可以用作delegate. AnAction可以用作delegate. AFunc可以用作delegate. 从本质上讲,adelegate是某种形式的可执行代码块。那么这如何转化为 PowerShell 呢?
PowerShell 代码将使用 aScriptBlock {}来定义可执行代码块。它们经常使用,从函数定义到类的方法定义,再到循环构造等等。AScriptBlock甚至可以使用 call 运算符单独使用和执行&。A只是一个未命名函数ScriptBlock的别名。由于 a是一个函数,我们可以使用它作为委托值。ScriptBlock
这里的关键是ScriptBlock需要转换为您的delegate类型。当我们这样做时,让我们用 using 语句来修复那满嘴的限定类型名称
注意:如果您的 C# 代码是在源文件中定义的,您可以使用
Get-Content -Raw. 如果它已经编译成 DLL,您可以跳过该部分并使用Add-Type提供 DLL 的路径。
$delegateTypeDefinition = @"
using System.Runtime.InteropServices;
# Here is the callback delegate you provided
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackDelegate([MarshalAs(UnmanagedType.LPTStr)] string entry);
public static class DelegateHelper
{
# Use your actual DLL
[DllImport("DllName.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
public static extern void Finalize(CallbackDelegate del);
}
"@
# Compile your C# code
Add-Type $delegateTypeDefinition
# Define your delegate function with the correct parameters
[CallbackDelegate]$callbackDelegate = {
Param(
[string]$entry
)
# Your callback code here
}
Run Code Online (Sandbox Code Playgroud)
通常,您随后会调用$callbackDelegate.Invoke("some string")来运行
C# 定义的委托函数。但既然您想将其传递给Finalize,我们就会这样做。
注意:这就是为什么我们把它放在
DllImport一个类的内部。它不必定义为静态类或成员,但导入的P/Invoke函数必须像方法一样在类中定义。
# Call Finalize
[DelegateHelper]::Finalize($callbackDelegate)
Run Code Online (Sandbox Code Playgroud)
理论上,这应该适用于传递回调。
也就是说,delegate类型,特别是在访问具有delegate类型的成员时,在 PowerShell 中可能表现得有些奇怪。此外,我没有或不知道本地 DLL 来自行测试。我只能保证$callbackDelegate.Invoke("some value")只要设置将 a 分配ScriptBlock给delegate类型并调用它就可以工作。
如果您遇到更多问题,或者在您的用例中我上面提供的内容存在“问题”,那么您说您可以在 C# 中使用此功能。您可能需要考虑完全用 C# 实现这一部分,同时在帮助程序类上另外创建一个公共帮助程序函数以获取字符串entry并Finalize在 C# 代码中运行。用于Add-Type从脚本编译源代码或加载预编译的 DLL。从那里,您可以在 PowerShell 中运行辅助函数来执行该Finalize函数。这有点逃避,但delegate类型是 PowerShell 有时难以使用的一个领域。
| 归档时间: |
|
| 查看次数: |
811 次 |
| 最近记录: |