Re: Communicating native C structs with managed code

Ivo Smits <[email protected]> Sat, 6 Jan 2018 21:15:53 +0100
Newsgroups gmane.comp.gnome.mono.devel
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--===============1715578260771353598==
Content-Type: multipart/alternative;
 boundary="------------FB5D0FE3265B8DB38C421570"
Content-Language: en-US

This is a multi-part message in MIME format.
--------------FB5D0FE3265B8DB38C421570
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit

Hi Ramin,

You can pass native pointers between C and C# using the IntPtr, void* or 
S1* (where S1 is the struct defined below) in P/Invoke calls. You can 
pass a struct to a P/Invoke using the ref modifier, which will, whenever 
possible, also pass a pointer to the struct. You can pass a native 
pointer from C to a ref parameter in a C# function. To use native 
pointers, you have to mark the affected code block as unsafe. For example:

[StructLayout(LayoutKind.Sequential)]
unsafe struct S1 {
     public double x;
     public double y;
     public Int64 z;
     public fixed int arr[256];
};

The unsafe keyword marks the structure as unsafe - it can only contain 
types which do not need marshalling. StructLayout can be used to specify 
the alignment options, usually the default works. StructLayout.Explicit 
and the FieldOffset attribute can be used to place fields at arbitrary 
offsets, for example to create "unions".

The fixed (int) defines an inline array which behaves like a pointer 
(like it would in C). This array can not be used as a regular array, but 
its members can be accessed using an index. There's no bounds checking.

You can then pass the struct to an external C function using one of the 
following options:
class Test {
       [DllImport("native.so")]
       public static extern void nativemethod1(ref S1 arg);
       [DllImport("native.so")]
       public static extern void nativemethod2(S1* arg);
       [DllImport("native.so")]
       public static extern void nativemethod3(void* arg);
       [DllImport("native.so")]
       public static extern void nativemethod4(IntPtr arg);

     unsafe void Test() {
       S1 s = new S1();
       nativemethod1(ref s);
       nativemethod2(&s); //only works because we're in an unsafe block 
and the struct is marked unsafe
       nativemethod3(&s);
       nativemethod4((IntPtr)(&s));
     }
}

The other way around works as well, for example:
class Test {
       [DllImport("native.so")]
       public static extern S1* nativemethod1();
       [DllImport("native.so")]
       public static extern IntPtr nativemethod3();

     unsafe void Test() {
       S1* s = nativemethod1();
       s = (S1*)nativemethod3(); //cast if you used an IntPtr
       s->x = 6; //the structure can now be modified directly. Make sure 
it's not released in the native code...
     }
}

--
Ivo


Op 5-1-2018 om 10:59 schreef R Zaghi:
> Hi
>
> What would be the most performance efficient method to pass a native C 
> struct of primitive data types (memory aligned or compact) to the 
> managed code in Mono/C# and allow modification of its member variables 
> in the managed code?
>
> Do we have anything specific in Mono that helps eliminate manual 
> marshalling on every call? or could we? :)
>
> Say, in the following scenarios:
>
> struct S1 {
> double x,
> double y,
> double z
> };
>
> Or
>
> struct S2 {
> int arr[256]
> };
>
> Or
>
> struct S3 {
> double x,
> int arr[256]
> };
>
>
>
> Ramin
>
>
>
> -- 
>
>
>
> Ramin Zaghi
>
> *Mosaic3DX™ | User Interface Technology*
> St John's Innovation Centre,
> Cowley Road,
> Cambridge,
> CB4 0WS, UK*
> *
> *E*:**[email protected] <mailto:[email protected]>
> *T*: +44 1223 421 311
> http://linkedin.com/in/raminzaghi
>
>
>
> _______________________________________________
> Mono-devel-list mailing list
> [email protected]
> http://lists.dot.net/mailman/listinfo/mono-devel-list


