Julia如何调用C# dll动态链接库?


#1

我用Julia以MATLAB为中介调用C#的dll是成功的(using MATLAB; eval_string(“NET.addAssembly(fullfile(pwd, ‘drivers’, ‘visaDlls’, ‘visaLibFwk.dll’))”);),但是MATLAB要付费,所以换成以Python为中介。
Python用“pip install pythonnet”添加一个模块,即可调用C# dll,但是,在Julia环境下运行这些Python语句,却找不到动态链接库dll文件。
有没有办法解决?
或者有没有更好的、免费的方式调用C# dll?

import clr
clr.AddReference(‘Drivers/visaDlls/visaLibFwk’)
<System.Reflection.RuntimeAssembly object at 0x0000000002C7E588>

julia> using PyCall
julia> pyversion
v"3.7.3"

julia> py"""
import clr
print(clr.FindAssembly(‘serialLib.dll’))
clr.AddReference(‘Drivers/visaDlls/visaLibFwk’)
“”"
None
ERROR: PyError ($(Expr(:escape, :(ccall(#= C:\Users\Hao.julia\packages\PyCall\ttONZ\src\pyeval.jl:39 =# @pysym(:PyEval_EvalCode), PyPtr, (PyPtr, PyPt
r, PyPtr), o, globals, locals))))) <class ‘System.IO.FileNotFoundException’>
FileNotFoundException(“Unable to find assembly ‘Drivers/visaDlls/visaLibFwk’.”)
File “C:\Users\Hao.julia\packages\PyCall\ttONZ\src\pyeval.jl”, line 3, in
const Py_eval_input = 258

Stacktrace:
[1] pyerr_check at C:\Users\Hao.julia\packages\PyCall\ttONZ\src\exception.jl:60 [inlined]
[2] pyerr_check at C:\Users\Hao.julia\packages\PyCall\ttONZ\src\exception.jl:64 [inlined]
[3] macro expansion at C:\Users\Hao.julia\packages\PyCall\ttONZ\src\exception.jl:84 [inlined]
[4] pyeval_(::String, ::PyDict{String,PyObject,true}, ::PyDict{String,PyObject,true}, ::Int64, ::String) at C:\Users\Hao.julia\packages\PyCall\ttONZ
\src\pyeval.jl:39
[5] top-level scope at C:\Users\Hao.julia\packages\PyCall\ttONZ\src\pyeval.jl:232

julia> versioninfo()
Julia Version 1.0.4
Commit 38e9fb7f80 (2019-05-16 03:38 UTC)
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: Intel® Core™ i7-6700 CPU @ 3.40GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-6.0.0 (ORCJIT, skylake)

julia> using Pkg; Pkg.status()
Status C:\Users\Hao\.julia\environments\v1.0\Project.toml
[7a1cc6ca] FFTW v0.2.4
[28b8d3ca] GR v0.40.0
[10e44e05] MATLAB v0.7.3
[e0fc9d43] PkgMirrors v1.2.0 #master (https://mirrors.zju.edu.cn/julia/PkgMirrors.jl.git)
[91a5bcdd] Plots v0.25.2
[438e738f] PyCall v1.91.2
[8bb1440f] DelimitedFiles
[8f399da3] Libdl
[10745b16] Statistics


#2

导出个C的接口就行了。

Anything mentioned about how to do this from C is directly applicable for doing this in Julia.

C# 导出 C 的接口


#3

谢谢指导!
感觉链接里的方法比较难,没试成功;我还是用Python中转成功了。
之前报错是因为CLR识别路径错误,改成绝对路径就可以了。
using PyCall
pyclr = pyimport(“clr”)
pyclr.AddReference(“C:\Users\Hao\Documents\Julia\Drivers\serialLib”)
输出 PyObject <System.Reflection.RuntimeAssembly object at 0x000000002FA25160>
加载C# dll(串口驱动)成功!

还可以定义函数把C#的对象返回给Julia:
py"""
from serialLib import *
def PySerial(port):
UART = SerialConnection(port)
return UART
“”"
然后定义一个串口收发的宏:
macro pterm(str)
SerialIn = UART.SendRecvString(str, 100)
print(SerialIn)
return (SerialIn)
end
这样就可以连接串口,
UART = py"PySerial"(12)
PyObject <serialLib.SerialConnection object at 0x000000002FA25828>
敲串口命令了:
str = @pterm(“cat /proc/version\n”)
cat /proc/version
Linux version 4.1.21-WR8.0.0.14_standard (ecspens@esekilx5979) (gcc version 5.2.0 (Wind River Linux 5.2.0-8.0) ) #1 SMP PREEMPT Mon May 20 15:50:01 CEST 2019
root@hostname:~#


#4

“我调用FFI的FFI”?..


#5

如果不在意性能的话完全可以借助PowerShell,非常省事
使用Julia调用PS,格式化后用管道取回数据就行了,据我所知PS这边好像没有FFI


如果你的DLL是.NET Core的话那么也是跨平台的

— EDIT
看起来你的这个库和串口通信有关?如果是数据收发的话,可以考虑Julia和PS之间使用管道通信,应该不会有特别大的瓶颈,如果你觉得PS写不顺手的话你可以内嵌C#脚本然后Add-Type就可以生成编译后的程序集到内存里

Add-Type可以增加-PassThru参数,你就能拿到导入的程序集里的东西的元数据(反射)

PS C:\Users\Azure\Desktop\Simuro5v5> $asm=Add-Type -Path '.\V5RPC.dll' -PassThru                                        PS C:\Users\Azure\Desktop\Simuro5v5> $asm|Select-Object Name,Namespace                                                  
Name                     Namespace
----                     ---------
EmbeddedAttribute        Microsoft.CodeAnalysis
IsReadOnlyAttribute      System.Runtime.CompilerServices
IStrategy                V5RPC
StrategyClient           V5RPC
StrategyServer           V5RPC
V5Client                 V5RPC
V5Server                 V5RPC
V5PacketReadWrite        V5RPC
V5Packet                 V5RPC
APIReflection            V5RPC.Proto
[省略]

下面是使用管道进行二进制数据IPC的例子(匿名管道就更简单了,Julia可以直接read(::Cmd)

PowerShell的世界

PS C:\Users\Azure> $guid=New-Guid
PS C:\Users\Azure> $guid

Guid
----
e3610798-7734-47e8-b063-6c6a1b2dd4fa


PS C:\Users\Azure> $server=[System.IO.Pipes.NamedPipeServerStream]::new($guid)
PS C:\Users\Azure> $server.WaitForConnection()
PS C:\Users\Azure> $writer=[System.IO.StreamWriter]::new($server)
PS C:\Users\Azure> $writer.Write('Hello from M$FT world!')
PS C:\Users\Azure> $writer.Flush()
PS C:\Users\Azure> $server.Close()                                                                                      PS C:\Users\Azure>

Julia的世界

julia> data=read("\\\\.\\pipe\\e3610798-7734-47e8-b063-6c6a1b2dd4fa")
22-element Array{UInt8,1}:
 0x48
 0x65
 0x6c
 0x6c
 0x6f
 0x20
 0x66
 0x72
 0x6f
 0x6d
    ⋮
 0x24
 0x46
 0x54
 0x20
 0x77
 0x6f
 0x72
 0x6c
 0x64
 0x21

julia> println(String(data))
Hello from M$FT world!

julia>

管道名字推荐使用GUID生成,保证不重样(当然你要想办法把名字告诉Julia这边)。懒的话固定名字也可以

忘了说了,PowerShell Core开源免费(狗头)