Avatar billede skov_p Praktikant
04. august 2007 - 00:18 Der er 25 kommentarer og
1 løsning

VB datastruktur til C# .NET struct

Hej

Jeg er ved at lave en applikation som skal kommunikere med en anden applikation via et API.

Jeg har nogle eksempler i VB som jeg har oversat til C#.
Men jeg får fejl ved nogle af kaldene vedr. memory.

Sådan ser VB definitionen ud:

Public Type Order
    lSize              As Long    ' Size of the entire structure
                                    ' Denne må settes til Len(Order) før Api-kallet
    sKey                As Integer
    sOrdreType          As Integer
    lKundeNr            As Long
    lFiller1            As Long
   
    achOrdreNr          As String * 10
    bNull_1            As String * 1
    achOrdreDato        As String * 6
    bNull_2            As String * 1
    achLevDato          As String * 6
    bNull_3            As String * 1
    achKundeNavn        As String * 30
    bNull_4            As String * 1
    achAdresseI        As String * 30
    bNull_5            As String * 1
    achAdresseII        As String * 30
    bNull_6            As String * 1
    achAdresseIII      As String * 30
    bNull_7            As String * 1
    achPostNr          As String * 6
    bNull_8            As String * 1
    achPostSted        As String * 25
    bNull_9            As String * 1
    achDeresRef        As String * 30
    bNull_10            As String * 1
    achVaarRef          As String * 30
    bNull_11            As String * 1
    achLevBet          As String * 30
    bNull_12            As String * 1
    achLevMate          As String * 30
    bNull_13            As String * 1
    achOrganisasjonsNr  As String * 15
    bNull_14            As String * 1
    achOrdreReferanse  As String * 10
    bNull_15            As String * 1
    chFlag              As String * 1
    chRestJN            As String * 1
    chFiller1          As String * 1
    sLagerSted          As Integer
    sFiller1            As Integer
    sFiller2            As Integer
    sFiller3            As Integer
    lAvdeling          As Long
    lProsjekt          As Long
    lFiller2            As Long
    lFiller3            As Long
    dOrdreRabattPros    As Double
    dKontantRabattPros  As Double
    dOrdreSum          As Double
    dValutaKurs        As Double
    dSumValuta          As Double
    usValutaKode        As Integer
    sFiller4            As Integer
    lFiller4            As Long
    dEkspedisjonsGebyr  As Double
    dFiller2            As Double
    achLevNavn          As String * 30
    bNull_16            As String * 1
    achLevAdresseI      As String * 30
    bNull_17            As String * 1
    achLevAdresseII    As String * 30
    bNull_18            As String * 1
    achLevAdresseIII    As String * 30
    bNull_19            As String * 1
    achLevPostNr        As String * 6
    bNull_20            As String * 1
    achLevPostSted      As String * 25
    bNull_21            As String * 1
    chFiller2          As String * 1
    sLevAdrNr          As Integer
End Type

Her er min .NET udgave

[StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi )]
  public struct Order {
    public int lSize;
    public short sKey;
    public short sOrdreType;
    public int lKundeNr;
    public int lFiller1;
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 10 )]
    public string achOrdreNr;          // public string * 10
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_1;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 6 )]
    public string achOrdreDato;        // public string * 6
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_2;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 6 )]
    public string achLevDato;          // public string * 6
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_3;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achKundeNavn;        // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_4;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achAdresseI;        // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_5;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achAdresseII;        // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_6;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achAdresseIII;      // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_7;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 6 )]
    public string achPostNr;          // public string * 6
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_8;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 25 )]
    public string achPostSted;        // public string * 25
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_9;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achDeresRef;        // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_10;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achVaarRef;          // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_11;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achLevBet;          // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_12;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achLevMate;          // public string * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_13;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 15 )]
    public string achOrganisasjonsNr;  // public string * 15
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_14;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 10 )]
    public string achOrdreReferanse;  // public string * 10
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_15;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string chFlag;              // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string chRestJN;            // public string * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string chFiller1;          // public string * 1
    public short sLagerSted;          // Integer
    public short sFiller1;            // Integer
    public short sFiller2;            // Integer
    public short sFiller3;            // Integer
    public int lAvdeling;              // Long
    public int lProsjekt;              // Long
    public int lFiller2;              // Long
    public int lFiller3;              // Long
    public double dOrdreRabattPros;    // Double
    public double dKontantRabattPros;  // Double
    public double dOrdreSum;          // Double
    public double dValutaKurs;        // Double
    public double dSumValuta;          // Double
    public short usValutaKode;        // Integer
    public short sFiller4;            // Integer
    public int lFiller4;              // Long
    public double dEkspedisjonsGebyr;  // Double
    public double dFiller2;            // Double  ' NYTT 971


    // Utvidelser til Build 920
    // Alt over er som i ENORDREHODE


    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achLevNavn;          // String * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_16;            // String * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achLevAdresseI;      // String * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_17;            // String * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achLevAdresseII;    // String * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_18;            // String * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 30 )]
    public string achLevAdresseIII;    // String * 30
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_19;            // String * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 6 )]
    public string achLevPostNr;        // String * 6
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_20;          // String * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 25 )]
    public string achLevPostSted;      // String * 25
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string bNull_21;            // String * 1
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst = 1 )]
    public string chFiller2;          // String * 1
    public short sLevAdrNr;            //As Integer
Avatar billede arne_v Ekspert
04. august 2007 - 01:19 #1
Hvilken fejl ?
Avatar billede nielle Nybegynder
04. august 2007 - 08:51 #2
Jeg skal ikke gøre mig klog på *hvorfor*, men øjensynligt respektere .Net/C# ikke dine SizeConst-værdier. Det kan man f.eks. se af følgende eksempel:

static void Main(string[] args)
{
    Nielle n = new Nielle();
    n.str1 = "1234567";
    n.str2 = "abcdefg";

    Console.WriteLine(n.str1);
    Console.WriteLine(n.str2);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Nielle
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
    public string str1;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
    public string str2;
}

som køre igennem uden at fejle selv om strengene er længerer end 3.

Man kunne derfor forestille sig at værdierne, i din struct, ligger på nogle andre steder i hukommelsen end der hvor den modtagende metode forventer at de skal ligge. Dette er sikkert grunden til at du får memory-fejl.

Desværre kan jeg ikke selv give noget bud på kuren. :^|
Avatar billede skov_p Praktikant
04. august 2007 - 13:55 #3
Der skal sendes en ovenstående datastruktur til API'et som returnerer et handle (memory adresse antager jeg). Det handel bruges så når ordren skal gemmes.
Det er når jeg prøver at lave "gemmekaldet" at API'et kommer med en dialog om at et memory område ikke kan findes.
Avatar billede skov_p Praktikant
04. august 2007 - 14:33 #4
Når jeg feks. henter varer gennem API'et fungerer "oversættelsen" af vare data strukturen fint.
Avatar billede arne_v Ekspert
04. august 2007 - 17:02 #5
nielle>

Jeg tror nu nok at den respekterer SizeConst.

Men MarshalAs har vel kun effekt når man Marshal'er !?

Eksempel:

using System;
using System.Runtime.InteropServices;

namespace E
{
    public class Program
    {
        private static byte[] ConvertStructToBytes(object o)
        {
            int siz = Marshal.SizeOf(0);
            IntPtr buf = Marshal.AllocHGlobal(siz);
            byte[] res = new byte[siz];
            Marshal.StructureToPtr(o, buf, true);
            Marshal.Copy(buf, res, 0, siz);
            Marshal.FreeHGlobal(buf);
            return res;
        }
        private static object ConvertBytesToStruct(byte[] b, Type t)
        {
            IntPtr buf = Marshal.AllocHGlobal(b.Length);
            Marshal.Copy(b, 0, buf, b.Length);
            object res = Marshal.PtrToStructure(buf, t);
            Marshal.FreeHGlobal(buf);
            return res;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct Nielle
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
            public string str1;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
            public string str2;
        }
        public static void Main(string[] args)
        {
            Nielle n = new Nielle();
            n.str1 = "1234567";
            n.str2 = "abcdefg";
            Console.WriteLine(n.str1);
            Console.WriteLine(n.str2);
            Nielle n2 = (Nielle)ConvertBytesToStruct(ConvertStructToBytes(n), typeof(Nielle));
            Console.WriteLine(n2.str1);
            Console.WriteLine(n2.str2);
            Console.ReadLine();
        }
    }
}
Avatar billede arne_v Ekspert
04. august 2007 - 17:03 #6
skov_p>

