[ vbvlada @ 18.11.2010. 11:27 ] @
OK, jasno mi je kako da uključim C-ovsku funkciju iz DLL-a (DLLImport), ali ne znam kako da uključim strukture koje su definisane u .h datoteci.
U toj .h datoteci su deklarisane sve konstante, promenljive, strukture i funkcije. Funkcije koriste strukture kao ulazno-izlazne argumente.

Ima li neko ideju kako se ovo koristi, mislim da mi fali dosta znanja kako se bezbedno "šeta" iz managed koda u unmanaged kod.

Konkretno, želim da koristim API za čitanje elektronske lične karte ("CelikAPI.dll") koji je pisan u C-u, a želim da ga koristim u C#-u.
[ mmix @ 18.11.2010. 11:38 ] @
moraces isto sam da definises strukture kroz marshalling.

pocni odavde
http://msdn.microsoft.com/en-us/library/ef4c3t39.aspx
[ vbvlada @ 19.11.2010. 14:06 ] @
Kaže mi da "signature" moje i C-ovske strukture nisu isti, u strukturi u C-u imam char[], možda mu to smeta, probao sam to da mapiram u string ali ništa.
[ mmix @ 19.11.2010. 15:20 ] @
Ko ti kaze?


ok, strignove marsalujes sa [MarshalAs(UnmanagedType.LPTStr)] atributom a deklarises kao string ili kao StringBuilder (u zavisnosti dal modifikujes ili samo citas string)

ne zabroavi da stavis CharSet = CharSet.Ansi u DllImport

[ vbvlada @ 22.11.2010. 09:38 ] @
Miljane, vidim da se razumeš prilično dobro i u ovo, pa ako možeš malo da mi pomogneš. Evo greške:

A call to PInvoke function 'CELIK_API!CELIK_API.Form1::EidReadFixedPersonalData' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

Ovo je nakon nekoliko pokušaja da napišem strukturu, ali ne znam gde šta ide.
Evo jedne od struktura koje se tamo koriste, ovo je iz .h datoteke:
Code:

typedef struct tagEID_FIXED_PERSONAL_DATA
{
    char personalNumber[EID_MAX_PersonalNumber];
    int personalNumberSize;
    char surname[EID_MAX_Surname];
    int surnameSize;
    char givenName[EID_MAX_GivenName];
    int givenNameSize;
    char parentGivenName[EID_MAX_ParentGivenName];
    int parentGivenNameSize;
    char sex[EID_MAX_Sex];
    int sexSize;
    char placeOfBirth[EID_MAX_PlaceOfBirth];
    int placeOfBirthSize;
    char stateOfBirth[EID_MAX_StateOfBirth];
    int stateOfBirthSize;
    char dateOfBirth[EID_MAX_DateOfBirth];
    int dateOfBirthSize;
    char communityOfBirth[EID_MAX_CommunityOfBirth];
    int communityOfBirthSize;
} EID_FIXED_PERSONAL_DATA, *PEID_FIXED_PERSONAL_DATA;


Ovo je test koji puca nakon poziva druge funkcije:
Code:

        [DllImport("CelikApi.dll", CharSet=CharSet.Ansi)]
        public static extern int EidStartup(int nApiVersion);
        [DllImport("CelikApi.dll", CharSet = CharSet.Ansi)]
        public static extern int EidReadFixedPersonalData(LicniPodaci pData);

        public Form1()
        {
            InitializeComponent();
            int i = EidStartup(1); // ovo radi
            LicniPodaci pData = new LicniPodaci();
            EidReadFixedPersonalData(pData); // ovde prikazuje onu gresku
            string test = pData.communityOfBirth;
        }

A ovo je struktura iz poslednjeg pokušaja:
Code:

[StructLayout(LayoutKind.Sequential)]
    public struct LicniPodaci
    {
        [MarshalAs(UnmanagedType.LPTStr)]
        public string personalNumber;
        public int personalNumberSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string surname;
        public int surnameSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string givenName;
        public int givenNameSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string parentGivenName;
        public int parentGivenNameSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string sex;
        public int sexSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string placeOfBirth;
        public int placeOfBirthSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string stateOfBirth;
        public int stateOfBirthSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string dateOfBirth;
        public int dateOfBirthSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string communityOfBirth;
        public int communityOfBirthSize; 
    }

A mogu da pošaljem i ceo .h fajl, pa da sve razjasnimo...
[ mmix @ 22.11.2010. 12:41 ] @
Problem ti je sa char[xxx] deloima strukture, ti ih marshalujes kao pointere (4byte) umesto kao niz

takvi nizovi se marshaluju sa

Code (csharp):

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = <vrednost EID_MAX_PersonalNumber>)]
public string personalNumber;

... // svi ostali char[xxx] isto tako
 


Imas ovde vise informacija o nacinima da marshalujes razlicite forme stringova: Default Marshaling for Strings
[ vbvlada @ 22.11.2010. 12:52 ] @
Ipak sam uspeo da pročitam. Evo dela strukture, ovako je uspelo:

Code:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct LicniPodaci
    {
        [MarshalAs(UnmanagedType.ByValTStr,SizeConst=14)]
        public string personalNumber;
        public int personalNumberSize;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
        public string surname;
        public int surnameSize;



Ovo su deklaracije funkcija:
Code:

       [DllImport("CelikApi.dll")]
        public static extern int EidStartup(int nApiVersion);
        [DllImport("CelikApi.dll",CharSet = CharSet.Auto)]  // nije htelo ni kada stoji ANSI, niti kada ne stoji ništa
        public static extern int EidReadFixedPersonalData([Out] out LicniPodaci pData);
        [DllImport("CelikApi.dll")]
        public static extern int EidBeginRead([MarshalAs(UnmanagedType.LPTStr)] string szReader);
        [DllImport("CelikApi.dll")]
        public static extern int EidEndRead();
        [DllImport("CelikApi.dll")]
        public static extern int EidCleanup();


Sada imam problem sa ćirilicom: Ime i prezime mi je na ćirilici (to se loše prikaže), dok je ostalo na latinici (a to se dobro prikaže).
Probao sam sa Encode.Convert, nekoliko kombinacija, ali nikad ne dobijam ono što treba.
Recimo ime mi prikaže ovako: ВЛАДИМИР
Kao što se gore u kodu vidi, morao sam da stavim da mi je JMBG dužina 14 a ne 13, jer nije hteo da mi pročita poslednju cifru, a tako isto i za datum. Ne znam ima li ovo veze sa ćirilicom, tj. da li postoji međusobni uticaj dužina polja u strukturi?


[Ovu poruku je menjao vbvlada dana 22.11.2010. u 14:03 GMT+1]
[ Mihajlo Cvetanović @ 22.11.2010. 13:47 ] @
Nemam preterano iskustva sa maršalovanjem, a i ono što imam je umočeno u gorki sirup, ali poslušaj šta će ti ovaj starac reći. Neka struktura nema string nego byte[]:

Code:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct LicniPodaci
{
  [MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.U8, USizeConst=14)]
  public byte[] personalNumber_Marshalled;
  public int personalNumberSize;

  public string personalNumber
  {
    get { return Encoding.UTF8.GetString(personalNumber_Marshalled, 0, personalNumberSize); }
  }
}


[Ovu poruku je menjao Mihajlo Cvetanović dana 22.11.2010. u 15:07 GMT+1]
[ mmix @ 22.11.2010. 14:04 ] @
Iskreno koliko vidim po problematici koju si izneo, celikovci su sje*ali konvenciju, njihovi char[] nisu null terminated stringovi vec prosti char buferi, bolje je da iskoristis pristup koji ti je dao Mihajlo, nemoj stavljati 14 tamo gde je 13 remetis poredak podataka posle. Ili to ili da pises C++/CLI wrapper
[ vbvlada @ 22.11.2010. 14:10 ] @
Svaka čast!
Skroz logično i radi :)
Hvala puno!
[ vbvlada @ 22.11.2010. 14:49 ] @
Odradio sam po Mihajlovom predlogu, ok je.
Imao sam još jednu strukturu koja u C-u ima polje byte[].
Ovamo sam je maršalovao kao
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U8, SizeConst = size+1)], kao što vidite i ovde sam morao da dodam još 1, jer je ponovo pucalo, mada ovde možda nisam pogodio tip...

Ovo je super stvar, samo da se savlada, mada vidim da mi fali dosta znanja iz tih stvari koje se nalaze ispod površine...
[ Mihajlo Cvetanović @ 22.11.2010. 15:05 ] @
Moguće je da ta dodatna C struktura nije definisana sa pakovanjem članova na prvi bajt nego na ofsete deljive sa 4 (to jest struktura nije unutar #pragma pack(push, 1) / #pragma pack(pop) direktiva). U tom slučaju dolazi do popunjavanja (padding) međuprostora bajtovima, što praktično dovodi do toga da se nizovi produžuju do prvog sledećeg broja deljivog sa 4.
[ mmix @ 22.11.2010. 15:10 ] @
Nema pragma pack

Iskreno, ja bi ovo odradio kao C++/CLI wapper assembly. Nema puno posla a trajno bi resilo problem svima, uradio bi vam to ali ne mogu da testiram, nemam cipovanu licnu kartu :)
[ vbvlada @ 23.11.2010. 09:25 ] @
Ja se stvarno ne razumem u ove stvari, C sam samo protrčao školski, pa se borim da razumem sve što pišete, a vama svaka čast :)
Mislio sam da mi ovaj test program sada radi, međutim, radio je ok samo u Debug-u. Imam dve strukture sa podacima, a jednu neće da mi pročita kada nije u Debug-u.
Mmix, ja imam volju da zajedno odradimo ovo po tvom predlogu. Imam čitač i l.k. sa čipom, a mogu da ih nađem još od kolega.
Pa ako ste za, možemo ovo da sredimo, stvarno bi bilo korisno da imamo gotov kod za korišćenje, a ne da se ovako svako ponaosob muči.
[ mmix @ 23.11.2010. 09:38 ] @
Stize mi veceras licna karta od sestre pa cu odraditi sutra ujutro. Vidim da vec ima nekoliko vas koji se patite sa time a bice vas jos vise kako se LK budu masovnije citale, uradicu wrapper pa cu okaciti.

[ vbvlada @ 23.11.2010. 09:56 ] @
Super!
Računam da ću iz toga da provalim kako se pišu ti wrapperi.

Šta je još zanimljivo: U ovom API-u nema čitanja email-a i bračnog statusa, a kolega mi reče da je bio u Vip-u i da su oni izvukli i te podatke.

Ja sam malo prerano postavio temu, jer je jedna bila već postavljena za ovaj CelikAPI, a tamo je neko rekao da API koristi neki Windows-ov dll, čini mi se scard.dll. Ima li svrhe da istražujemo i u tom pravcu?
Meni bi dosta značilo da pročitam i mail (broj telefona ako ima), mada se ja uopšte ne sećam da sam davao mail kada sam vadio l.k.
[ mmix @ 23.11.2010. 10:06 ] @
Ja koliko znam mail nema, ne verujem ni da telefon ima. Ali moguce je da apliakcija VIPa kombinuje LK i unete podatke da odstampa onaj list.
[ vbvlada @ 23.11.2010. 10:16 ] @
Ne znam, ni meni nije poznato za mail, ali tako mi kolega reče, možda nije lepo video. Ok, do sutra onda :)
[ mmix @ 23.11.2010. 20:01 ] @
Nije uopste tesko, vec sam izvukao image u Bitmap i fixed personal, odradio sam i disposable patern i skrivenu globalnu inicijalizaciju i cleanup. Visok stepen apstrakcije, sto bi rekli
Da odradim ujutro i variable i documents pa cu okaciti sors svega



*jmbg je tu al nije za javnost
[ mmix @ 24.11.2010. 10:26 ] @
Ok, mali test, imam neki problem al ne znam dal je do mog drajvera ili do implemetnacije.

Prikacen je primer, probajte da li odradi ili baci exception? (meni posle random broja komandi odbije poslusnost sa -7 card missing)

[ vbvlada @ 24.11.2010. 10:40 ] @
Evo probaću ja sada...

Inače, i mup-ova aplikacija nekada meni prijavi grešku.
Ja sam na Win 7, nešto mi se čudno ponaša, moguće je da je do drajvera...
Javljam se posle testiranja.
[ vbvlada @ 24.11.2010. 10:47 ] @
Uh, ovo je neugodno, mislio sam da kod tebe neće da se desi isto kao u mom kodu:
Ispišeš u konzoli "Varijabilni podaci", i tada sledi izuzetak Card missing.

Kao što sam gore napisao, ako pokrenem program u Debug-u, varijabilni podaci se pročitaju, a bez debug-a mi se ne prikaže ništa, s tim što ja nisam imao exception, već sam dobijao prazna polja. A ja sam radio u Win forms aplikaciji...

Pri testiranju ovoga svaki put baci exception kod mene, a ne posle random broja komandi.
[ vbvlada @ 24.11.2010. 10:52 ] @
Da li možda ima veze sa redosledom pozivanja C-ovskih funkcija?
Startup, BeginRead, Readxxx, EndRead, Cleanup...
Ne znam da li je možda bitno da se svi podaci pročitaju u jednom cugu ili možda "konekcija" treba da se otvara posebno za svaku vrstu podataka...
[ Mihajlo Cvetanović @ 24.11.2010. 11:06 ] @
Startup i Cleanup moraju da se pozivaju tačno jednom tokom rada programa. Nastaju problemi ako se pozivaju više puta.
[ vbvlada @ 24.11.2010. 12:38 ] @
Ok, ja sam te dve stavio u konstruktoru forme i na Form_Closing.

Ja dobijam -1 (EID_E_GENERAL_ERROR) kada čitam var. podatke bez debug-a ali situacija je sledeća:
Click jednom, vrati mi -1 (za var. data) i pročita fixed data.
Click drugi put vrati mi 0 za var. data ali mi ne pročita fixed data.
Nakon par klikova čita mi sve, pa mi onda pročita samo fixed ili var. data, sve je skroz nasumično.
Pa mi nekad vrati -1 a pročita podatke i tako u krug.
[ vbvlada @ 25.11.2010. 11:49 ] @
Gde smo stali, šta se dešava?
Da li je drajver ili je kod?
Probaću kako ovo moje radi na XP SP3...
[ mmix @ 25.11.2010. 13:17 ] @
Stali smo dotle da je meni uleteo paid project audit :)

ovoj nas mali LGPL projekat ce morati da saceka vikend.
[ vbvlada @ 25.11.2010. 15:24 ] @
Hm...
Ovo što sam ja pisao lepo radi na XP SP3, testirao sam par puta.
Ja imam ne tako nov čitač, na kome piše da je za 98 i XP.
Ja sam našao driver za Win 7, međutim ne radi kako valja, i stalno pokreće Found New Hardware kada ubacim ličnu kartu, nakon čega kaže da nije uspeo da instalira smart karticu ( dok je driver za čitač kao OK).
[ mmix @ 25.11.2010. 16:00 ] @
Da nije omnikey 3121 ;) i meni se isto tako ponasa.

kako radi ovaj moj primer na xpu?

[ vbvlada @ 25.11.2010. 17:05 ] @
Nije taj čitač, sad ne mogu da vidim, ali mislim da je neki EZ....
Nisam se setio, bio sam u žurbi da proverm kako radi i tvoj primer.
Probaću večeras ili sutra ujutru...
[ vbvlada @ 25.11.2010. 22:50 ] @
Miljane, tvoj primer radi na XP-u
Da li ovo znači da je driver u pitanju?
Da li bi nešto značilo kupiti noviji čitač koji je kompatibilan sa Win7?
Inače ja koristim EZ100PU, to je valjda model, a marka je Smart Systems ili SITO, to su dve nalepnice na njemu :)
[ mmix @ 26.11.2010. 08:34 ] @
Onda je do drajvera definitivno, vec sam se bio zabrinuo da sam izgubio "magicni dodir" :)

Videcu ako danas ranije zavrsim ovaj projekat mozda i stignem da dovrsim ovaj rlease. Btw, jel zna neko uopste dal Celik trpi multithreading? Ili da ubacim serijalizaciju?
[ Mihajlo Cvetanović @ 26.11.2010. 09:07 ] @
Mislim da funkcije nisu thread safe.
[ vbvlada @ 26.11.2010. 09:58 ] @
Ja bolje da ćutim :)
Baš da vidim taj kod, šta si ti to radio i zašto se to radi...
[ mmix @ 26.11.2010. 09:59 ] @
OK, msclr::lock it is.
Za sad cu da serijalizujem sve metode pa cemo resavati problem sa threadingom ako nekom bas zafali

[ mmix @ 26.11.2010. 10:56 ] @
Eve ga

CelikNET: LGPL CLR Interop Wrapper za CelikAPI
[ vbvlada @ 26.11.2010. 15:48 ] @
Svaka čast još jednom i hvala!

Zanima me da li bi ovaj pristup mogli da imamo kada bi pravili wrapper za winscard.dll ?
Nisam detaljno izučavao, ali to je opet C-ovska biblioteka koja se valjda koristi generalno za pristup smart kartici.

Ne znam da li sam u pravu, ali nagađam da onaj ko pravi neku smart karticu definiše imena ili adrese memorijskih lokacija za podatke, a da se korišćenjem winscard biblioteke pristupa tim podacima.

Bilo bi dobro kada bi mogli da imamo .NET podlogu za generalni pristup.