[c#] marshalling

Pagina: 1
Acties:
  • 136 views sinds 30-01-2008
  • Reageer

  • elgringo
  • Registratie: Januari 2001
  • Laatst online: 16-09 20:30
Ik heb een DLL geschreven in C++ die ik in C# wil gaan gebruiken. De DLL is om communicatie met een PLC tot stand te brengen

Deel van header file (ik heb .h .lib en de dll, dll ga ik gebruiken, maar adhcv de header weet ik wat er is)
C++:
1
2
int PRODAVEAPI GetErrorMessage_ex6 (int ErrorNr, ULONG BufLen, char * pBuffer);
int PRODAVEAPI as_zustand_ex6 (unsigned char * pState);

in de 2de functie wordt er om een char* gevraagd die een mininmale grote heeft. De retourwaarde is een errorcode die met de eerste functie opgehaald kan worden.

De eerste functie geef je de errorcode, buffergrote en bufferpointer mee.

Die tweede functie heb ik alsvolgt gedefinieerd:
C#:
1
2
[DllImport("prodave6.dll", EntryPoint = "as_zustand_ex6", ExactSpelling = false)]
public static extern int as_zustand_ex6([MarshalAs(UnmanagedType.LPStr)] ref string test);

Als ik de functie aanroep:
C#:
1
2
string teststring="";
int i=ProdaveWrapper.as_zustand_ex6(ref teststring);

Werkt het niet, ik krijg code 286 terug en die staat voor: 'No connection to database or S7DOS handle invalid.'. De tweede functie(geterrormessage) geeft 28736 terug, die staat voor 'Result buffer too small'
Op zich ook wel logisch aangezien die string niet zo groot is. De char* wordt door de functie gevuld.

Hoe kan ik een buffer meesturen die wel groot genoeg is, dus dat die ruimte wel vastgelegd is?

Bij de eerste functie waar de buffer grote en bufferpointer meegegeven moet worden heb ik geen flauw idee hoe ik dit moet oplossen.
Ik heb LPArray geprobeerd met een vaste grote van 100 en buffergrote 100 meegegevn en dit werkt niet.
Hoe moet ik deze functie aanpakken

[ Voor 4% gewijzigd door elgringo op 01-06-2007 09:57 ]

if broken it is, fix it you should


  • reddog33hummer
  • Registratie: Oktober 2001
  • Laatst online: 03-08 23:13

reddog33hummer

Dat schept mogelijkheden

Waarom gebruik je: "unsigned char*" en geen char*
Laat eens wat meer van de c++ code zien.

Zaken waar je met dit soort zaken altijd op moet letten:
Gebruik je unicode aan de C# en/of C++ kant (dit kan namelijk 2X zoveel tekens opleveren dan dat je verwacht).
heb je rekening gehouden met de trailing in de buffer \0 ?

[ Voor 76% gewijzigd door reddog33hummer op 01-06-2007 08:46 ]

Backup not found (R)etry (A)bort (P)anic<br\>AMD 3400+ 64, 2 GB DDR, 1,5 TB Raid5


  • elgringo
  • Registratie: Januari 2001
  • Laatst online: 16-09 20:30
reddog33hummer schreef op vrijdag 01 juni 2007 @ 08:44:
Waarom gebruik je: "unsigned char*" en geen char*
Laat eens wat meer van de c++ code zien.

Zaken waar je met dit soort zaken altijd op moet letten:
Gebruik je unicode aan de C# en/of C++ kant (dit kan namelijk 2X zoveel tekens opleveren dan dat je verwacht).
heb je rekening gehouden met de trailing in de buffer \0 ?
Moet ik Siemens voor vragen. Ik heb de dll zo aangeleverd gekregen (softwarepakket). unsigned char is iig een byte.
De code heb ik dus ook niet, alleen een header met alle functies een lib ar statische library en een dll die ik wil gebruiken.

Ik heb in c# en de c++ code niets verandert, hoe kan ik zien wat ie gebruikt?
Ik hou nog geen rekening met de '\0' Ik wil eerst weten waarom die buffer te klein is.

[ Voor 12% gewijzigd door elgringo op 01-06-2007 09:02 ]

if broken it is, fix it you should


  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Ik meen me te herinneren dat C/C++ strings altijd als StringBuffers gemarshalled worden, niet als System.String. Misschien dat dat helpt?

  • elgringo
  • Registratie: Januari 2001
  • Laatst online: 16-09 20:30
MrBucket schreef op vrijdag 01 juni 2007 @ 09:06:
Ik meen me te herinneren dat C/C++ strings altijd als StringBuffers gemarshalled worden, niet als System.String. Misschien dat dat helpt?
Wat versta je onder stringbufers?

Ik heb net met stringbuilder geprobeerd:

C#:
1
2
3
4
5
[DllImport("prodave6.dll", EntryPoint = "as_zustand_ex6", ExactSpelling = false)]
public static extern int as_zustand_ex6(StringBuilder test);

StringBuilder s = new StringBuilder(200);
int i=ProdaveWrapper.as_zustand_ex6(s);

Ook hier krijg ik een melding dat de buffer te klein is

if broken it is, fix it you should


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Even voor de duidelijkheid, als je in je unmanaged dll de buffer zelf aanmaakt met een bepaalde grootte werkt het wel?

Owh wacht ff, de dll is niet van jezelf :D.
Erm ... als je de functies vanuit unmagaged code gebruikt werkt het wel?


(Siemens software sucked btw :P )

[ Voor 40% gewijzigd door farlane op 01-06-2007 09:25 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Misschien een tip: Maak zelf een unmanaged-wrapper dll die de siemens dll aanspreekt.
Ik heb zelf met Cantata software moeten werken en een wrapper bouwen heeft toch een hoop gescheeld.

Anders heb je misschien iets aan dit: http://www.thescripts.com/forum/thread496724.html

Nu met Land Rover Series 3 en Defender 90


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

ik heb eerder "3rd party" gewrapped voor .NET talen, om het hele marshalling gedoe makkelijker te maken, doe ik alle malloc/new calls in unmanaged code (C++/CLI), en wrap ik alle functies in in een (managed) static class :)

dan krijg je een opbouw als:
[jouw app (.NET)] -- imports -> [een wrapper .NET/native gemengd] -- linkt tegen -> [3rd party native .lib/.dll]
voordeel is dat je al het "gedoe" met [DLLImport ...] tags en marshalling maar 1x doet, en in die aparte library, zodat je je daar niet meer druk over hoeft te maken in je uiteindelijke app :)

dat vereist natuurlijk wel (een beetje) kennis van C++, en (aanrader) bouw je wrapper zo safe mogelijk (check alle return values, maak voor elke mogelijke error een exception aan)

edit: ik zie dat MTWZZ net ook al zoiets zegt :|

[ Voor 3% gewijzigd door MLM op 01-06-2007 09:45 ]

-niks-


  • elgringo
  • Registratie: Januari 2001
  • Laatst online: 16-09 20:30
farlane schreef op vrijdag 01 juni 2007 @ 09:24:
Even voor de duidelijkheid, als je in je unmanaged dll de buffer zelf aanmaakt met een bepaalde grootte werkt het wel?

Owh wacht ff, de dll is niet van jezelf :D.
Erm ... als je de functies vanuit unmagaged code gebruikt werkt het wel?


(Siemens software sucked btw :P )
Ik heb de header meegelinkt (prodave6.h) met statische lib

C++:
1
2
3
4
5
6
unsigned char* test;
test=new unsigned char(200);
int t=as_zustand_ex6 (test);
    
char* test2=new char(200);
int t2=GetErrorMessage_ex6 (t, 200, test2);

functie 1 (t)geeft steeds 286 terug en functie 2 (t2) 28736
286 betekend 'No connection to database or S7DOS handle invalid.'
28736 betekend 'Buffer too small'

(foutcode 286 had ik verkeerd gezien, ik keek naar 287)
maw hij doet exact hetzelfde. Test en test2 blijven leeg. Terwijl geterrormessage_ex6 de omschrijving van de fout (286 in dit geval) had moeten terug geven

EDIT:
weer wat gevonden: buffer die meegegeven wordt moet minimaal 256 byte groot zijn (waarom, dat weet alleen de kerstman, aangezien een error max 100 tekens is)
functie werkt onder c++ iig wel

[ Voor 9% gewijzigd door elgringo op 01-06-2007 10:46 ]

if broken it is, fix it you should


  • elgringo
  • Registratie: Januari 2001
  • Laatst online: 16-09 20:30
MLM schreef op vrijdag 01 juni 2007 @ 09:41:
ik heb eerder "3rd party" gewrapped voor .NET talen, om het hele marshalling gedoe makkelijker te maken, doe ik alle malloc/new calls in unmanaged code (C++/CLI), en wrap ik alle functies in in een (managed) static class :)

dan krijg je een opbouw als:
[jouw app (.NET)] -- imports -> [een wrapper .NET/native gemengd] -- linkt tegen -> [3rd party native .lib/.dll]
voordeel is dat je al het "gedoe" met [DLLImport ...] tags en marshalling maar 1x doet, en in die aparte library, zodat je je daar niet meer druk over hoeft te maken in je uiteindelijke app :)

dat vereist natuurlijk wel (een beetje) kennis van C++, en (aanrader) bouw je wrapper zo safe mogelijk (check alle return values, maak voor elke mogelijke error een exception aan)

edit: ik zie dat MTWZZ net ook al zoiets zegt :|
Jij stelt dus voor om een wrapper in C++ te schrijven die de siemens dll communiceert. Deze c++ wrapper wordt door c# weer gebruikt.

Ik wilde zelf een statische c# class maken die alle zooi bevat. Deze class heeft een aantal public c# functies die gebruikt gaan worden in de rest vd code. Wat heeft jou idee als voordeel?

if broken it is, fix it you should


  • elgringo
  • Registratie: Januari 2001
  • Laatst online: 16-09 20:30
Woei, en onder C# werkt het ook. Ik heb een stringbuilder gebruikt met meer dan 256 tekens.

Nu blijft alleen de vraag over hoe ik die unsigned char * moet verwerken

if broken it is, fix it you should


  • Piels
  • Registratie: Maart 2001
  • Laatst online: 27-11 14:22
Een unsigned char * lijkt me gewoon een byte * in C#

Windows Phone Apps: Belstatus, Pinautomaten

Pagina: 1