Vi skal se noget kode og en præcis exception tekst.
Avatar billede nielle Nybegynder
04. august 2007 - 18:24 #7
arne_v> Men MarshalAs har vel kun effekt når man Marshal'er !?

Det har du jo nok ret i. :^)

Nu er det ikke meningen at jeg vil hijacke dette spørgsmål, men der er nu alligevel noget som under mig med dit eksempel:

1) Med denne kode:

private static byte[] ConvertStructToBytes(object o)
{
    int siz = Marshal.SizeOf(0);
    ...
    byte[] res = new byte[siz];
    ...
    return res;
}

- vil ConvertStructToBytes() altid returnere et byte-array med 4 bytes (tallet 0 bliver tolket som en System.Int32). Hvordan kan den så håndtere structs som er væsentlig større end 4 bytes? For det kan den rent faktisk - har prøvet efter...

Det virker lidt mistænkeligt. Næsten som om at arrayet alligevel fylder mere end de 4 bytes (også selv om Length faktisk siger at længden er 4)?!

2) Hvordan kan det være at de 2 strenge - anden gang de bliver udskrevet via n2 - kun er 2 karakter lange i stedet for 3 (SizeConst=3)? Er det mon fordi at de et eller andet sted undervejs bliver nul-termineret, og at nul-byten "stjæler" det sidste tegn i strengen?
Avatar billede arne_v Ekspert
04. august 2007 - 20:35 #8
Det skulle naturligvis være o og ikke 0.

:-)

UnmanagedType.ByValTStr er så vidt jeg ved .NET'sk for char*, så ja det er 2 data bytes +
en nul terminerings byte.
Avatar billede nielle Nybegynder
04. august 2007 - 23:06 #9
Men 0 virker underligt nok også... ? Og man kan endda få det til at virke ved at skrive

int siz = 4;
Avatar billede arne_v Ekspert
04. august 2007 - 23:20 #10
Mit gæt en af følgende:
* AllocHGlobal allokerer memory på 8 byte boundaries og derfor vil alt 1-8 reelt give 8 byte reel plads
* virtuel memory mappes per page og derfor kan man "bruge" pladsen op til 512 byte boundary (i dette tilfælde - i andre tilfælde vil man overskrive vigtige data)
Avatar billede skov_p Praktikant
05. august 2007 - 00:36 #11
Her er et eksempel på hvordan det kan gøres i et regneark.