--------------FB5D0FE3265B8DB38C421570
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 8bit

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Hi Ramin,</p>
    <p>You can pass native pointers between C and C# using the IntPtr,
      void* or S1* (where S1 is the struct defined below) in P/Invoke
      calls. You can pass a struct to a P/Invoke using the ref modifier,
      which will, whenever possible, also pass a pointer to the struct.
      You can pass a native pointer from C to a ref parameter in a C#
      function. To use native pointers, you have to mark the affected
      code block as unsafe. For example:</p>
    <div dir="auto">[StructLayout(LayoutKind.Sequential)]<br>
      unsafe struct S1 {</div>
    <div dir="auto">    public double x;</div>
    <div dir="auto">    public double y;<br>
          public Int64 z;<br>
    </div>
    <div dir="auto">    public fixed int arr[256];</div>
    <div dir="auto">};<br>
      <br>
      The unsafe keyword marks the structure as unsafe - it can only
      contain types which do not need marshalling. StructLayout can be
      used to specify the alignment options, usually the default works.
      StructLayout.Explicit and the FieldOffset attribute can be used to
      place fields at arbitrary offsets, for example to create "unions".<br>
      <br>
      The fixed (int) defines an inline array which behaves like a
      pointer (like it would in C). This array can not be used as a
      regular array, but its members can be accessed using an index.
      There's no bounds checking.<br>
      <br>
      You can then pass the struct to an external C function using one
      of the following options:<br>
      class Test {<br>
            [DllImport("native.so")]<br>
            public static extern void nativemethod1(ref S1 arg);<br>
            [DllImport("native.so")]<br>
            public static extern void nativemethod2(S1* arg);<br>
    </div>
          [DllImport("native.so")]<br>
          public static extern void nativemethod3(void* arg);<br>
          [DllImport("native.so")]<br>
          public static extern void nativemethod4(IntPtr arg);<br>
    <br>
        unsafe void Test() {<br>
          S1 s = new S1();<br>
          nativemethod1(ref s);<br>
          nativemethod2(&amp;s); //only works because we're in an unsafe
    block and the struct is marked unsafe<br>
          nativemethod3(&amp;s);<br>
          nativemethod4((IntPtr)(&amp;s));<br>
        }<br>
    }<br>
    <br>
    The other way around works as well, for example:<br>
    class Test {<br>
          [DllImport("native.so")]<br>
          public static extern S1* nativemethod1();<br>
          [DllImport("native.so")]<br>
          public static extern IntPtr nativemethod3();<br>
    <br>
        unsafe void Test() {<br>
          S1* s = nativemethod1();<br>
          s = (S1*)nativemethod3(); //cast if you used an IntPtr<br>
          s-&gt;x = 6; //the structure can now be modified directly.
    Make sure it's not released in the native code...<br>
        }<br>
    }<br>
    <br>
    --<br>
    Ivo<br>
    <br>
    <br>
    <div class="moz-cite-prefix">Op 5-1-2018 om 10:59 schreef R Zaghi:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAFLMc5u572Co+7=z_wN8bR=iwx8mZTSwwWYokhWCeezZoAWRzg@mail.gmail.com">
      <div dir="auto">Hi</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">What would be the most performance efficient
        method to pass a native C struct of primitive data types (memory
        aligned or compact) to the managed code in Mono/C# and allow
        modification of its member variables in the managed code?</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">Do we have anything specific in Mono that helps
        eliminate manual marshalling on every call? or could we? :)</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">Say, in the following scenarios:</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">struct S1 {</div>
      <div dir="auto">double x,</div>
      <div dir="auto">double y,</div>
      <div dir="auto">double z</div>
      <div dir="auto">};</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">Or</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">struct S2 {</div>
      <div dir="auto">int arr[256]</div>
      <div dir="auto">};</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">Or</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">struct S3 {</div>
      <div dir="auto">double x,</div>
      <div dir="auto">int arr[256]</div>
      <div dir="auto">};</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto"><br>
      </div>
      <div dir="auto"><br>
      </div>
      <div dir="auto">Ramin</div>
      <div dir="auto"><br>
      </div>
      <div dir="auto"><br>
      </div>
      <div dir="auto"><br>
      </div>
      <div dir="ltr">-- <br>
      </div>
      <div class="gmail_signature" data-smartmail="gmail_signature">
        <div dir="ltr">
          <div>
            <div dir="ltr">
              <div>
                <div dir="ltr">
                  <div>
                    <div dir="ltr">
                      <div>
                        <div dir="ltr"><br>
                        </div>
                        <div dir="ltr"><br>
                        </div>
                        <div dir="ltr"><br>
                        </div>
                        <div dir="ltr">Ramin Zaghi</div>
                        <div dir="ltr"><br>
                          <div><img
src="https://drive.google.com/uc?id=0B3xiwa7kf1uwRlYxenBFM1o2NEk&amp;export=download"
                              moz-do-not-send="true"><b>Mosaic3DX™ | <font
                                size="1">User Interface Technology</font></b></div>
                          <div>
                            <div style="font-size:small">St John's
                              Innovation Centre,</div>
                            <div style="font-size:small">Cowley Road,</div>
                            <div style="font-size:small">Cambridge,</div>
                            <div style="font-size:small">CB4 0WS, UK<b><br>
                              </b></div>
                            <div style="font-size:small"><b>E</b>:<b> </b><a
                                href="mailto:[email protected]"
                                target="_blank" moz-do-not-send="true">[email protected]</a></div>
                            <div style="font-size:small"><b>T</b>: +44
                              1223 421 311</div>
                          </div>
                          <div><font size="2"><a
                                href="http://linkedin.com/in/raminzaghi"
                                target="_blank" moz-do-not-send="true">http://linkedin.com/in/raminzaghi</a></font></div>
                          <div><font size="2"><br>
                            </font></div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
Mono-devel-list mailing list
<a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
<a class="moz-txt-link-freetext" href="http://lists.dot.net/mailman/listinfo/mono-devel-list">http://lists.dot.net/mailman/listinfo/mono-devel-list</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>

--------------FB5D0FE3265B8DB38C421570--

--===============1715578260771353598==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline

X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KTW9uby1kZXZl
bC1saXN0IG1haWxpbmcgbGlzdApNb25vLWRldmVsLWxpc3RAbGlzdHMuZG90Lm5ldApodHRwOi8v
bGlzdHMuZG90Lm5ldC9tYWlsbWFuL2xpc3RpbmZvL21vbm8tZGV2ZWwtbGlzdAo=

--===============1715578260771353598==--