Hallo,
Ich arbeite an eine Anwendung, die shared memory auslesen soll. Um das via Memory Mapped File zu machen, müssen viele aufrufe von kernel32.dll implementiert werden.
Hier ist eine der Funktionen (in VB):
Private Declare Sub CopyMemoryRead Lib "kernel32" Alias "RtlMoveMemory" ( _
pDst As Any, _
ByVal Src As Long, _
ByVal ByteLen As Long)
Wie kann man diesen Aufruf in C# umschreiben?
Mein versuch funktioniert leider nicht, da ich nicht weiß was man an stelle "As any" in C# nehmen soll????
[DllImport ("kernel32", SetLastError=true)]
public static extern void CopyMemoryRead (long Dst , long pSrc,long ByteLen);
Vielen Dank,
Zero_Base
@herbivore
Danke für die Antwort. Leider haben sie da keine implementirung für CopyMemoryRead 🙁
Zero_Base
Hallo Zero_Base,
da der Parameter, der "As Any" deklariert ist mit einem kleinen "p" am Anfang beginnt, würde ich drauf tippen, dass es ein Pointer ist. Von daher würd ich zuerst Mal IntPtr versuchen. Im Endeffekt ist das aber Glückssache obs funktioniert - fürs Marshalling gibts leider meist nur Beispiele auf dem "Hello World" - Level in der MSDN...
"It is not wise to be wise" - Sun Tzu
Ich glaube nicht, dass PtrInt nicht so passen wird, da ich an der stelle mein struct an die Funktion übergebe.
CopyMemoryRead (this.myData, myMBMMem, 1024);
public struct
{
string strName;
string strID;
string strDatum;
}
Please help....
Hallo Zero_Base,
ich habe auf pinvoke.net zwar in der Hoffnung verwiesen, dass du die Funktion direkt dort findest. Aber auch wenn das nicht der Fall ist, kannst du aus pinvoke.net großen Nutzen ziehen. Oft bekommen auch andere API-Funktionen die gleichen Parameter. Guck einfach mal ähnliche Funktionen durch. Ihc gehe davon aus, dass du mit ein bisschen Stöbern dein Problem lösen können müsstest.
herbivore
hat denn keiner meinen Link gesehen?
Mal ganz ernsthaft: Aus .NET heraus diese Funktion auszurufen macht überhaupt nur Sinn, wenn du bereits einen IntPtr hast, also unmanaged Speicher kopieren willst. Um wie bei dir managed Speicher in unmanaged Speicher zu kopieren reicht
Marshal.StructureToPtr()
aus und bewirkt völlig das gleiche (intern arbeitet dort auch CopyMem()).
Du musst übrigens die Struktur mit Layout-Attributen auszeichen und auf Strings musst du ebenfalls verzichten und stattdessen mit char-Arrys arbeiten, die auch noch mit MarshalAs.Size eine feste Länge bekommen müssen.
Zudem musst du natürlich die Speicherfreigabe beachten, also entweder "true" als letzten Parameter angeben (damit verschwindet aber dein Speicher automatisch beim nächsten Kopier-Aufruf, das ist nicht immer sinnvoll) oder per Hand mit Marshal.DestroyStructure freigeben.
Dann funzt das.
Vielen Dank an alle für die Antwort!!!
@Svenson
Du musst übrigens die Struktur mit Layout-Attributen auszeichen und auf Strings musst du ebenfalls verzichten und stattdessen mit char-Arrys arbeiten, die auch noch mit MarshalAs.Size eine feste Länge bekommen müssen.
kannst du mir bitte das vielleicht mit einem Beispiel erklären?
Zero_Base
[StructLayout(LayoutKind.Sequential,
Pack = 0, CharSet = CharSet.Unicode)]
public struct DISPLAY_DEVICE
{
public int cb;
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst=32)]
public char[] DeviceName;
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst=128)]
public char[] DeviceString;
public int StateFlags;
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst = 128)]
public char[] DeviceID;
[MarshalAs(
UnmanagedType.ByValArray,
SizeConst = 128)]
public char[] DeviceKey;
}
Hier eine ganz gute Hilfe zum Thema fürs nächste mal (daraus ist das Beispiel):
http://www.vsj.co.uk/articles/display.asp?id=501
Das Pack-Feld steuert das sogenannte Byte-Alignment. Wird dann u.U. wichtig, wenn du z.B. eine ungerade Zahl von Zeichen in einem Array hast. In dem Beispiel liegen alles Felder direkt hintereinander (ohne Füll-Bytes). Daher bieten sich grundätzlich durch 4 oder 8 teilbare Feldlängen an (32/64 Bit Systeme). Mit Pack 0 wird die System-Einstellung verwendet, die auch Windows verwendet. Nur bei C/C++-Libs muss man sich darum kümmern, wenn in den Compilereinstellungen eine davon abweichende Einstellung gemacht wurde.
@Svenson
danke sehr für die Antwort!!!!! 🙂
Wenn ich so ein stuct jetzt benutze, heißt es daß ich dann nicht mehr Marshal.StructureToPtr() brauche?
Zero_Base
Nein, damit der ganze Kram dient nur dazu, die Wandlung in unmanaged Speicher auszusteuern.
Es klappt aber trotzdem noch nicht.......... X(
[StructLayout(LayoutKind.Sequential,Pack = 1, CharSet = CharSet.Unicode)]
public struct MyData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=11)]
public char[] strName;
[MarshalAs( UnmanagedType.ByValArray,SizeConst = 16)]
public char[] strID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
public char[] strDatum;
}
IntPtr addressOfStructure1 = Marshal.AllocHGlobal(40);
CopyMemoryRead (Marshal.StructureToPtr(this.myData,this.addressOfStructure1,true), myMBMMem, 1024);
Dabei kriege ich ein Fehler: void kann nicht zu einem IntPtr konvertiert werden. Wie soll ich meine Structur in IntPtr umwandeln?
Vielen Dank in voraus,
Zero_Base
Marshal.StructureToPtr(this.myData,this.addressOfStructure1,true)
CopyMemoryRead (this.addressOfStructure1, myMBMMem, Marshal.SizeOf(typeof(MyData));
1024 als letzter Parameter wäre fatal. Du hast viel weniger Bytes zum kopieren, wenn du versuchst mehr zu kopieren hast du bestenfalls Speichermüll in myMBMMem, schlimmstenfalls schmiert die Anwendung mit einer Zugriffsverletzung weg.