Sub LagEnOrdre()
   
    Dim lRetVal As Long
    Dim strONR As String
    Dim lKundeNr As Long
    Dim sTekstLinje As String * 60

    With ActiveSheet
        Application.ScreenUpdating = False
       
        If (OrdreHandle <> 0) Then
          ' Free ORDRE !!!!!!!!
          RubFreeEnOrdre (OrdreHandle)
        End If

        OrdreHandle = 0
       
        strONR = .Cells(6, 1)
        lKundeNr = .Cells(6, 2)
        If lKundeNr = 0 Then
            MsgBox (vbCr & "Kunde-nummer er IKKE fylt ut !!!" & vbCr)
        Else
            EOH.lSize = Len(EOH) 'Size of the entire structure, settes før Api-kalles
           
            If (strONR = "") Then
                ' Opprett en ny ordre om den ikke finnes fra før !
                EOH.achOrdreNr = ""
                EOH.lKundeNr = lKundeNr
                EOH.sOrdreType = 101
               
                OrdreHandle = RubOpprettEnOrdre(EOH)
               
                EOH.achDeresRef = "Deres ref"
                EOH.achVaarRef = "VårRef"
                EOH.lAvdeling = 10
                EOH.lProsjekt = 11
                EOH.achOrdreDato = "150500"
               
                strONR = EOH.achOrdreNr
                MsgBox (vbCr & "Opprettet ny ordre: " & strONR & vbCr)
            Else
                EOH.achOrdreNr = strONR
                OrdreHandle = RubHentEnOrdre(EOH)
            End If
           
            strONR = EOH.achOrdreNr
            If (OrdreHandle <> 0) Then
              ' Legger til Ordrelinje
                EOL.lSize = Len(EOL) 'Size of the entire structure, settes før Api-kalles
                EOL.achArtNr = "30-4497"
                EOL.achArtNavn = "TEST Ø-Æ-Å øæå"
                EOL.achOrdreNr = strONR
                EOL.dPris = 123.12345
                EOL.dRab1 = 10.5
                EOL.dAntOrd = 10
                EOL.dAntLev = 5
               
                lRetVal = RubEnOrdreAddLinje(OrdreHandle, EOL)
               
                ' Legg til en tekstlinje
                sTekstLinje = "Dette er en tekstlinje ÆØÅ æøå"
                lRetVal = RubEnOrdreAddTekstLinje(OrdreHandle, sTekstLinje)
               
                '  Legger til ekspedisjonsgebyr og porto
                EOH.dEkspedisjonsGebyr = 10
                EOH.dPorto = 15
               
                '  Skrivordren
                lRetVal = RubSkriveEnOrdre(OrdreHandle, EOH)
               
                MsgBox ("Ordre: " & strONR & vbCr & "er oppdatert med 1 ny linje ! ")
               
            End If
        End If
           
        OrdreHandle = 0
    End With

End Sub
Avatar billede skov_p Praktikant
05. august 2007 - 00:38 #12
Her er min kode

    oHandle = RubMethods.RubOpprettEnOrdre( ref oh );

      ArtInfo2 ai = new ArtInfo2();
      ai.lSize = Marshal.SizeOf( typeof( ArtInfo2 ) );
      ai.achArtNr = GetSelectedArticle();
      res = RubMethods.RubLesArtikkel( ref ai );

      PrisInfo pi = new PrisInfo();
      pi.lSize = Marshal.SizeOf( typeof( PrisInfo ) );
      pi.lReskNummer = 10563;
      pi.szArtNr = GetSelectedArticle();
      res = RubMethods.RubGetKundeArtikkelPris( ref pi );

      EnOrdreLinje ol = new EnOrdreLinje();
      ol.lSize = Marshal.SizeOf( typeof( EnOrdreLinje ) );
      ol.achOrdreNr = oh.achOrdreNr;
      ol.dPris = pi.dMinPris;
      ol.achArtNr = ai.achArtNr;
      ol.achEnhet = ai.achEnhetsTekst;
      ol.achArtNavn = ai.achArtNavn;
      ol.achLevDato = DateTime.Now.ToShortDateString().Replace( "-", "" );
      ol.dRab1 = pi.dRab1;
      ol.dRab2 = pi.dRab2;
      ol.dAntOrd = 0;
      ol.dAntLev = 0;
      ol.dAntRest = 0;

      res = RubMethods.RubEnOrdreAddLinje( ref oHandle, ref ol );

      res = RubMethods.RubSkriveEnOrdre( ref oHandle, ref oh );

    }

  public class RubMethods{

    [DllImport( "RubApi.dll", CharSet = CharSet.Ansi )]
    public static extern int RubOpprettEnOrdre(ref EnOrdreHode2 order);

    [DllImport( "RubApi.dll", CharSet = CharSet.Ansi )]
    public static extern int RubGetKundeArtikkelPris(ref PrisInfo pi);

    [DllImport( "RubApi.dll", CharSet = CharSet.Ansi )]
    public static extern int RubEnOrdreAddLinje(ref int ordreHandle, ref EnOrdreLinje orderLine);

    [DllImport( "RubApi.dll", CharSet = CharSet.Ansi, EntryPoint = "RubSkriveEnOrdre" )]
    public static extern int RubSkriveEnOrdre(ref int ordreHandle, ref EnOrdreHode2 orderHeader);
}
Avatar billede skov_p Praktikant
05. august 2007 - 01:10 #13
Når jeg kalder

res = RubMethods.RubSkriveEnOrdre( ref oHandle, ref oh );

