C/C++ zu C# Convertieren

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von jvbsl.

    C/C++ zu C# Convertieren

    Hallo, :D

    ich hänge gerade an einer Methode aus C++, sie sieht wie folgt aus INT is_AllocImageMem (HIDS hf, INT width, INT height, INT bitspixel, char** ppcImgMem, INT* pid)
    die ich wie folgt übersetze, nun ist meine Frage ob ich das char** richtig eingebunden habe, denn char* ist/kann ein Byte[] sein oder StringBuilder oder ist das eine einfache Referenz

    C#-Quellcode

    1. /// <summary>
    2. /// <para>Allocates image memory</para>
    3. ///
    4. /// </summary>
    5. /// <param name="hf">Frame grabber handle</param>
    6. /// <param name="width">Width of image</param>
    7. /// <param name="height">Height of image</param>
    8. /// <param name="bitspixel">Color depth of image (bits per pixel)</param>
    9. /// <param name="ppcImgMem">Contains pointer to start of image memory</param>
    10. /// <param name="pid">Contains the ID for image memory</param>
    11. /// <returns>IS_SUCCESS, IS_NO_SUCCESS</returns>
    12. [DllImport(IMPORT, EntryPoint = "is_AllocImageMem")]
    13. public static unsafe extern int AllocImageMem(IntPtr hf, int width, int height, PixelFormat bitspixel, byte* ppcImgMem, ref int pid);

    Facebamm schrieb:

    char**
    ist in jedem Fale ein IntPtr, der dann zur Laufzeit entsprechend bestückt / ausgelesen werden muss.
    Gugst Du hier: Austausch von Daten zwischen einer VB.NET-exe und einer C-DLL, 32 und 64 Bit
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany das einzigste was du in dem Thread drinne stehen hast mit char** ist Auslesen dieses ANSI-Strings aus der DLL: GetStringAnsi(char** text) aber das brint mir nichts,
    ich verstehe nicht was nun char* ist, ist es byte[] oder StringBuilder und wie bekomme ich meinen IntPtr davon Oo

    @Snickbrack so mach ich das dock, die ganzen Funkionen habe ich schon in C++ als Driver, ich muss sie nur noch in C# übertragen
    Dateien
    • Falcon.cs

      (82,24 kB, 234 mal heruntergeladen, zuletzt: )
    das passendste für char** ist in C# sbyte**. Aber um das zu verwenden was am geschicktesten zu verwenden ist, muss man Wissen, was C++ damit macht. Es könnte auch ref sbyte* passend sein oder out sbyte*.
    Ist das ein Parameter der von innen gesetzt wird, oder ist es reiner Input?
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    @Facebamm Das mit dem IntPtr geht so:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Runtime.InteropServices;
    3. using System.Windows.Forms;
    4. namespace TestWin32Dll
    5. {
    6. public partial class Form1 : Form
    7. {
    8. public Form1()
    9. {
    10. InitializeComponent();
    11. }
    12. private void button1_Click(object sender, EventArgs e)
    13. {
    14. Dll.TestStruct st = new Dll.TestStruct(true);
    15. st.index = 1;
    16. st.flag = false;
    17. st.testValue = Dll.MyTestEnum.a2;
    18. dynamic txt = "bla bla bla";
    19. //st.text = "bla".ToCharArray(); // funktioniert nicht
    20. for (int i = 0; i < Math.Min(st.text.Length, txt.Length); i++)
    21. {
    22. st.text[i] = txt[i];
    23. }
    24. IntPtr p1 = Marshal.AllocHGlobal(Marshal.SizeOf(st));
    25. Marshal.StructureToPtr(st, p1, true);
    26. Dll.TestStruct st2 = (Dll.TestStruct)Marshal.PtrToStructure(p1, typeof(Dll.TestStruct));
    27. Marshal.FreeHGlobal(p1);
    28. MessageBox.Show(new string(st2.text), "Value from DLL");
    29. }
    30. }
    31. }

    C#-Quellcode

    1. using System;
    2. using System.Runtime.InteropServices;
    3. namespace TestWin32Dll
    4. {
    5. static class Dll
    6. {
    7. public enum MyTestEnum
    8. {
    9. a0,
    10. a1,
    11. a2,
    12. a3
    13. }
    14. [StructLayout(LayoutKind.Sequential)]
    15. public struct TestStruct
    16. {
    17. public int index;
    18. [MarshalAs(UnmanagedType.Bool, SizeConst = 4)] // C-BOOL nach C#-bool
    19. public bool flag;
    20. public MyTestEnum testValue;
    21. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    22. public char[] text;
    23. public TestStruct(bool xx)
    24. {
    25. index = 0;
    26. flag = false;
    27. testValue = MyTestEnum.a0;
    28. text = new char[256];
    29. }
    30. }
    31. }
    32. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich habe aus einem anderen Projekt folgenden Code gefunden

    C-Quellcode

    1. struct FalconImage
    2. {
    3. char * memory = 0;
    4. int imageId = 0;
    5. };
    6. ...
    7. // INT is_AllocImageMem (HIDS hf, INT width, INT height, INT bitspixel, char** ppcImgMem, INT* pid)
    8. is_AllocImageMem(handle, Width, Height, 24, &image.memory, &image.imageId)


    bedeutet also das ppcImgMem eine referenz ist?
    Wenn ja, was ist nun Char* - String, Char[], byte[], IntPtr, StringBuilder ... ich bin da etwas verwirrt stark verwirrt O0

    Edit: ich bin zum Fazit gekommen, das es ein Pointer zur Speicheradresse des Bildes ist und das eine Referenz zum Pointer erstellt wird, die dann mit dein Adresse des Bildes geschrieben wird
    oder bin ich da falsch?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Facebamm“ ()

    @Facebamm Ds ist korrekt.
    Initial muss der Pointer mit NULL belegt werden (das macht C++ nicht automatisch!).
    Wenn dann Speicher alloziiert wurde, kannst Du diese Variable mit dem Startpointer des Speichers belegen.
    Nach free muss diese Variable dann wieder genullt werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das muuss weder vorher noch nachher genullt werden. Vorher nicht, weil die variable hoffentlich von der Funktion überschrieben wird(bzw. Man einen Status zurück bekommt).
    Und am ende auch nicht. Das macht man eher wenn nicht ganz klar ist wann es sich um einen gültigen ptr handelt und wann nicht und macht dann das Debugging einfacher, mehr aber nicht.

    char* im allgemeinen kann in C# alles was du genannt hast sein, außer char[] da ein char in C# 16bit groß ist und in c(++) 8bit. Außerdem ist es in C(++) signed, weshalb sbyte[] besser passt als byte[], aber im Speicher steht dasselbe also ists egal.

    Also passt ref/out IntPtr oder ref/out byte* ziemlich gut.
    Nicht vergessen, dass C# pointer hat und es sich bei IntPtr um eine struct handelt, die gemarshallt werden muss, also gut overhead mitbringt.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    jvbsl schrieb:

    Das muuss weder vorher noch nachher genullt werden.
    Wenn der Zustand "Speicher alloziiert" anhand des Pointers abgefragt wird, schon. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Jetzt klappt alles wie es soll.

    Daher, das mir das zulange gedauert hatte, das Bitmap aus dem Speicher in ein PictureBox zu zeichnen, habe ich das ganze zu einem Control umgewandelt.

    Das ganze sieht jetzt so aus und kann rund 133 Bilder/sec was aber nicht ganz stimmt, denn da wo das bild herkommt, dort kommen nur 25 Bilder/sec her => ich greife ~5x auf ein bild in 1 Sekunde zu.
    CPU Belastung liegt bei 50% mit 3,4 Ghz und Ram bei ca 30% mit 8Gb (Debug und Remote-Debugger sind am Laufen).
    Im Release erhoffe ich mir natürlich mehr Leistung :D


    Und bitte fleißig meckern :P

    C#-Quellcode

    1. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2. private unsafe void CaptureVideo() {
    3. Stopwatch watch = new Stopwatch();
    4. GetPixelByteCount(WIDTH, HEIGHT, PixelFormat.RGB24, out int count, out int line);
    5. while(!_captureToken.IsCancellationRequested) {
    6. while(_captureEnable && (ErrorCodes)NativeMethods.FreezeVideo(_grapperHandle, (int)WaitMode.Wait) == ErrorCodes.SUCCESS) {
    7. stopwatch.Restart();
    8. SystemGDI.BitmapData bmpData = _videoImage.LockBits(_videoRect, SystemGDI.ImageLockMode.ReadWrite, SystemGDI.PixelFormat.Format24bppRgb);
    9. IntPtr bmpPtr = bmpData.Scan0;
    10. Kernel32.CopyMemory(bmpPtr, _image.Memory, (uint)count);
    11. byte* bmpMemPtr = (byte*) bmpPtr.ToPointer();
    12. for(int pos = 0; pos < count; pos += 1) {
    13. *(bmpMemPtr + pos) = (byte)(255 - *(bmpMemPtr + pos)); //invertieren
    14. }
    15. _videoImage.UnlockBits(bmpData);
    16. _captureEnable = false;
    17. stopwatch.Stop();
    18. Log.StdLog($"CaptureVideo {stopwatch.Elapsed.Milliseconds}ms");
    19. stopwatch.Restart();
    20. Invalidate();
    21. }
    22. }
    23. }
    24. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    25. private void GetPixelByteCount(int width, int height, PixelFormat pixelFormat, out int byteCount, out int byteLine) {
    26. int bitspixel = (int)pixelFormat;
    27. byteLine = width * ((bitspixel + 1) / 8);
    28. int lineMod = byteLine % 4;
    29. byteCount = lineMod == 0
    30. ? byteLine * height
    31. : (byteLine + (4 - lineMod)) * height;
    32. }
    33. ....
    34. protected override void OnPaint(PaintEventArgs e) {
    35. stopwatch.Stop();
    36. Log.StdLog($"Invalid-Call: {stopwatch.Elapsed.Milliseconds}ms");
    37. stopwatch.Restart();
    38. lock(_videoImage) {
    39. e.Graphics.DrawImage(_videoImage, Point.Empty);
    40. _captureEnable = true;
    41. }
    42. stopwatch.Stop();
    43. Log.StdLog($"Paint: {stopwatch.Elapsed.Milliseconds}ms");
    44. }
    Wie viele bytes ergeben denn einen pixel?
    Du könntest einen code machen, der die pixel auf long basis invertiert statt byte, da bekommste bestimmt einiges raus, parallelisierbar ists sogar auch.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    jvbsl schrieb:

    Wie viele bytes ergeben denn einen pixel?

    3 byte => 24 bits => 8 bit pro farbe => byte

    und ein long sind 64 bit => 8 byte

    jvbsl schrieb:

    long basis invertiert statt byte


    Wie meinst du das genau? Oo

    jvbsl schrieb:

    parallelisierbar ists sogar auch.


    Ja das stimmt.
    Also 255 - x wobei x E [0;255] ist ja äquivalent zu ~x. Einfach die bits invertieren. Deshalb kannst du einerseits einfach ~x verwenden und andererseits das ganze auch mit long machen.
    d.h. du verwendest statt byte* eben long* und machst ebenfalls ~x, jedoch hält ein long 2 2/3 Pixel. D.h. du musst am ende evtl noch was zusätzlich machen.
    Pseudo:

    C#-Quellcode

    1. int longCount = Math.DivRem(count, 8, out int rem);
    2. for (int i=0;i<longCount;i++,longPtr++)
    3. {
    4. *longPtr= ~(*longPtr);
    5. }
    6. //rest durchlaufen
    7. var bytePtr = (byte*)longPtr;
    8. for (int i=0;i<rem;i++,bytePtr++)
    9. {
    10. *bytePtr = ~(bytePtr);
    11. }
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    oha, den Operator ~ hatte ich komplett vergessen -.-

    Ich hab mir jetzt einfach ein Struct angelegt und lauf mit dem dann durch ;D

    C#-Quellcode

    1. [StructLayout(LayoutKind.Explicit)]
    2. public unsafe struct Pixel24Rgb {
    3. [FieldOffset(0)]
    4. public byte R;
    5. [FieldOffset(1)]
    6. public byte G;
    7. [FieldOffset(2)]
    8. public byte B;
    9. public static Pixel24Rgb operator ~(Pixel24Rgb pixel) {
    10. Pixel24Rgb tmpPixel = pixel;
    11. tmpPixel.R = (byte) ~pixel.R;
    12. tmpPixel.G = (byte) ~pixel.G;
    13. tmpPixel.B = (byte) ~pixel.B;
    14. return tmpPixel;
    15. }
    16. }


    und mein Ptr type genändert

    C#-Quellcode

    1. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2. public unsafe void InvertColors(in byte* bufferMemPtr) {
    3. _watch.Restart();
    4. Pixel24Rgb* intBufferMemPtr = (Pixel24Rgb*) bufferMemPtr;
    5. int structSize = sizeof(Pixel24Rgb);
    6. for(int pos = 0, n = _byteCount; pos < n; pos += structSize) {
    7. *(intBufferMemPtr + pos) = ~*(intBufferMemPtr + pos);
    8. }
    9. _watch.Stop();
    10. Log.StdLog($"InvertColors: {_watch.Elapsed.Milliseconds}ms");
    11. }


    Edit: ich sollte erst testen --- Geht noch nicht

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Facebamm“ ()

    Also diese struct ist zwar schön, aber für die perf bringt sie dir nivhts. Das mit long hat schon seinen Grund, schließlich hast du ~1/8 der invertier aufrufe und Sprünge, das ist einiges...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---