2015-10-16 12 views
7

Ho costruito un C# DLL (MyTestDll) utilizzando il pacchetto NuGet UnmanagedExports:Caricamento C# DLL con le esportazioni non gestiti Into Python

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

lo uso da Python tramite ctypes DLL importazione:

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

È solo una fantasia, funziona.

Poi, ho aggiunto un altro DLL (NoSenseDll):

namespace NoSenseDll 
{ 
    public class NoSenseClass 
    { 
     public static int Sum(int a, int b) 
     { 
      return a + b; 
     } 
    } 
} 

ho iniziato ad usare questo NoSenseDll per implementare MyTestDll:

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

Purtroppo, non funziona. Python dice:

WindowsError: [Error -532462766] Windows Error 0xE043435 

ho cercato di aggiungere C:\\Temp\\Test al percorso, ma che non ha aiutato.


Ho scritto un 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; 
} 

Esso funziona se il secondo DLL (NoSenseDll) si trova nella stessa cartella del file eseguibile C++. Non funziona se aggiungo semplicemente la cartella NoSenseDll a PATH.

+0

* Ho provato ad aggiungere 'C: \\ Temp \\ Test' al percorso, ma questo non ha aiutato. * Hai davvero usato i doppi backslash? Forse potrebbe essere il problema. Tiravo a indovinare. – Palec

+0

Ho fatto del mio meglio per modificare le tue domande e risposte per essere più facilmente comprensibile, e ho risolto NoSen * c * eDll su NoSen * s * eDll. Grazie per l'impegno profuso in questa sessione di domande e risposte! – Palec

risposta

4

Progetto soluzione:

  1. Copia NoSenseDll alla cartella di Python, nel mio caso %HOMEPATH%\Anaconda.
  2. Riavvia IPython/Spyder.

soluzione finale:

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

Nota finale:

Se non è possibile utilizzare IronPython a causa di matplotlib o panda,
se non è possibile utilizzare python.net a causa di IPython o spyder,
se non si desidera utilizzare COM Interop solo perché,
e si è reali voglio che C# e Python lavorino insieme, usare la soluzione sopra e il riflesso C#.

+0

puoi per favore indicare problemi da pythonnet in ipython o spyder? – denfromufa

2

È inoltre possibile controllare Costura.Fody.

Questa è un'attività di compilazione che aggiungerà le dipendenze come risorse all'assieme e persino aggancia un inizializzatore del modulo per caricarle in fase di runtime.

+0

puoi fornire un esempio per questo caso? Quanto è diverso questo dalle tue esportazioni non gestite? – denfromufa

+1

Continueresti a utilizzare il mio pacchetto, ma con Costura, le tue dipendenze vengono aggiunte come risorse nell'assembly. Costura aggiunge ganci per caricarli da lì. –