får jeg

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Avatar billede arne_v Ekspert
05. august 2007 - 02:49 #14
Jeg har svært ved at gennemskue problemet.

Et gæt ville være at Rub-funktionerne gemmer nogle interne pointere mellem kaldene
og at det er derfor det går galt.

Du kunne prøve at gemme dine structs i noget Marshal.AllocHGlobal'ed memory
og så kalde funktionerne med en IntPtr.
Avatar billede nielle Nybegynder
05. august 2007 - 07:44 #15
Et par ting jeg undre mig lidt over:

1) Har du prøvet at teste på res-værdierne undervejs? De indeholder formodentlig en kode om hvorvidt det gik godt ... returnere de alle sammen "success"?

2) Dit oprindelige spørgsmål gik på struct'en Order. Den kan jeg saelt ikke se blive brugt i dit kodeeksempel?

3) Din regneark-kode er lidt underlig: Du opretter aldrig noget OrdreLinje-objekt. I stedet begynder du blot at arbejde med EOL som om den allerede eksistere. Er dette en global defineret variabel, eller hvad?

Under alle omstændigheder er det en afvigelse mellem de to løsninger, hvis den ene hele tiden ændre sin adresse (i C# løsningen) og den anden ligger fast (i VBA-løsningen).

Det også lidt interessant at dit EnOrdreLinje sendes til RUP i linjen lige før at det går galt.

4) I VBA løsningen kalder du RubEnOrdreAddTekstLinje() imellem kaldene til RubEnOrdreAddLinje() og RubSkriveEnOrdre(). Det gør du ikke i C# løningen. Kunne det tænkes at give problemer?

5) Har du prøvet om det fungere bedre i VB.Net fremfor C#?
Avatar billede skov_p Praktikant
05. august 2007 - 10:48 #16
Arne v:
Det med lave kald gennem en DLL er nyt for mig så jeg skal bruge et eksempel for at se hvad du har i tankerne ang. Marshal.AllocHGlobal og IntPtr.

Nielle:
1) Returværdierne er ok bortset fra RubOpprettEnOrdre som skal returnerer memory området for ordren som ser ud til at være forkert.

2) Jeg gav den bare et mere sigende navn. Det er det samme som EnOrdreHode2

3) Jeg har ikke prøvet at bruge eksemplet, det er blot et der er vist i dokumentationen.

Adressen der returneres i C# er den samme for RubOpprettEnOrdre

4) Det er ikke et nødvendigt kald

5) Jeg har overvejet at lave det i VB.NET da jeg så kan lave en del copy/paste fra eksemplerne jeg har. men jeg er mest til C#. Jeg kan vel lave typerne og kaldene til API'et i VB.NET dll og resten i C#
Avatar billede skov_p Praktikant
06. august 2007 - 21:30 #17
VB er endnu ringere en C# (hvilket jeg nu altid har ment...)

Virker:
[DllImport("RubApi.dll",CharSet=CharSet.Ansi)]
private static extern int RubRpcLogon(int client, string dataArea);

Virker ikke:
Public Declare Function RubRpcLogon Lib "RubApi" (ByRef clientId As Integer, ByRef dataPath As String) As Integer

Virker ikke:
<DllImport("RubApi.dll", CharSet:=CharSet.Ansi)> _
Public Shared Function RubRpcLogon(ByRef clientId As Integer, ByRef dataPath As String) As Integer
End Function

Er det forkert at gemme returværdien fra API'et i en int, hvilket måske giver mig en forkert adresse? Andre forslag???

int handle = RubOpprettEnOrdre(ref ordreHode2)

[DllImport( "RubApi.dll", CharSet = CharSet.Ansi )]
public static extern int RubOpprettEnOrdre(ref EnOrdreHode2 order);
Avatar billede arne_v Ekspert
07. august 2007 - 00:58 #18
Din VB.NET er ikke den samme som din C# - da C# default bruger ByVal og du angiver ByRef !
Avatar billede arne_v Ekspert
07. august 2007 - 00:59 #19
Jeg kan godt prøve og bixe et eksempel der illusterer hvad jeg mener med IntPtr.
Avatar billede arne_v Ekspert
07. august 2007 - 01:33 #20
DLL kode:

