Jag jobbar med C# i Compact Framework mot en "vanlig" c++ dll. Vissa av dess funktioner tar struktar. I riktiga .net framework kan man använda sig av MarshalAs, men den finns inte tillgänglig i CF. Hur uppnår man samma sak i CF? >>Talar användingen av "new" emot att det skall fungera? jag använder pekare till structar/klasser och det fungerar fint. OK, [StructLayout(LayoutKind.Sequential)] Jag får NotSupportedException om jag kör med ref (på den rad funktionen körs). Och med pekare på structen får jag som sagt kompileringsfel; "Cannot take the address or size of a variable of a managed type" >Alltså det finns ju value types och reference types. Om man kör new på en char blir det då reference type? detta fungerar , dock är det ju kraftigt osnyggt... detta kanske är snyggaremer unmanaged
Jag läste i ett annat forum att man då istället kan använda en klass, men då dök nästa problem upp. Man kan inte göra en pekare till en managed type ("Cannot take the address or size of a variable of a managed type"). Hur gör jag min klass unmanaged? Det räcker iallafall inte med att ha med nyckelordet unsafe. I klassen har jag också character arrayer med fast längd. Talar användingen av "new" emot att det skall fungera?
Tack på förhand!
/peterbladhSv: mer unmanaged
>Hur uppnår man samma sak i CF?
Beror på från fall till fall. Sök i google arkiven för microsoft.public.dotnet.framework.compactframework så hittar du en del tips. Framför allt
http://groups.google.com/groups?selm=OcNZ3bdvCHA.1132%40TK2MSFTNGP12
>Hur gör jag min klass unmanaged?
Det går inte i C#.
>Talar användingen av "new" emot att det skall fungera?
Förstår inte frågan.
MSSv: mer unmanaged
>Förstår inte frågan
Alltså det finns ju value types och reference types. Om man kör new på en char blir det då reference type? Om det blir det så är det ju till nackdel för C-koden som inte vill ha ett objekt.
/peterbladhSv: mer unmanaged
marshallAs använder du när du vill konvertera tex en sträng till något annat , dvs hur bytarna ligger i minnet , om din struct är rätt deklarerad behövs inte detta...
läs om [StructLayout(LayoutKind.Sequential)]
och om kommandot "fixed"
exempel på struct som går att använda med pekare.
<code>
[StructLayout(LayoutKind.Sequential)]
struct _NCCALCSIZE_PARAMS
{
public RECT NewRect;
public RECT OldRect;
public RECT OldClientRect;
public WINDOWPOS lppos;
}
</code>
//RogerSv: mer unmanaged
men då kommer nästa grej - jag behöver fixed sized arrays i structen (char arr[8] i C). Hur får jag till det?
/peterbladhSv: mer unmanaged
struct MyStruct
{
public byte[] arr;
}
...
MyStruct a=new Mystruct();
a.arr = new byte[8];
anrop(a);
...
[edit]
oke , det är jag som svamlar...
det gick bra att HÄMTA en struct från en pekare...
dock inte att skapa en struct och göra en pekare till den...
men går det inte reklarera parametern som "ref" i anropet?
[/edit]Sv: mer unmanaged
En workaround är ju att göra ett enklare interface i c dllen eller göra en ny som som fungerar som mellanhand. Detta känns dock inte särskilt bra, så ny uppslag mottages gladeligen:)
/peterbladhSv: mer unmanaged
Nej, typen är vad den är, new påverkar inte det.
MSSv: mer unmanaged
<code>
//'skapa en buffer för din strukt , måste vara samma storlek som structen i antal bytes
byte[] buffer=new byte [12];
//'få en pekare till första posten i buffern
fixed (byte* buffstart=&buffer[0])
{
//'koppla en mystruct pekare till samma minnes area som buffern
MyStruct* mystruct = (MyStruct*)(void*)buffstart;
//sätt värden på alla params..
mystruct->SomeValue =123;
mystruct->b1 =1;
mystruct->b2 =1;
mystruct->b3 =1;
//'anropa
anrop(mystruct);
}
</code>
och här kommer det fulaste :)
<code>
[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
public int SomeValue;
//' meningen är att dessa esätter din char/byte []
public byte b1;
public byte b2;
public byte b3;
public byte b4;
public byte b5;
public byte b6;
public byte b7;
public byte b8;
}
</code>Sv: mer unmanaged
<code>
using System;
namespace ConsoleApplication1
{
class MyStruct
{
public int SomeValue=0;
public long SomeOtherValue=0;
//NOTE: max 8 bytes..
public string MyString="";
public byte[] Marshall()
{
byte[] buffer=new byte[4+8+8];
byte[] bytes=null;
bytes=BitConverter.GetBytes (this.SomeValue);
Array.Copy (bytes,0,buffer,0,bytes.Length);
bytes=BitConverter.GetBytes (this.SomeOtherValue);
Array.Copy (bytes,0,buffer,4,bytes.Length);
if (MyString.Length <8)
{
//forcera till 8 bytes
MyString+=new string (' ',8-MyString.Length);
}
else if (MyString.Length>8)
{
//klipp om den är för lång
MyString=MyString.Substring (0,8);
}
bytes=System.Text.Encoding.ASCII.GetBytes(MyString);
Array.Copy (bytes,0,buffer,4+8,bytes.Length);
return buffer;
}
}
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
MyStruct ms=new MyStruct ();
ms.MyString ="khdjkhj";
ms.SomeOtherValue =123;
ms.SomeValue =661;
byte[] buffer=ms.Marshall ();
unsafe
{
fixed (byte* b = &buffer[0] )
{
for (int i=0;i<4+8+8;i++)
{
Console.WriteLine (b[i]);
}
//skicka b istället för din struct , eftersom b är en pekare till en
//minnes area som innehåller det du vill att den ska göra
Anrop(b);
}
}
Console.ReadLine ();
}
}
}
</code>