使用非托管导出将C#DLL加载到Python中

Dmi*_*try 7 .net c# python dll unmanaged

我使用NuGet包UnmanagedExports构建了一个C#DLL(MyTestDll):

[DllExport("Test", CallingConvention = CallingConvention.Cdecl)]
public static string Test(string name)
{
    return "hi " + name + "!";
}
Run Code Online (Sandbox Code Playgroud)

我通过ctypes DLL导入Python使用它:

path = "C:\\Temp\\Test"
os.chdir(path)
dll = ctypes.WinDLL("MyTestDll.dll")
f = dll.Test
f.restype = ctypes.c_char_p
print f('qqq')
Run Code Online (Sandbox Code Playgroud)

这只是一种幻想,它有效.

然后,我又添加了一个DLL(NoSenseDll):

namespace NoSenseDll
{
    public class NoSenseClass
    {
        public static int Sum(int a, int b)
        {
            return a + b;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我开始使用这个NoSenseDll来实现MyTestDll:

[DllExport("Test", CallingConvention = CallingConvention.Cdecl)]
public static string Test(string name)
{
    return NoSenseDll.NoSenseClass.Sum(4, 5).ToString();
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,它不起作用.Python说:

WindowsError: [Error -532462766] Windows Error 0xE043435
Run Code Online (Sandbox Code Playgroud)

我试图添加C:\\Temp\\Test到路径,但这没有帮助.


我写了一个C++测试:

#include "stdafx.h"
#include "windows.h"
#include <iostream>
#include <string>
#include "WinBase.h"

typedef char*(__stdcall *f_funci)(const char*);

int _tmain(int argc, _TCHAR* argv[])
{
    int t;
    std::string s = "C:\\Temp\\Test\\MyTestDll.dll";
    HINSTANCE hGetProcIDDLL = LoadLibrary(std::wstring(s.begin(), s.end()).c_str());

    f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "Test");

    std::cout << "funci() returned " << funci(std::string("qqq").c_str()) << std::endl;
    std::cin >> t;
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

如果第二个DLL(NoSenseDll)与C++可执行文件位于同一文件夹中,则它可以正常工作.如果我只是将NoSenseDll文件夹添加到PATH,它就不起作用.

Dmi*_*try 4

解决方案草案:

\n\n
    \n
  1. 将NoSenseDll复制到Python的文件夹中,在我的例子中是%HOMEPATH%\\Anaconda
  2. \n
  3. 重新启动 IPython/Spyder。
  4. \n
\n\n
\n\n

最终解决方案:

\n\n
static MyTestDllClass() // static constructor\n{\n    AppDomain currentDomain = AppDomain.CurrentDomain;\n    currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);\n}\nstatic Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)\n{\n    string folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n    string assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");\n    if (File.Exists(assemblyPath) == false) return null;\n    Assembly assembly = Assembly.LoadFrom(assemblyPath);\n    return assembly;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后说明:

\n\n

如果你因为 matplotlib 或 pandas 而不能使用 IronPython,如果
你因为 IPython 或间谍程序而不能使用 python.net,如果
你不想使用 xe2x80x99 COM Interop 只是因为,
\n并且您确实想让 C# 和 Python 一起工作,请使用上面的解决方案和 C# 反射。

\n