Entwickler-Ecke

Sonstiges (.NET) - Methoden mit Pointer in zur Laufzeit eingebunden Native-DLLs


Oliver M. - Mo 23.04.12 18:03
Titel: Methoden mit Pointer in zur Laufzeit eingebunden Native-DLLs
Hi,

ich möchte auf einige Funktionen in iTunesMobileDevice.dll aus C# heraus zugreifen. Je nach dem wo iTunes installiert wird, ist der Pfad von iTunesMobileDevice.dll anders, das heißt ich kann die DLL erst zu Laufzeit einbinden, wenn ich per Programmcode ermittelt habe, wo die DLL ist. Eine der Methoden der Dll ist wie folgt:

Quelltext
1:
AMDeviceNotificationSubscribe(DeviceNotificationCallback callback, uint unused1, uint unused2, uint unused3, out void* am_device_notification_ptr)                    

Meine Idee war es wie folgt zu lösen:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
static Type iTunesMobileDeviceType;
static object iTunesMobileDeviceInstance;

static KlassenName()
{
  AssemblyName name = new AssemblyName();
  name.Name = "iTunesMobileDevice" + Guid.NewGuid().ToString("N"); 
  AssemblyBuilder abuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
  ModuleBuilder mBuilder = abuilder.DefineDynamicModule("iTMDModule");
  TypeBuilder tBuilder = mBuilder.DefineType("iTMDClass"  + Guid.NewGuid().ToString( "N" ));
  MethodBuilder mebuilder = tBuilder.DefinePInvokeMethod("iTMDMethod", path, "AMDeviceNotificationSubscribe"
    MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
    CallingConventions.Standard, typeof(int), 
    new Type[] {typeof(DeviceRestoreNotificationCallback), typeof(uint), typeof(uint), typeof(uint), typeof(void*)}, 
    CallingConvention.StdCall, CharSet.Auto);
  iTunesMobileDeviceType = tBuilder.CreateType();
  iTunesMobileDeviceInstance = Activator.CreateInstance(iTunesMobileDeviceType);
}



public static unsafe int AMDeviceNotificationSubscribe(DeviceNotificationCallback callback, uint unused1, uint unused2, uint unused3, out void* am_device_notification_ptr)
{
  iTunesMobileDeviceType.InvokeMember("iTMDMethod", BindingFlags.InvokeMethod, null, iTunesMobileDeviceInstance, new object[] { callback, unused1, unused2, unused3, am_device_notification_ptr});
}


Das Problem dabei ist, dass ich in der zweitletzten Zeile bei new object[] { callback, unused1, unused2, unused3, am_device_notification_ptr} einen Fehler erhalte, da ich keinen Pointer (void*) in ein object konvertieren kann.

Hat jemand eine andere Idee, wie ich mein Problem lösen könnte?

Danke im Voraus und mfG,
Oliver


Ralf Jansen - Mo 23.04.12 18:32

Zitat:
Je nach dem wo iTunes installiert wird, ist der Pfad von iTunesMobileDevice.dll anders, das heißt ich kann die DLL erst zu Laufzeit einbinden

Wenn du selbst ein LoadLibrary der dll machst und im DllImportAttribute dann nur den dll Namen angibst, als "iTunesMobileDevice.dll", sollte das funktionieren. Oder übersehe ich warum du es dir so kompliziert machst?


Oliver M. - Mo 23.04.12 19:42

Entschuldigung, aber könntest du bitte genauer erläutern was ein LoadLibrary ist und wie es geht. Ich habe zwar schon davon gehört, aber ich weiß nicht wirklich, was das ist.
Das Problem beim DllImportAttribute ist, dass man ja eine Konstante angeben muss.


Ralf Jansen - Mo 23.04.12 20:48

Mit der LoadLibrary [http://pinvoke.net/default.aspx/kernel32/LoadLibrary.html] API Methode werden Dlls geladen. Das müsste das DllImportAttribute bei Pinvoke auch tun wenn eine Library abgefragt wird die noch nicht geladen wurde. Sobald eine Library geladen wurde muss diese nicht immer wieder von der Platte geladen werden sondern es wird einfach die im Speicher befindliche verwendet.
Du musst also dafür sorgen das vor dem ersten PInvokeaufruf bei dem du den richtigen Pfad nicht angeben kannst die Dll bereits im Speicher ist, eben per besagtem Aufruf von LoadLibrary, dann ist nicht relevant das du keinen gültigen Pfad angeben kannst da er nicht mehr gebraucht wird.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("Bibliothek.dll")]
static extern Int32 TestFunction(string parameter);

static void Main()
{
    LoadLibrary(@"C:\MeinLangerPfad\Bibliothek.dll");
    TestFunction("meineParameter");
}


Oliver M. - Di 24.04.12 16:55

Hi,

Vielen Dank. Dass das so einfach ist, hätte ich nicht gedacht.
Das einzige was irgendwie komisch ist, ist dass ich beim Aufruf von LoadLibrary(path + "iTunesMobileDevice.dll") ein Fenster erhalte, dass die „ASL.dll“ fehlt. Entweder binde ich diese per LoadLibrary() ebenfalls ein, dann fehlt eine andere DLL, oder ich setzte die Umgebungsvariable PATH auf den Pfad der DLLs, also Environment.SetEnvironmentVariable("PATH"@"C:\Program Files (x86)\Common Files\Apple\Apple Application Support");.
Aber jetzt läuft es, und das ist ja das wichtigste.

Nochmals vielen Dank,
Oliver