#include <stdio.h>

struct foo
{
    long int a;
    long int b;
};

void bar1(struct foo *f)
{
    printf("bar1: address of data: %p\n",f);
    printf("bar1: values at entry: %d %d\n",f->a,f->b);
    f->a++;
    f->b++;
    printf("bar1: values at exit: %d %d\n",f->a,f->b);
}

void bar2(struct foo *f,int v)
{
    printf("bar2: address of data: %p\n",f);
    printf("bar2: values at entry: %d %d\n",f->a,f->b);
    f->a += v;
    f->b += v;
    printf("bar2: values at exit: %d %d\n",f->a,f->b);
}
Avatar billede arne_v Ekspert
07. august 2007 - 01:33 #21
Normal kald af Win32 DLL:

using System;
using System.Runtime.InteropServices;

namespace E
{
    public class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        struct foo
        {
            public int a;
            public int b;
        }
        [DllImport(@"C:\foobar.dll")]
        static extern void bar1(ref foo f);
        [DllImport(@"C:\foobar.dll")]
        static extern void bar2(ref foo f, int v);
        public static void Main(string[] args)
        {
            foo f;
            f.a = 11;
            f.b = 21;
            Console.WriteLine("values before bar1: " + f.a + " " + f.b);
            bar1(ref f);
            Console.WriteLine("values after bar1: " + f.a + " " + f.b);
            Console.WriteLine("values before bar2: " + f.a + " " + f.b);
            bar2(ref f, 1);
            Console.WriteLine("values after bar2: " + f.a + " " + f.b);
            Console.Write("Press any key to continue . . . ");
            Console.ReadKey(true);
        }
    }
}
Avatar billede arne_v Ekspert
07. august 2007 - 01:33 #22
Brug af IntPtr:

using System;
using System.Runtime.InteropServices;

namespace E
{
    public class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        struct foo
        {
            public int a;
            public int b;
        }
        [DllImport(@"C:\foobar.dll")]
        static extern void bar1(IntPtr f);
        [DllImport(@"C:\foobar.dll")]
        static extern void bar2(IntPtr f, int v);
        public static void Main(string[] args)
        {
            foo f;
            f.a = 11;
            f.b = 21;
            int siz = Marshal.SizeOf(f);
            IntPtr buf = Marshal.AllocHGlobal(siz);
            Marshal.StructureToPtr(f, buf, true);
            Console.WriteLine("values before bar1: " + f.a + " " + f.b);
            bar1(buf);
            f = (foo)Marshal.PtrToStructure(buf, typeof(foo));
            Console.WriteLine("values after bar1: " + f.a + " " + f.b);
            Console.WriteLine("values before bar2: " + f.a + " " + f.b);
            bar2(buf, 1);
            f = (foo)Marshal.PtrToStructure(buf, typeof(foo));
            Console.WriteLine("values after bar2: " + f.a + " " + f.b);
            Marshal.FreeHGlobal(buf);
            Console.Write("Press any key to continue . . . ");
            Console.ReadKey(true);
        }
    }
}
Avatar billede arne_v Ekspert
07. august 2007 - 01:35 #23
Den sidste version sikrer med 112% garanti af f ligger samme sted i unmanaged memory.

Jeg må indrømme at den første version faktisk udskriver samme adresse for f i de to kald,
så jeg ved ikke om min ide er noget værd.

Men det er ihvertfald en ide.
Avatar billede skov_p Praktikant
07. august 2007 - 21:37 #24
Tak for hjælpen.

Jeg kunne ikke gennemskue dit eksempel, det var adressen som API'et returnerede der var forkert hvis den belv lagret i en int.
Det var det jeg havde mistanke om da jeg skrev 06/08-2007 21:30:34

Jeg lavede min int handle; om til int* handle; og nu virker det.
Troede egenligt at det var det samme som ref, men så lærte jeg også noget i dag.

Send et svar begge to
Avatar billede arne_v Ekspert
08. august 2007 - 00:19 #25
svar
Avatar billede nielle Nybegynder
08. august 2007 - 07:10 #26
Springer over på denne her :^)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester