[ miki78ns @ 12.08.2009. 15:04 ] @
Pokusavam napraviti aplikaciju koja cita podatke sa novih licnih karti da bih kasnije moglo da se implementira u neke druge programe. Sva upustva, header fajl , dll se nalaze na
http://www.mup.sr.gov.yu/domino/dokumenta.nsf/aplikacijalkl
Kompajlirao sam nejavlja gresku ali kad pokrenem program javlja mi neki error kao na slici u dodatku.
Jos par pitanja:
1. prototip funkcije EID_API int WINAPI EidStartup(int nApiVersion);
Argument nApiVersion tipa int predstavlja verziju apija cije se funkcije pozivaju, da li to znaci da je nApiVersion=1.01

2. prototip funkcije: EID_API int WINAPI EidBeginRead(LPCSTR szReader);
Argument szReader tipa LPCSTR koji treba da bude ime smart kard citaca koji se koristi.
Ja imam MSI StarReader 74-in-1 sta se tu smatra pod imenom citaca?


#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <cmath>
#include <cstdlib>
#include "CelikApi.h"

#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif

extern "C"
{
DECLDIR int EidStartup( int );
//DECLDIR void Function( void );
}

using namespace std;
typedef int (*EidStartupFunc)(int);
typedef int (*EidBeginReadFunc)(LPCSTR);
typedef int (*EidCleanupFunc)();
typedef int (*EidEndReadFunc)();
typedef PEID_DOCUMENT_DATA (*EidReadDocumentDataFunc)(PEID_DOCUMENT_DATA);
typedef PEID_FIXED_PERSONAL_DATA (*EidReadFixedPersonalDataFunc)(PEID_FIXED_PERSONAL_DATA);
typedef PEID_VARIABLE_PERSONAL_DATA (*EidReadVariablePersonalDataFunc)(PEID_VARIABLE_PERSONAL_DATA);
typedef PEID_PORTRAIT (*EidReadPortraitFunc)(PEID_PORTRAIT);
HINSTANCE hinetDLL;


int main()
{
EidStartupFunc _EidStartup;
EidBeginReadFunc _EidBeginRead;
EidCleanupFunc _EidCleanup;
EidEndReadFunc _EidEndRead;
EidReadDocumentDataFunc _EidReadDocumentData;
EidReadFixedPersonalDataFunc _EidReadFixedPersonalData;
EidReadVariablePersonalDataFunc _EidReadVariablePersonalData;
EidReadPortraitFunc _EidReadPortrait;

hinetDLL = LoadLibrary(TEXT("CelikApi.dll"));
_EidStartup = (EidStartupFunc)GetProcAddress(hinetDLL,"EidStartup()");
_EidBeginRead = (EidBeginReadFunc)GetProcAddress(hinetDLL,"EidBeginRead()");
_EidReadDocumentData = (EidReadDocumentDataFunc)GetProcAddress(hinetDLL,"EidReadDocumentData()");
_EidReadFixedPersonalData = (EidReadFixedPersonalDataFunc)GetProcAddress(hinetDLL,"EidReadFixedPersonalData()");
_EidReadVariablePersonalData = (EidReadVariablePersonalDataFunc)GetProcAddress(hinetDLL,"EidReadVariablePersonalData()");
_EidReadPortrait = (EidReadPortraitFunc)GetProcAddress(hinetDLL,"EidReadPortrait()");
_EidCleanup = (EidCleanupFunc)GetProcAddress(hinetDLL,"EidCleanup()");
_EidEndRead = (EidEndReadFunc)GetProcAddress(hinetDLL,"EidEndRead()");

cout << _EidStartup << endl;
cout << _EidBeginRead << endl;
cout << _EidEndRead << endl;
cout << _EidCleanup << endl;
system("PAUSE");
return 0;
FreeLibrary(hinetDLL);
}


[Ovu poruku je menjao miki78ns dana 13.08.2009. u 21:36 GMT+1]

[Ovu poruku je menjao miki78ns dana 13.08.2009. u 22:17 GMT+1]
[ Mihajlo Cvetanović @ 12.08.2009. 15:46 ] @
Nisam radio sa pozivanjem funkcija preko LoadLibrary, pa nagađam, možda oni typedef-ovi moraju da stoje unutar extern "C" bloka. Slika koju si dao nije preterano informativna. Da li aplikacija puca na isti način i ako statički linkuješ dll?

1. Broj 1 je trenutno jedina prihvatljiva vrednost. Nema nikakvo značenje preko toga što je to broj 1. Možeš eventualno da ga posmatraš ne kao verziju API-ja, nego kao verziju interfejsa API-ja. Ako se recimo neka struktura bude menjala onda bi promenom ovog broja koristio te proširene strukture.

2. String se koristi ako imaš više čitača instaliranih, jer onda moraš da biraš čitač. Ako imaš samo jedan čitač onda stavi prazan string, koji znači "gledaj prvi sa spiska". Prihvatljivi su oni stringovi čija se imena ključeva (foldera) u registru nalaze na mestu HKLM\SOFTWARE\Microsoft\Cryptography\Calais\Readers. Programerski se do ovih stringova dolazi funkcijama Card Managera (SCardEstablishContext, SCardListReaders, SCardFreeMemory, SCardReleaseContext).
[ kiklop74 @ 13.08.2009. 16:56 ] @
Tvoj kod je neispravan. Nepravilno si deklarisao tip funkcije i pogresno koristis GetProcAddress. GetProcAddress trazi SAMO ime funkcije bez zagrada.

Ispravna deklaracije bilo koje funkcije trazi i calling-convention koju ti nisi naveo:

Ovo :

Code:

typedef int (* EidStartupFunc)(int);
typedef int (*EidBeginReadFunc)(LPCSTR);
typedef int (*EidCleanupFunc)();
typedef int (*EidEndReadFunc)();
////..... itd


Treba da izgleda ovako:

Code:

typedef int (WINAPI * EidStartupFunc)(int);
typedef int (WINAPI * EidBeginReadFunc)(LPCSTR);
typedef int (WINAPI * EidCleanupFunc)();
typedef int (WINAPI * EidEndReadFunc)();
///.... itd



Dalje umesto ovog:

Code:

_EidBeginRead = (EidBeginReadFunc)GetProcAddress(hinetDLL,"EidBeginRead()");


ide ovo:

Code:

_EidBeginRead = (EidBeginReadFunc)GetProcAddress(hinetDLL,"EidBeginRead");


A kada vec koristis c++ bolje je ovo:

Code:

_EidBeginRead = reinterpret_cast<EidBeginReadFunc>( GetProcAddress(hinetDLL,"EidBeginRead"));

[ miki78ns @ 13.08.2009. 20:36 ] @
Hvala sad radi posle ovih izmena od kiklop74. Rezultat ovog

cout << _EidStartup << endl;
cout << _EidBeginRead << endl;
cout << _EidEndRead << endl;
cout << _EidCleanup << endl;

programa je:

0
1
1
1
Press any key to continue . . .

0 znaci da je EidStartup funkcija uspesno izvrsena, cudi me da su ostale tri vrednosti 1 jer u celikapi.h su sve negativne vrednosti za ostale tipove gresaka:
const int EID_OK = 0;
const int EID_E_GENERAL_ERROR = -1;
const int EID_E_INVALID_PARAMETER = -2;
const int EID_E_VERSION_NOT_SUPPORTED = -3;
const int EID_E_NOT_INITIALIZED = -4;
const int EID_E_UNABLE_TO_EXECUTE = -5;
const int EID_E_READER_ERROR = -6;
const int EID_E_CARD_MISSING = -7;
const int EID_E_CARD_UNKNOWN = -8;
const int EID_E_CARD_MISMATCH = -9;
const int EID_E_UNABLE_TO_OPEN_SESSION = -10;
const int EID_E_DATA_MISSING = -11;
const int EID_E_CARD_SECFORMAT_CHECK_ERROR = -12;
const int EID_E_SECFORMAT_CHECK_CERT_ERROR = -13;

pa sam i ja ocekivao da ce biti -1. Cudno je da daje isti rezultat i kad izvadim licnu iz citaca. Inace, program Celik sa sajta MUP-a radi sto znaci da je moj msi citac ispravan.

[ Mihajlo Cvetanović @ 14.08.2009. 09:42 ] @
Meni je s druge strane čudno i 0 i 1 jer se funkcije ne pozivaju tako. Fale ti zagrade, a fale ti i parametri u pozivima. Čini se da do sada nikad nisi radio sa GetProcAddress i pointerima na funkcije. I ja to ne upotrebljavam, ali tu negde moraju da budu parametri, što znači da moraju da postoje i neke zagrade.

To što za prvu funkciju vraća nulu verovato znači da GetProcAddress za nju nije uspeo.
[ miki78ns @ 14.08.2009. 14:31 ] @
ako izmenim da bude ovako:
cout << _EidStartup(1) << endl;
cout << _EidBeginRead("0") << endl;
cout << _EidEndRead() << endl;
cout << _EidCleanup() << endl;

rezultat:
0
0
0
0

sto znaci da su sve cetiri funkcije dobro izvrsene. Ali isto daje i kad citac nije prikljucen.Mozda ce reagovati kad se upotrebe funckije _EidReadDocumentData koja cita podatke iz licne.
Ako stavim ovako samo primera radi ocekujuci negativne vrednosti greske:
cout << _EidStartup(1) << endl;
cout << _EidBeginRead << endl;
cout << _EidEndRead() << endl;
cout << _EidCleanup() << endl;

rezultat:
0
1
-5
0

-5 znaci UNABLE_TO_EXECUTE i to je u redu ali 1 nije negativna.
[ Mihajlo Cvetanović @ 14.08.2009. 14:51 ] @
String koji se daje u funkciji EidBeginRead se u tom trenutku samo čuva, ali se ne koristi. To znači da funkcija vraća 0 šta god da navedeš kao čitač. Funkcije koje čitaju podatke će vratiti grešku ako se navede pogrešan string, kao što je recimo "0" koji si naveo u primeru.

Što se tiče 1 za _EidBeginRead opet si izostavio zagrade pa si opet dobio 1. Bez zagrada pointer na funkciju je samo jedna promenljiva čija se vrednost nekako konvertuje u 1 kad pozoveš cout. Kad bi na primer pozvao printf("%08X", _EidBeginRead), dobio bi adresu u memoriji gde se nalazi učitana funkcija. To što dobijaš 1 umesto 0 ili negativnog broja nema nikakve veze sa Čelikovim dll-om, nego sa tvojim pogrešnim kodom.
[ miki78ns @ 14.08.2009. 21:48 ] @
mora ici taj LPCSTR pod "" jer drugacije mi javlja gresku pri kompajliranju. Znaci ovako moze:
cout << _EidBeginRead("szReader") << endl;

moze mala pomoc kako pozvati ovu funkciju _EidReadDocumentData to je struktura podataka pa se nesnalazim najbolje.


[Ovu poruku je menjao miki78ns dana 15.08.2009. u 00:00 GMT+1]
[ Mihajlo Cvetanović @ 15.08.2009. 18:46 ] @
Šta ti nije jasno? Jesi li ikad radio sa strukturama?
[ kiklop74 @ 16.08.2009. 00:01 ] @
npr.

Code:


EID_DOCUMENT_DATA data = {0};

int result = EidReadDocumentData(&data);



Usput tvoje definicije funkcija EidReadDocumentData, EidReadFixedPersonalData, EidReadVariablePersonalData, EidReadPortrait su netacne jer svaka od njih vraca int a ne pointer na neku od struktura sto se i vidi iz originalnog hedera.

Code:

EID_API int WINAPI EidReadDocumentData(PEID_DOCUMENT_DATA pData);
EID_API int WINAPI EidReadFixedPersonalData(PEID_FIXED_PERSONAL_DATA pData);
EID_API int WINAPI EidReadVariablePersonalData(PEID_VARIABLE_PERSONAL_DATA pData);
EID_API int WINAPI EidReadPortrait(PEID_PORTRAIT pData);


odnosno:

Code:

typedef int (WINAPI *EidReadDocumentDataFunc)(PEID_DOCUMENT_DATA);
///... itd


Vidi se da si veoma nov u celoj ovoj stvari. Bavi se citanjem tutorijala, bolje nego da zavisis od drugih.

[ nepodmitljivi @ 09.12.2009. 13:34 ] @
Izvinite sto podizem temu iz mrtvih, ali da li je neko probao da naizmenicno poziva _EidStartup i _EidCleanup?
Otkud mi takva ideja pitate se vi? Napravio sam svoj dll u C# (mislim da je programski jezik nebitan) koji koristim iz neke trece aplikacije i sve lepo radi pri citanju el. l. k., dobijem podatke, popunim svoja polja, snimim u bazu, sve radi kako treba. Ali sasvim slucajno ponovo pritisnem dugme za citanje i dobijem gresku EID_E_UNABLE_TO_EXECUTE = -5 u pozivu _EidStartup. Postovao sam proceduru prilikom citanja, prvo startup, pa begin read, pa onda citam podatke i punim neku svoju strukturu, pa na kraju end read i cleanup. Ocigledno cleanup ne radi kako treba posto gresku javlja prilikom sledeceg poziva EidStartup (otud i naizmenicno pozivanje _EidStartup i _EidCleanup, koje bi trebalo bez problema da prolazi, zar ne?)
Da bi ponovo procitao licnu kartu moram da resetujem program, ne pomaze vadjenje l.k./citaca.
[ Mihajlo Cvetanović @ 09.12.2009. 14:04 ] @
Da, u pitanju je greška u EidCleanup. Da bi zaobišao grešku probaj da preurediš kod tako da se EidStartup i EidCleanup pozivaju samo jednom, prvi na početku rada programa, a drugi na kraju.
[ nepodmitljivi @ 10.12.2009. 09:33 ] @
Hvala na odgovoru, pretpostavio sam da cu morati nesto tako da muljam, ali mi to pravi bas veliki problem jer je struktura programa takva da to ne bi trebalo tako da se radi. Ali nije to poenta sad, drugo pitanje, da li je neko slao obavestenje o problemu na onu adresu [email protected], ima li vajde od toga, sprema li se mozda nova verzija API-ja?
[ nash2k @ 16.12.2009. 10:16 ] @
Da li ovaj dll može da se koristi iz VB 6. Ako može, kako bi to trebalo da se izvede, jer ne mogu da ga registrujem, a da ne pričam o tome da nemam pojma kako bih deklarisao tipove pojedinih funkcija i argumenata. Svaka pomoć je dobrodošla :)
[ kiklop74 @ 16.12.2009. 14:18 ] @
Moze. Pogledaj ovaj sajt koji govori o API funkcijama u vb6 . Taj princip treba primeniti i na ovaj dll.

http://allapi.mentalis.org/vbtutor/api1.shtml
[ nash2k @ 16.12.2009. 14:22 ] @
Hvala, vec sam izguglao neke artikle na temu, radi se na isprobavanju
[ nash2k @ 16.12.2009. 16:46 ] @
Nakon malo (više) istraživanja na temu prosledjivanja struct parametara čiji su članovi nizovi bajtova, došli smo do problema. Nakon poziv funkcije EidReadDocumentData vraća grešku -6 (EID_E_READER_ERROR).
Pošto card reader radi sa Čitačem elektronske lične karte, ne liči da je on neispravan. Dakle deluje da sam poziv funkcije ima neki problem.
[ kiklop74 @ 16.12.2009. 18:53 ] @
Ovo bi trebalo da bude kompletan port

Code:

Rem Celikapi.bas

Const EID_MAX_DocRegNo = 9
Const EID_MAX_IssuingDate = 10
Const EID_MAX_ExpiryDate = 10
Const EID_MAX_IssuingAuthority = 30

Const EID_MAX_PersonalNumber = 13
Const EID_MAX_Surname = 60
Const EID_MAX_GivenName = 40
Const EID_MAX_ParentGivenName = 25
Const EID_MAX_Sex = 2
Const EID_MAX_PlaceOfBirth = 25
Const EID_MAX_StateOfBirth = 25
Const EID_MAX_DateOfBirth = 10
Const EID_MAX_CommunityOfBirth = 25

Const EID_MAX_State = 3
Const EID_MAX_Community = 25
Const EID_MAX_Place = 25
Const EID_MAX_Street = 36
Const EID_MAX_HouseNumber = 5
Const EID_MAX_HouseLetter = 2
Const EID_MAX_Entrance = 3
Const EID_MAX_Floor = 3
Const EID_MAX_ApartmentNumber = 6

Const EID_MAX_Portrait = 7700

//
// Function return values
//

Const EID_OK                            =  0
Const EID_E_GENERAL_ERROR               = -1
Const EID_E_INVALID_PARAMETER           = -2
Const EID_E_VERSION_NOT_SUPPORTED       = -3
Const EID_E_NOT_INITIALIZED             = -4
Const EID_E_UNABLE_TO_EXECUTE           = -5
Const EID_E_READER_ERROR                = -6
Const EID_E_CARD_MISSING                = -7
Const EID_E_CARD_UNKNOWN                = -8
Const EID_E_CARD_MISMATCH               = -9
Const EID_E_UNABLE_TO_OPEN_SESSION      = -10
Const EID_E_DATA_MISSING                = -11
Const EID_E_CARD_SECFORMAT_CHECK_ERROR  = -12
Const EID_E_SECFORMAT_CHECK_CERT_ERROR  = -13


Public Type EID_DOCUMENT_DATA
    docRegNo As String * EID_MAX_DocRegNo
    docRegNoSize as Long
    issuingDate as String * EID_MAX_IssuingDate
    issuingDateSize as Long
    expiryDate as String * EID_MAX_ExpiryDate
    expiryDateSize as Long
    issuingAuthority as String * EID_MAX_IssuingAuthority
    issuingAuthoritySize as Long
End Type

Public Type EID_FIXED_PERSONAL_DATA
    personalNumber As String * EID_MAX_PersonalNumber
    personalNumberSize As Long
    surname As String * EID_MAX_Surname
    surnameSize As Long
    givenName As String * EID_MAX_GivenName
    givenNameSize As Long
    parentGivenName As String * EID_MAX_ParentGivenName
    parentGivenNameSize As Long
    sex As String * EID_MAX_Sex
    sexSize As Long
    placeOfBirth As String * EID_MAX_PlaceOfBirth
    placeOfBirthSize As Long
    stateOfBirth As String * EID_MAX_StateOfBirth
    stateOfBirthSize As Long
    dateOfBirth As String * EID_MAX_DateOfBirth
    dateOfBirthSize As Long
    communityOfBirth As String * EID_MAX_CommunityOfBirth
    communityOfBirthSize As Long
End Type


Public Type EID_VARIABLE_PERSONAL_DATA
    state As String * EID_MAX_State
    stateSize As Long
    community As String * EID_MAX_Community
    communitySize As String
    place As String *EID_MAX_Place
    placeSize As Long
    street As String * EID_MAX_Street
    streetSize As Long
    houseNumber As String * EID_MAX_HouseNumber
    houseNumberSize As Long
    houseLetter As String * EID_MAX_HouseLetter
    houseLetterSize As Long
    entrance As String * EID_MAX_Entrance
    entranceSize As String
    floor As String * EID_MAX_Floor
    floorSize As Long
    apartmentNumber As String * EID_MAX_ApartmentNumber
    apartmentNumberSize As Long
End Type

Public Type EID_PORTRAIT
    portrait As Byte * EID_MAX_Portrait
    portraitSize As Long
End Type

Public Declare Function EidStartup Lib "celikapi"  (ByVal nApiVersion as Long) As Long
Public Declare Function  EidCleanup Lib "celikapi" () As Long

Public Declare Function EidBeginRead Lib "celikapi"  (ByVal szReader As String) As Long
Public Declare Function EidEndRead Lib "celikapi"  () As Long

Public Declare Function EidReadDocumentData Lib "celikapi"  (pData As EID_DOCUMENT_DATA) As Long
Public Declare Function EidReadFixedPersonalData Lib "celikapi"  (pData As EID_FIXED_PERSONAL_DATA) As Long
Public Declare Function EidReadVariablePersonalData Lib "celikapi"  (pData As EID_VARIABLE_PERSONAL_DATA) As Long
Public Declare Function EidReadPortrait Lib "celikapi"  (pData As EID_PORTRAIT) As Long

[ nash2k @ 17.12.2009. 10:08 ] @
Prvo, hvala na odgovoru.

Dakle, već sam napravio ovakve deklaracije, čak sam eksperimentisao deklaracijom niza bajtova, pa sam probao i ovako kao sto si ti napisao, a probao sam i da ih prevedem kao niz bajtova. Obe stvari su mi proizvodile istu gresku.
Mozda je problem u inicijalizaciji promenjivih pre poziva funkcije. Ne znam. Kod poziva funkcije EidBeginRead, parametar je naziv readera? Ja joj prosledjujem "CardMan 3x21" kako mi stoji u device manageru, da li mozda treba nesto drugo?
[ Mihajlo Cvetanović @ 17.12.2009. 11:06 ] @
Ako ti je to jedini čitač priključen na računar onda kao ime čitača stavi prazan string (što znači "gledaj prvu karticu na koju naletiš po spisku s bilo kog čitača"). Jedino ako praviš program koji koristi više čitača, ili ako neki korisnik koristi neki drugi čitač s drugom karticom onda imaš potrebu da navedeš ime čitača. Imena svih čitača priključenih na računar dobijaš sistemskim funkcijama (SCardEstablishContext, SCardListReaders, SCardFreeMemory, SCardReleaseContext). Ova SCardListReaders je glavna stvar, ali ponavljam, ova komplikacija ti treba samo ako ti stvarno treba :-). Ako ti ova komplikacija stvarno treba onda bi trebalo da napraviš GUI opciju za korisnika da odabere čitač sa spiska koji mu daš, a koji si dobio navedenim funkcijama. Imena čitača koje dobiješ pomoću gore navedene sistemske funkcije su stringovi koje daješ funkciji EidBeginRead.
[ nash2k @ 17.12.2009. 11:18 ] @
Haha ne verujem.. Sve vreme mislim da mi portovanje u VB nije dobro, a u stvari mi je problem u pozivu EidBeginRead..
Hvala na ovom razjašnjenju. Trenutno mislim da nam nije potrebna podrška za više čitača, tako da prazan string završava posao.
[ kiklop74 @ 17.12.2009. 13:07 ] @
Kad smo već kod čitača kartica. Koji model bi bio adekvatan za čitanje podataka sa LK? Mislim na nešto što je dostupno u masovnoj prodaji.
[ Mihajlo Cvetanović @ 17.12.2009. 13:47 ] @
Svaki čitač je dobar, razlika je samo u brzini. OmniKey čitači su se pokazali kao good choice. Ima jedan čitač, stari model, više se i ne proizvodi, ali eto treba ga izbegavati jer se blokira sa ličnom kartom: GemPlus 430.
[ nash2k @ 17.12.2009. 16:54 ] @
Omnikey, deluju dobro.
[ nash2k @ 21.12.2009. 12:48 ] @
Još jedna enigma. Možda ima više veze sa samom ličnom kartom nego sa API-jem.
Na primerku lične karte koji ja imam, svi podaci su uredno na latinici sem imena i prezimena, koji su na ćirilici (bar odštampani fizički na LK). Kada kroz API učitam ime i prezime, dobijem kuke i kvake. Da li neko zna je l' ovo Unicode ili nešto drugo? VB6 ih ne voli
[ Mihajlo Cvetanović @ 21.12.2009. 13:20 ] @
Podaci koje dobiješ su podaci sa same kartice, a oni su u UTF-8 formatu. Moguće da u VB postoje posebne funkcije za konverziju, ali tu je i SDK funkcija MultiByteToWideChar kojoj daš vrednost CP_UTF8 za parametar CodePage.
[ nash2k @ 22.12.2009. 10:00 ] @
Hmmm MultiByteToWideChar mi ne vraća ništa, izgleda.. Ali postoji brdo raznih funkcija koje služe za konverzije u raznim smerovima, valjda će neka da radi to što nama treba.. Ali ne mogu a da se ne zapitam, zašto su ime i prezime sačuvani drugačije..
[ Mihajlo Cvetanović @ 22.12.2009. 10:25 ] @
Ima neki zakon u vezi s time, ime i prezime se pišu pismom one nacionalnosti kojoj osoba pripada, a za Srbe je default ćirilica. Ako ti je bitno pismo onda moraš željeno da naglasiš kad ti unose podatke.
[ nash2k @ 22.12.2009. 10:37 ] @
Pa to je baš predivno.. Znači imaćemo i kineska imena onda. Moram da proučim koje sve char setove kinezi koriste, hahahaha omg umrecu..
[ Mihajlo Cvetanović @ 22.12.2009. 11:26 ] @
Ne bih rekao da se koriste pisma koje normalan policajac ne može da pročita. Po zakonu lična karta se ispisuje i na jezicima nacionalnih manjina, pa pretpostavljam da se samo pisma nacionalnih manjina uzimaju u obzir.
[ kiklop74 @ 22.12.2009. 15:01 ] @
U ovom slučaju treba koristiti API funkciju

MultiByteToWideChar za konverziju UTF-8 stringa u Unicode

Code:


Public Const CP_ACP = 0
Public Const CP_OEMCP = 1
Public Const CP_THREAD_ACP = 3
Public Const CP_UTF8 = 65001

Public Declare Function MultiByteToWideChar Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, lpMultiByteStr As Any, ByVal cbMultiByte As Long, lpWideCharStr As Any, ByVal cchWideChar As Long) As Long


Public Function ConvertToUniCode(ByVal SourceStr As String) As String
    Dim UniCodeStr As String
    Dim sLen As Integer
    Dim ret As Long
    
    sLen = Len(SourceStr) * 2
    'MsgBox "sLen = " & sLen
    UniCodeStr = String(sLen, 0) 'pad to correct length with 0's
    'MsgBox UniCodeStr
    ret = MultiByteToWideChar(CP_UTF8, 0, SourceStr & Chr(0), -1, UniCodeStr, sLen)
    'MsgBox "ret = " & ret
    ConvertToUniCode = UniCodeStr
End Function



[ nash2k @ 22.12.2009. 17:06 ] @
Da, to ima smisla, ali po mom skromnom mišljenju, štampani deo lične karte je jedna strana medalje, a druga strana je ono što je pohranjeno na čipu lične karte. Ovaj drugi deo treba ceo da bude u istom pismu, ćiriličnom ili latiničnom, ali ne malo u jednom, a malo u drugom. Neki moji prijatelji, eksperti za standardizaciju, bi imali mnogo toga da kažu na tu temu.
[ nash2k @ 22.12.2009. 17:17 ] @
Za kiklop74:

ovaj kod konzistentno obara VS6 IDE na liniji
Code:

ret = MultiByteToWideChar(CP_UTF8, 0, SourceStr & Chr(0), -1, UniCodeStr, sLen)


Dobije se stara dobra poruka "Please tell Microsoft about this problem" :)
[ kiklop74 @ 23.12.2009. 01:57 ] @
To je kod koji sam negde iskopao. POgledaj ovde cini se da je bolja varijanta

http://www.vbmonster.com/Uwe/F...-to-read-UTF-8-chars-using-VBA

U svakom slucaju uz google ces sigurno naci ono sto ti treba. Cini mi se samo da umesto stringova u onim strukturama za celikapi treba koristiti nizove bajtova.

U svakom slucaju ovo je neopevano smaranje. Mnogo bolje resenje bi bio jos jedan dll u c++ koji bi imao novi set api funkcija prilagodjen VB i slicnim okruzenjima - tj. umesto utf-8 stringova bi vracao normalni unicode i svega ovoga ne bi uopste bilo.

Ako me ne bude mrzelo ovih dana sacinicu jednu verziju toga.

[ kiklop74 @ 23.12.2009. 21:10 ] @
Evo prve verzije dll-a sa sve sors kodom, adekvatnim BAS fajlom i prekompajliranom verzijom dll-a.

http://cablemodem.fibertel.com.ar/mega/celikapivbdll.zip

Ako ima problema dojaviti.
[ nash2k @ 25.12.2009. 10:07 ] @
OK, bice propusteno kroz test
[ nash2k @ 25.12.2009. 10:41 ] @
OK, dobra vest je da svi pozivi funkcija prolaze bez pucanja
Malo sam ispravio EID_PORTRAIT

Code:

Public Type EID_PORTRAIT
        portrait As String * EID_MAX_Portrait
        portraitSize As Long
End Type


i zamenio C komentare // u VB komentare '

U svakom slučaju, okruženje ne zna da mi prikaže pročitane stringove, dok su brojčane vrednosti u redu. Čak nisam siguran da su neka polja uopšte učitana. A neke vrednosti su malo čudne.
Npr. communityOfBirth dobija neku vrednost nakon učitavanja, a communityOfBirthSize dobije vrednost 0, što je nelogično.
dateOfBirth takodje dobija vrednost u nečitljivim characterima, a size mu dobija neki sumanut broj. No, jedna slika vredi hiljadu reči, pa ću probati da zakačim sliku debug prozora..
[ kiklop74 @ 25.12.2009. 13:11 ] @
Mislim da znam u cemu je problem, javicu se ovih dana sa osvezenom verzijom koda.
[ nepodmitljivi @ 11.03.2010. 10:13 ] @
Drugari, ne znam da li je neko probao da pokrece ova nasa pisanija na sedmici, ali aplikacija koju sam ja napravio i koja je besprekorno radila pod XP-om sada neobjasnivo puca pri pozivu EidReadDocumentData, sto mi je najcudnije, jer nista nisam menjao, inicijalizacija prolazi, a pada pri citanju. Inace, koristim neki gemalto smart card reader i sedmica je sama nasla neke, rekao bih genericke drajvere i prepoznala citac bez problema. Skinuo sam i proizvodjaceve drajvere, ali opet isto. Aplikacija sa mupovog sajta radi lepo sa generickim drajverima. .'/
[ Mihajlo Cvetanović @ 11.03.2010. 13:48 ] @
Nije čudo što inicijalizacija prolazi, jer se tu praktično ne dešava ništa vredno pažnje.

Detaljno opiši šta se dešava s programom, i postavi ovde i kod koji pravi problem. Probaj da napraviš minimalnu konzolnu aplikaciju koja lepo čita podatke u XP, a ne radi u Windows 7. Kako izgleda kad debaguješ aplikaciju na Sedmici?
[ nepodmitljivi @ 12.03.2010. 09:16 ] @
[SuppressUnmanagedCodeSecurity()]
public class myIDUnsafeNativeMethods
{
[DllImport(GlobalConstants.myIDApi, CharSet = CharSet.Unicode)]
static internal extern int EidStartup(
int nApiVersion
);

[DllImport(GlobalConstants.myIDApi, EntryPoint = "EidCleanup", CharSet = CharSet.Unicode)]
static internal extern int EidCleanup(
);

[DllImport(GlobalConstants.myIDApi, CharSet = CharSet.Unicode)]
static internal extern int EidReadFixedPersonalData(
ref tagEID_FIXED_PERSONAL_DATA pData
);

[DllImport(GlobalConstants.myIDApi, CharSet = CharSet.Unicode)]
static internal extern int EidReadDocumentData(
ref tagEID_DOCUMENT_DATA pData
);

[DllImport(GlobalConstants.myIDApi, CharSet = CharSet.Unicode)]
static internal extern int EidBeginRead(
[MarshalAs(UnmanagedType.LPStr)] String szReader
);
...



[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public myResult ReadData()
{
myResult tmpResult = new myResult();
int ret;

ret = myIDUnsafeNativeMethods.EidBeginRead(_deviceName);
if (ret < 0)
{
tmpResult.errorCode = ret;
tmpResult.errorMessage = GetErrorMessage(ret) + " _EidBeginRead";
myIDUnsafeNativeMethods.EidEndRead();
return tmpResult;
}
ret = myIDUnsafeNativeMethods.EidReadDocumentData(ref tmpResult.eIdDocumentData);
if (ret < 0)
{
tmpResult.errorCode = ret;
tmpResult.errorMessage = GetErrorMessage(ret) + " _EidReadDocumentData";
myIDUnsafeNativeMethods.EidEndRead();
return tmpResult;
}
...
Nema nekih detalja :) idem kroz kod, EidBeginRead vrati 0, dodjem do EidReadDocumentData i dobijem EID_E_READER_ERROR = -6; Cini mi se da sedmica daje drugacija imena USB uredjajima od XP-a, to sam primetio pomocu ovog programceta http://www.nirsoft.net/utils/usb_devices_view.html, eksperimentisao sam sa _deviceName, ali onda dobijem EID_E_UNABLE_TO_EXECUTE = -5; Dublje od toga ne mogu da udjem kroz debug (cekirao sam u project properties "Enable unmanaged code debug").
[ Mihajlo Cvetanović @ 12.03.2010. 11:07 ] @
Ako imaš samo jedan čitač u sistemu onda stavi prazan string kao ime čitača.
[ irreal @ 04.05.2010. 11:42 ] @
nepodmitljivi, da li možeš ti ili neko drugi ko je koristio dll iz C# / VB.NET-a da mi pokažeš kako si definisao strukturu EID_DOCUMENT_DATA ?

sve mi prolazi bez problema, ali kada god pozovem EidReadDocumentData, dobijem AccessViolationException "Attempted to read or write protected memory. This is often an indication that other memory is corrupt"

prethodne funkcije vracaju eid_ok i sve radi kako treba.

za naziv uredjaja saljem prazan string ("") posto imam samo jedan citac na sistemu.

isto koristim gemalto citac, isto koristim windows 7, medjutim razlika je sto sam aplikaciju testirao i na Win XP (na kojem takodje imam drajvere i radi mup-ova aplikacija) i tu takodje puca pri pozivu EidReadDocumentData

može li iko da mi pomogne?

evo je moja trenutna definicija za eid_document_data, ma da sam probao hiljadu razlicitih nacina do sada:
Code:
        [StructLayout(LayoutKind.Sequential, Size = EID_MAX_IssuingAuthority + EID_MAX_IssuingDate + EID_MAX_DocRegNo + EID_MAX_ExpiryDate), Serializable]
        public class EID_DOCUMENT_DATA
        {
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_DocRegNo)]
            public string docRegNo;
            public int docRegNoSize;
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_IssuingDate)]
            public string issuingDate;
            public int issuingDateSize;
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_ExpiryDate)]
            public string expiryDate;
            public int expiryDateSize;
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_IssuingAuthority)]
            public string issuingAuthority;
            public int issuingAuthoritySize;
        };


(smatram da je nepotrebno da postavljam ostatak koda koji imam jer su definicije funkcija uglavnom identicne kao u kodu koji je postavio nepodmitljivi)
[ apolo469 @ 20.07.2010. 21:31 ] @
Ako je tema ziva jos uvek... Treba mi prikaz podataka sa LK u VB.netu.... onaj celik api sto je okacen na MUP sajtu ne moze da je upotrebi ili ja ne znam kako to da uradim...
Da li je neko pokusao da integrise celik u VB.net ...svaka pomoc bi mi bila dobrodosla

Hvala
[ MAD-MAX @ 07.09.2010. 11:40 ] @
Treba da nekako prosledim ime i prezime koje pročitam sa lične karta nekom mom php skriptu. E sad, problem je kao što je i pisano ovde, što je ime i prezime na ćirilici i ne znam kako da ga prosledim, da li da nekako (ne znam kako) to u samom c++ "prevedem" na latinicu ili kako? Ono sa MultiByteToWideChar mi nije baš najjasnije.

Vidim da neko vreme nije pisano na ovoj temi ali ako je neko nešto konkretno uradio povodom toga bio bi mu zahvalan na pomoći.
[ Goran Rakić @ 07.09.2010. 11:47 ] @
Ime i prezime na samoj ličnoj karti je UTF-8. Samo prosledi to PHP-u, i transliteruj ako želiš bilo pre, bilo posle slanja.

Pogledaj i http://gitorious.org/freesteel za alternativu, može ti biti zgodnije za integraciju.
[ apolo469 @ 07.09.2010. 11:54 ] @
Jel uspeo neko na Linuxu da ocita LK?
[ Goran Rakić @ 07.09.2010. 12:14 ] @
http://blog.goranrakic.com/arc..._licne_karte_za_gnulinuks.html

Citat:

Predstavljam vam slobodan čitač elektronske karte, od milja nazvan FreeSteel. Trenutno, FreeSteel je jednostavna Python skripta koji se oslanja na pyscard i PC/SC i radi na svim poznatim platformama (Linux, Windows, MacOS X). Skript se poziva iz terminala, i ispisuje informacije inače vidljive kroz besplatnu aplikaciju Čitač Elektronske Lične Karte za Windows. Sa argumentom -p program čuva sliku sa lične karte u datoteku <JMBG>.jpg, moguće je i navesti posebno ime sa -p moja_slika.jpg. Opcije -q i -s omogućavaju izvoz X.509 sertifikata sa javnim delom ključa za kvalifikovani i običan elektronski potpis.


Trebalo bi da MUP ima i CelikAPI biblioteku i aplikaciju za GNU/Linuks, ali ja do toga nisam uspeo da dođem. Pokušavam da dođem do tehničke specifikacije operativnog sistema na kartici.
[ MAD-MAX @ 07.09.2010. 12:18 ] @
Citat:
Goran Rakić: Ime i prezime na samoj ličnoj karti je UTF-8. Samo prosledi to PHP-u, i transliteruj ako želiš bilo pre, bilo posle slanja.

Pogledaj i http://gitorious.org/freesteel za alternativu, može ti biti zgodnije za integraciju.


Da stavim www.nesto.com/skirpt.php?name=ВЛАДИМИР

Pokušavao sam to al neće tako. Kako si ti tačno uspevao?
[ Goran Rakić @ 07.09.2010. 12:28 ] @
Šta ti je to "╨Æ╨¢╨É╨ö"?

Ako uradiš ispravan UTF-8 urlencode parametra skript.php?name=GORAN (ćirilicom) radi sasvim normalno (postaje skript.php?name=%D0%93%D0%9E%D0%A0%D0%90%D0%9D) i očitavaš $_GET['name'] kao UTF-8 nisku u PHP-u. Ako koristiš neku biblioteku za slanje HTTP GET zahteva, pogledaj kako ona radi sa UTF-8 tekstom i da li očekuje da urlencode odradiš ti ili biblioteka to radi umesto tebe.

Ne znam koji alat koristiš pa ne mogu da ti više pomognem. Vodi računa da UTF-8 ne učitavaš u široki char tip, već u bajtovsku nisku ili da odradiš ispravnu konverziju (ne preko trenutne sistemske kodne strane). Vodi računa da urlencode koji bi koristio potržava višebajtni UTF-8 zapis.

Problem koji imaš nema veze sa ličnom kartom već time što ne znaš kako da radiš sa UTF-8 tekstom.
[ MAD-MAX @ 07.09.2010. 13:02 ] @
Citat:
Goran Rakić:...
Problem koji imaš nema veze sa ličnom kartom već time što ne znaš kako da radiš sa UTF-8 tekstom.


Upravo tako.

Možda nisam dovoljno precizno formulisao pitanje, moj je i problem što ne znam da radim sa utf-om u C/C++.
Znači kako da iz onog

char givenName[EID_MAX_GivenName];
int givenNameSize;

ja "lepo" pročitam tu ćirilicu i prosledim je php skriptu?
[ Goran Rakić @ 07.09.2010. 13:08 ] @
Zavisi od toga kako je prosleđuješ i da li tvoj PHP očekuje UTF-8 ili CP1251 ili neki drugi kodni raspored? (Ako bi pravio HTML formular, šta bi stavio kao meta charset?)
[ MAD-MAX @ 07.09.2010. 13:45 ] @
utf-8
[ Mali Misha @ 07.09.2010. 13:57 ] @
Ako binarne rezultate iz C++ prikazuješ u PHP preko HTML-a, dovoljno je da u header ubaciš:

Code:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
...
</head>
[ Goran Rakić @ 07.09.2010. 13:58 ] @
Kako šalješ HTTP GET? Imaš li neku biblioteku koju koristiš ili ručno praviš socket pa dalje?
[ MAD-MAX @ 07.09.2010. 14:07 ] @
Moj problem je više sa C++ strane, PHP je u redu. Kada bih ja mogao da u C++-u generišem nešto ovako:

skript.php?name=%D0%93%D0%9E%D0%A0%D0%90%D0%9D

to radi bez problema. I vrednost je promenljive name je GORAN.

Ja iz ovog niza karaktera "char givenName[EID_MAX_GivenName];" kad pročitam šta piše dobijem ovo "╨Æ╨¢╨É╨ö". Inače pravi tekst koji se krije je "VLADIMIR" i to su 8 karaktera, vrednost promenljive givenNameSize je 16 odnosno niz givenName ima 16 elemenata, po dva za svako ćirilično slovo.

Ono što ja ne znam je kako da iz tog niza karaktera "givenName" dobijem vrednost kao na primer "%D0%93%D0%9E%D0%A0%D0%90%D0%9D" koju bi lepo prosledio u URL i posle bi bilo sve ok.
[ MAD-MAX @ 07.09.2010. 14:09 ] @
Imam

char* link = "http://localhost/licna_karta.php?name=";

posle na to treba da dodam vrednost i pozovem

ShellExecute(NULL, "open", a, NULL, NULL, SW_SHOWNORMAL);

Btw "a" je isto tipa char* na koji je nadovezana vrednost promenljive
[ kiklop74 @ 07.09.2010. 14:39 ] @
Na primer:

http://www.codeproject.com/KB/string/urlencode.aspx
[ Mali Misha @ 07.09.2010. 14:40 ] @
Citat:
MAD-MAX: Moj problem je više sa C++ strane, PHP je u redu. Kada bih ja mogao da u C++-u generišem nešto ovako:

skript.php?name=%D0%93%D0%9E%D0%A0%D0%90%D0%9D

to radi bez problema. I vrednost je promenljive name je GORAN.


Aha. Pa to prevodiš u bazu 16, bajt po bajt. Dakle, ako imaš niz od dva bajta (unsigned char-a) 80 i 100. Njih ćeš slati kao: %50%64, jer je 80 u bazi 16 = 50, a 100 u bazi 16 = 64.
[ Goran Rakić @ 07.09.2010. 14:44 ] @
Kao što rekoh, potrebno je da name provučeš kroz urlencode:

Code (c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define hex(c) ( (c)<10 ? '0'+(c) : 'A'+(c)-10 )

char *urlencode(char *s) {
  char *ret = malloc(strlen(s)*3+1), *p = ret;
  while (*s) {
    if (isalnum(*s) || *s == '-' || *s == '_' || *s == '.')
      *p++ = *s;
    else if (*s == ' ')
      *p++ = '+';
    else {
      *p++ = '%';
      *p++ = hex(0xF & (*s>>4)); // visi polubajt
      *p++ = hex(0xF & *s);      // nizi polubajt
    }
    s++;
  }
  *p = '\0';
  return ret;
}

int main() {
  char *str = "GORAN RAKIĆ";
  char *enc = urlencode(str);
  printf("%s\n", enc);
  free(enc);
  return 0;
}

[ MAD-MAX @ 09.09.2010. 10:06 ] @
Hvala vam svima na pomoći. Sada radi kako treba.

Pozdrav!
[ MAD-MAX @ 24.09.2010. 16:57 ] @
Opet ja :)

Imam jedan C++ program koji sam napisao koji radi sledeće. Dok se ne ubaci LK ne radi ništa (čeka u while petlji) a kad se ubaci otvori se browser (što i nije bitno, recimo da hoću da mi na konzoli ispiše "LK in"), kad se LK izvadi ništa se ne dešava (ili neka se ispiše "LK out"), kad se LK ponovo stavi ponovo da mi ispiše "LK in", odnosno meni treba da otvori browser ka nekom mom PHP skriptu gde ja prosleđujem ime, prezime itd itd.

Problem koji imam je da mi funkcije _EidReadFixedPersonalData() i _EidReadVariablePersonalData() vraćaju vrednost koja nije EID_OK odnosno nije 0 iako je LK u čitaču, vrednosti koje dobijam su ili 0 ili -7 ali nikako da dobijem sve nule za obe funkcije kada je LK unutra

Inače primetio sam da kada je LK u čitaču ja za vrednost funkcije _EidReadFixedPersonalData() dobijam naizmenično vrednosti 0 i -7 (a LK je u čitaču) a kad izvadim LK onda je uvek -7 kao što i treba da bude. Da situacija bude još čudnije ponekad mi funkcija _EidReadFixedPersonalData() vrati nekoliko nula pa -7 pa nekoliko nula pa -7 i onda počne ponovo naizmenično 0 i -7

Code:

....
int cc = 0;
while(1) {
    temp = -1;
    cout << "_EidStartup: " << _EidStartup(1) << endl;
    cout << "_EidBeginRead: " << _EidBeginRead("") << endl;

    while(temp !=0){
        temp = _EidReadFixedPersonalData(mojdata);
        // Ovo ispod nije bitno ali mi vardata treba za moj program
        _EidReadVariablePersonalData(vardata); 
        if (cc!=0)
           cout << "Temp je: " << temp << endl;    
    }
    
    // Za potrebe testiranja, da vidim povratnu vrednost
    int i =0;
    while(i<200) {
     cout << _EidReadFixedPersonalData(mojdata) << endl;
     i++;
    }
        
    cout << "LK in" << endl;
    // Ovde se u 99% slucajeva vrti dok je kartica u citacu
    while((_EidReadFixedPersonalData(mojdata)==-7) && (_EidReadFixedPersonalData(mojdata)==0)){}
    
    cout << "LK out" << endl;
    _EidEndRead();
    _EidCleanup();
    cc++;
}

    system("PAUSE");
    return 0;
    FreeLibrary(hinetDLL);
}



Ne znam da li je problem to što jako često pozivam ove funkcije (čekanje u while petlji), možda se to radi na neki drugi način koji ja ne znam pa bi mi značila pomoć.

Znači moje pitanje je, kako da na najlakši i najbolji način na svaku promenu lične karte u čitaču ja odradim neku akciju (u mom slučaju otvaram browser sa prosleđenim informacijama sa LK i čekam da se trenutna LK izvadi i stavi nova kada radim ponovo isto), a kad lične karte nema u čitaču samo se čeka?

[ Goran Rakić @ 24.09.2010. 18:01 ] @
Koristi PC/SC API u petlji koja proverava da li je kartica u čitaču. U samoj petlji ako biblioteka koju koristiš kao PC/SC omotač već nema neki callback mehanizam koristi sleep da ne izgoriš procesor ovako. Izmesti EidStartup/EidCleanup pozive van te petlje, na početku i kraju programa.

Kratka Google pretraga mi kaže da bi verovatno mogao da koristiš http://msdn.microsoft.com/en-us/library/aa379473(VS.85).aspx mada moguće da postoji i nešto zgodno višeg nivoa.
[ Rongon @ 25.09.2010. 14:39 ] @
Ovako, moras da prepravis da se _EidStartup i _EidCleanup samo jednom pozivaju (pri pokretanju programa i pri zavrsetku). Znaci, nema ulancavanja i pozivanja u svakoj petlji. Celik API jednostavno tako radi...
Razmisli ovako nesto da implementiras preko win32 SCard API-ja, koristeci SCardGetStatusChange funkciju u petlji koja se vrti.
Code:


SCARD_READERSTATE   readerState; // stanje citaca
BOOL bDone = FALSE; // da li je kraj
SCARDCONTEXT hSC;
SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSC); // uspostavi kontekst

readerState.szReader = L"IME CITACA"; // ovo ili fiksno stavis, ili dobijas preko SCardListReaders funkcije
readerState.dwCurrentState = SCARD_STATE_UNAWARE; // pocetno stanje je neodredjeno

_EidStartup(1);
while (!bDone)
    {
        // sacekaj proveru statusa
        SCardGetStatusChange(hSC, INFINITE, &readerState, 1); //ceka dok se status citaca ne promeni
        // dvEventState je novo stanje, dvCurrentState je trenutno (staro) stanje
        // proveri status citaca
        if( readerState.dwEventState & SCARD_STATE_PRESENT ) { // ako je novo stanje KARTICA_IN
            if ( (readerState.dwCurrentState & SCARD_STATE_EMPTY) || // i ako je staro stanje KARTICA_OUT
                (readerState.dwCurrentState == SCARD_STATE_UNAWARE) ) { // ili neodredjeno (samo za pocetni slucaj)
                    //kartica je ubacena
                    cout << "LK in" << endl;
                    _EidBeginRead("");
                    // ... citanje i sta vec, pozivanje skripte
                    _EidEndRead();
            }
        }else if(readerState.dwEventState & SCARD_STATE_EMPTY) { // ako je novo stanje KARTICA_OUT
            if (readerState.dwCurrentState & SCARD_STATE_PRESENT) { // i ako je staro stanje KARTICA_IN
                // kartica je izvadjena
                cout << "LK out" << endl;
            }
        }
        // sacuvaj novu vrednost stanja
        readerState.dwCurrentState = readerState.dwEventState;
} // glavna petlja while(!bDone)

_EidCleanup();
SCardReleaseContext(hSC);

Ovo nisam testirao na masini, jer mi je trenutno citac kartica pokvaren :( , ali bi trebalo da radi, jer sam nesto slicno vec radio i testirao.
P.S. Ne zaboravi i da libujes "Winscard.lib" koji je potreban za ove SCard funkcije...

[Ovu poruku je menjao Rongon dana 26.09.2010. u 16:08 GMT+1]

[Ovu poruku je menjao Rongon dana 26.09.2010. u 16:09 GMT+1]
[ MAD-MAX @ 26.09.2010. 15:53 ] @
Probaću ovo u ponedeljak pošto sada nemam čitač kod mene, nadam se da će raditi.

Hvala vam mnogo.
[ MAD-MAX @ 27.09.2010. 10:42 ] @
@Rongon:
Verujem da je glupo ali ne umem da nateram tvoj primer da radi. Jel možeš da mi kažeš kako da linkujem WinSCard.dll (koji imam na računaru btw) da bi mogao da kompajliram tvoj primer. Da li treba da konvertujem taj dll u *.a za statičko linkovanje, tako sam negde pročitao, pojma nemam? Nisam nigde mogao da nađem winscard.lib i winscard.h.

Ovo malo programče pravim u DevC++ i nemam Visual Studio na računaru. Čini mi se da sam negde pročitao da uz VS idu winscard.lib i winscard.h Nisam nikad radio sa win32 api-jem niti sam C++ programer ali verujem da mi tvoj kod može završiti to što mi treba samo da ga nekako kompajliram.

Hvala!
[ Rongon @ 27.09.2010. 13:07 ] @
@MAD-MAX
Testirao sam kod, i radi savrseno preko VS2008. E sad, za DevC++ bi mogao da probas ovako nesto:
http://www.openwebspider.org/documentation/how-to-link-libmysqllib-with-dev-c-or-gcc-under-windows/.
Nemam iskustva sa DevC++, ali bi u najgoru ruku mogao da pozivas funkcije iz winscard.dll na ovaj nacin:
http://goffconcepts.com/techarticles/development/cpp/calldll.html. Napises ovako za svaku funkciju koju koristis (SCardEstablishContext, SCardGetStatusChange, SCardReleaseContext), i trebalo bi da radi... Mada bi trebalo i da skines winscard.h negde sa neta.
Nisam na svom kompu trenutno, ali cu do veceras da zakacim ovde i winscard.h i winscard.lib.
[ MAD-MAX @ 28.09.2010. 17:26 ] @
Jel možeš da uploaduješ tvoj VS2008 projekat, skinuo sam VC++ 2010 Express pa bi trebalo da tu radi tvoj projekat.

Inače evo kako sam rešio problem:

Code:

..........
cout << "_EidStartup: " << _EidStartup(1) << endl;

while(1) {
    temp = -1;
    cout << "_EidBeginRead: " << _EidBeginRead("") << endl;

    while(temp !=0){
        temp = _EidReadFixedPersonalData(mojdata);
        Sleep(100);
    }

    while(_EidReadVariablePersonalData(vardata)!=0){}
    
    cout << "LK in" << endl;

    string s;
    s = link + (string)mojdata->personalNumber;

    s += "&first_name=";
    string first_name;
    first_name = cir2hex(mojdata->givenName,mojdata->givenNameSize);
    s += first_name;

    s += "&last_name=";
    string last_name;
    last_name = cir2hex(mojdata->surname,mojdata->surnameSize);
    s += last_name;
    
    char *a=new char[s.size()+1];
    a[s.size()]=0;
    memcpy(a,s.c_str(),s.size());
    ShellExecute(NULL, "open", a, NULL, NULL, SW_SHOWNORMAL);

    while(!((_EidReadFixedPersonalData(mojdata)==-7) && (_EidReadFixedPersonalData(mojdata)==-7) && (_EidReadFixedPersonalData(mojdata)==-7))) {
        Sleep(100);
    }
    cout << "LK out" << endl;
    _EidEndRead();
}
    _EidCleanup();
    
..........


Znači izbacio sam _EidStartup i _EidCleanup van while petje (što sam prvobitno tako i uradio, al nema veze) i fora je da sa Sleep dam malo "oduška" čitaču jer ako je bez toga i LK je u čitaču _EidReadFixedPersonalData() mi vraća naizmenično -7 i 0 a ako ubacim Sleep(100) onda vraća 4 nule pa -7 i tako u krug što mi i nije jasno ali nema veze, čim mi vrati nulu ja imam u "mojdata" podatke koji mi trebaju. I naravno kad se kartica izvadi _EidReadFixedPersonalData() stalno vraća -7 što ja detektujem da je karica van čitača.

@Rongon:
Ovo mi završava posao ali ako možeš pošalji mi kod koji si testirao čisto da ga probam ne bi li naučio nešto novo.

Posebno hvala Rongonu i Goranu Rakiću na pomoći.
[ Rongon @ 28.09.2010. 18:22 ] @
Evo test projekta, bez celikapi.dll, koji treba da se stavi u folder gde se iskomplajlira :)
[ KARABAYA @ 03.11.2010. 10:08 ] @
jel uspeo neko da uradi neki program u vb.net?

Meni sve radi do trenutka kada treba da podatke prosledim nekoj promenljivoj.
EidBeginRead i EidStartup mi prodju bez problema.
Dok kada pozovem funkciju EidReadDocumentData(DocumentData) on mi vrati gresku -6, naravno ostavi mi praznu strukturu DocumentData.

Ovako mi izgleda struktura DocumentData

Code:
  Public Structure EID_DOCUMENT_DATA
        Public docRegNo() As Char
        Public docRegNoSize As Integer
        Public issuingDate() As Char
        Public issuingDateSize As Integer
        Public expiryDate() As Char
        Public expiryDateSize As Integer
        Public issuingAuthority() As Char
        Public issuingAuthoritySize As Integer
    End Structure



A funckija ovako:
Code:

    <DllImport("CelikApi.dll")> _
    Public Shared Function EidReadDocumentData(ByRef pData As EID_DOCUMENT_DATA) As Integer

    End Function



Gde gresim?
[ Mihajlo Cvetanović @ 03.11.2010. 10:21 ] @
Kako pozivaš EidBeginRead? Funkcija vraća uspeh koji god string da joj daš, ali ako je string pogrešan onda će prilikom konkretnog čitanja EidReadX funkcija vraćati -6. Ako imaš samo jedan čitač priključen onda pozovi EidBeginRead sa praznim stringom.
[ KARABAYA @ 03.11.2010. 10:44 ] @
Stavio sam sad da mi on iz sistema iscita citac i njegov naziv da stavi u funkciju eid beginread.

Sad mi javlja gresku kod poziva

docdata = EidReadDocumentData(DocumentData)

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.



(docdata je integer; DocumentData je EID_DOCUMENT_DATA)
[ Mihajlo Cvetanović @ 03.11.2010. 11:11 ] @
Stavi prazan string za EidBeginRead.
[ canejr @ 10.12.2010. 15:20 ] @
Nadam se da ima ljudi koji su i dalje prisutni, a mogu da mi pomognu.
Treba da napravim C# aplikaciju koja ce da cita podatke sa LK koristeci Celik API. Trenutno sam u fazi pravljenja wrapper-a.
Pokusao sam da upotrebim sve sto je ovde receno, koristio sam i net, ali ne uspevam. Istovremeno, program Celik radi sasvim normalno, na istom racunaru (Windows XP SP2). Uradio sam i uninstall .net framework 3.5 SP1. Koristim VS2005.

Sta je problem:
Vec na EidBeginRead se javlja "Microsoft C++ exception: CardException at memory location 0x00138270". Na netu kazu da moze da se ignorise?
Na EidReadFixedPersonalData (a i sve ostale): "Microsoft C++ exception: unsigned long at memory location 0x00138818" i to dvaput (uzastopno)
Posle toga (jos uvek na EidReadFixedPersonalData ili bilo koji drugi metod): "Access violation writing location".
Na kraju: "An unhandled exception of type 'System.ExecutionEngineException' occurred in System.Windows.Forms.dll" (probao da stavim try/catch, ali dzaba)

Inace, pre Access violation, sistem definitivno cita podatke, jer na citacu pocne da blinka lampica, ali onda sve pukne, reklo bi se kad procitane podatke treba da upise nazad meni u prosledjenu klasu. Probao sam da koristim MarshallAs i MarshallAsAttribute. Probao sa LPStr i ByValTStr, ali stalno isto. Nekako zakljucujem da je problem u pointerima ili tipovima, ali nikako ne uspevam da nadjem problem. Ni da ga resim.

Stavio sam da se EidStartup poziva samo na pocetku. EidCleanup samo na kraju. Izmedju pozivam.. pa evo cele klase:
Code:

    public partial class Form1 : Form
    {
        int ret;

        public Form1()
        {
            InitializeComponent();
        }

        [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
        private void button1_Click(object sender, EventArgs e)
        {
            ret = Celik.EidBeginRead("");
            if (ret < 0)
            {
                // Nije ni bitno, nikad ne udje ovde
            }

            Celik.tagEID_FIXED_PERSONAL_DATA podaci = new Celik.tagEID_FIXED_PERSONAL_DATA();
            try
            {
                ret = Celik.EidReadFixedPersonalData(ref podaci);
            }
            catch (Exception ex)
            {
                int a = 5;
            }

            if (ret < 0)
            {
                MessageBox.Show(((enmCelikStatus)ret).ToString(), "Greska", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

            Celik.EidEndRead();
            return;
        }
    }


Zakljucujuem da je probem u klasi Celik:
Code:

    [SuppressUnmanagedCodeSecurity()]
    public class Celik
    {
        //
        // Constants
        //
        // Size of all UTF-8 fields in bytes
        const int EID_MAX_DocRegNo = 9;
        const int EID_MAX_IssuingDate = 10;
        const int EID_MAX_ExpiryDate = 10;
        const int EID_MAX_IssuingAuthority = 30;

        const int EID_MAX_PersonalNumber = 13;
        const int EID_MAX_Surname = 60;
        const int EID_MAX_GivenName = 40;
        const int EID_MAX_ParentGivenName = 25;
        const int EID_MAX_Sex = 2;
        const int EID_MAX_PlaceOfBirth = 25;
        const int EID_MAX_StateOfBirth = 25;
        const int EID_MAX_DateOfBirth = 10;
        const int EID_MAX_CommunityOfBirth = 25;

        const int EID_MAX_State = 3;
        const int EID_MAX_Community = 25;
        const int EID_MAX_Place = 25;
        const int EID_MAX_Street = 36;
        const int EID_MAX_HouseNumber = 5;
        const int EID_MAX_HouseLetter = 2;
        const int EID_MAX_Entrance = 3;
        const int EID_MAX_Floor = 3;
        const int EID_MAX_ApartmentNumber = 6;

        const int EID_MAX_Portrait = 7700;

        //
        // Functions
        //
        [DllImport("CelikApi.dll", CharSet = CharSet.Unicode)]
        public static extern int EidStartup(
        int nApiVersion
        );

        [DllImport("CelikApi.dll", EntryPoint = "EidCleanup", CharSet = CharSet.Unicode)]
        public static extern int EidCleanup(
        );

        [DllImport("CelikApi.dll", CharSet = CharSet.Unicode)]
        public static extern int EidBeginRead(
        [MarshalAs(UnmanagedType.LPStr)] String szReader
        );

        [DllImport("CelikApi.dll", CharSet = CharSet.Unicode)]
        public static extern int EidEndRead(
        );

        [DllImport("CelikApi.dll", CharSet = CharSet.Unicode)]
        public static extern int EidReadFixedPersonalData(
        ref tagEID_FIXED_PERSONAL_DATA pData
        );

        [DllImport("CelikApi.dll", CharSet = CharSet.Unicode)]
        public static extern int EidReadDocumentData(
        ref tagEID_DOCUMENT_DATA pData
        );

        [DllImport("CelikApi.dll", CharSet = CharSet.Unicode)]
        public static extern int EidReadPortrait(
        ref tagEID_PORTRAIT pData
        );

        //
        // Classes
        //
        [StructLayout(LayoutKind.Sequential, Size = EID_MAX_IssuingAuthority + EID_MAX_IssuingDate + EID_MAX_DocRegNo + EID_MAX_ExpiryDate), Serializable]
        public class tagEID_DOCUMENT_DATA
        {
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_DocRegNo)]
            public string docRegNo;
            public int docRegNoSize;
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_IssuingDate)]
            public string issuingDate;
            public int issuingDateSize;
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_ExpiryDate)]
            public string expiryDate;
            public int expiryDateSize;
            [MarshalAsAttribute(UnmanagedType.LPStr, SizeConst = EID_MAX_IssuingAuthority)]
            public string issuingAuthority;
            public int issuingAuthoritySize;
        };

        [StructLayout(LayoutKind.Sequential, Size = EID_MAX_PersonalNumber + EID_MAX_Surname + EID_MAX_GivenName + EID_MAX_Sex + EID_MAX_PlaceOfBirth + EID_MAX_StateOfBirth + EID_MAX_DateOfBirth + EID_MAX_CommunityOfBirth), Serializable]
        public class tagEID_FIXED_PERSONAL_DATA
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_PersonalNumber)]
            public string personalNumber;
            public int personalNumberSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_Surname)]
            public string surname;
            public int surnameSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_GivenName)]
            public string givenName;
            public int givenNameSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_Sex)]
            public string sex;
            public int sexSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_PlaceOfBirth)]
            public string placeOfBirth;
            public int placeOfBirthSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_StateOfBirth)]
            public string stateOfBirth;
            public int stateOfBirthSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_DateOfBirth)]
            public string dateOfBirth;
            public int dateOfBirthSize;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EID_MAX_CommunityOfBirth)]
            public string communityOfBirth;
            public int communityOfBirthSize;
        };

        [StructLayout(LayoutKind.Sequential, Size = EID_MAX_Portrait), Serializable]
        public class tagEID_PORTRAIT
        {
            [MarshalAs(UnmanagedType.LPStr, SizeConst = EID_MAX_Portrait)]
            public string portrait;
            public int portraitSize;
        };
    }

    public enum enmCelikStatus
    {
        EID_OK = 0,
        EID_E_GENERAL_ERROR = -1,
        EID_E_INVALID_PARAMETER = -2,
        EID_E_VERSION_NOT_SUPPORTED = -3,
        EID_E_NOT_INITIALIZED = -4,
        EID_E_UNABLE_TO_EXECUTE = -5,
        EID_E_READER_ERROR = -6,
        EID_E_CARD_MISSING = -7,
        EID_E_CARD_UNKNOWN = -8,
        EID_E_CARD_MISMATCH = -9,
        EID_E_UNABLE_TO_OPEN_SESSION = -10,
        EID_E_DATA_MISSING = -11,
        EID_E_CARD_SECFORMAT_CHECK_ERROR = -12,
        EID_E_SECFORMAT_CHECK_CERT_ERROR = -13
    };


Svaka ideja/pomoc dobrodosla.
[ mmix @ 10.12.2010. 15:43 ] @
Pogledaj ovde


LGPL CLR Interop Wrapper za CelikAPI
[ canejr @ 10.12.2010. 15:54 ] @
Hvala!
Sad jos da provalim sta se tu desava..
Jedino me sad jako kopka sta ne valja u onom mom kodu. :)
[ mmix @ 10.12.2010. 16:10 ] @
Verovatno nesto u vezi sa time sto celikAPI ne koristi null terminated stringove ili sa velicinom bufera ili oba problema zajedno.
[ mbogdanovic @ 17.01.2013. 08:38 ] @
Pozdrav svima,

programer bez znanja C++, imam isti zadatak da koristim podatke iz LK i SD i da ih importujem u bazu.

Da li kod koji ste do sada razvijali funkcioniše i da li mogu da vidim primer, kako da pozivam neke funkcije, kao na primer : EID_API int WINAPI EidReadDocumentData(PEID_DOCUMENT_DATA pData);

Hvala do neba.

Pozdrav od Miodraga
[ nneexx @ 19.01.2013. 14:43 ] @
Meni isto ovo treba za Alasku xbase++

Da li je neko resavao problem za ovaj programski jezik ?

Pozdrav.
[ wakawaki @ 01.12.2022. 09:34 ] @
Ljudi, treba mi pomoc. Ima li neko funkcionalan kod u c++ za citanje licne karte?
[ Mihajlo Cvetanović @ 01.12.2022. 11:56 ] @
Na prethodnoj strani korisnik Rongon je priložio Visual Studio konzolni projekat koji detektuje ubacivanje lične karte u čitač i zatim je i pročita.

https://www.elitesecurity.org/t372490-3#2704657

Projekat je star. Čelik API je od tada promenjen. Treba da preuzmeš najnoviji API sa sajta MUP i da u projektu zameniš celikapi.h i celikapi.lib, kao i da iskopiraš celikapi.dll u folder u kome je exe fajl. Debug i/ili Release folder. Na sajtu MUP trenutno je aktuelna verzija Čelik API 1.3.2. I to može vremenom da se promeni.

http://ca.mup.gov.rs/ca/ca_cyr...ikApi+Windows+1.3.2+32-bit.zip za 32-bitne aplikacije
http://ca.mup.gov.rs/ca/ca_cyr...ikApi+Windows+1.3.2+64-bit.zip za 64-bitne aplikacije