Hi, In our application we have a program that reads info on identity-cards. For years we created a handle like : CREATE "EIDLIBCTRL.EIDlib" chctrlframe NO-ERROR. At that point we could access the dll (like an ocx). The government released new software and the above isn't possible anymore. There's a new DLL and we can't access it like we use to access an OCX or DLL. I think it's possible in OE AppBuilder OE11.3, but I really don't know where to start. Can someone point me into the right direction or where can I find docs that can get me started. They give some examples in C, C# and Java. An example in C# is : using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using Net.Sf.Pkcs11; using Net.Sf.Pkcs11.Objects; using Net.Sf.Pkcs11.Wrapper; using System.Security.Cryptography.X509Certificates; namespace EidSamples { class ReadData { private Module m = null; private String mFileName; /// /// Default constructor. Will instantiate the beidpkcs11.dll pkcs11 module /// public ReadData() { mFileName = "beidpkcs11.dll"; } public ReadData(String moduleFileName) { mFileName = moduleFileName; }
Hi,
Thanks for the link. Seems like I need to do a lot of reading. But it's a good to time to start with it.
I hope it isn't to complicated ....
Given that they're now providing C# examples, looks like the new .dll is now a .NET assembly.
You'll want to add this to your assemblies.xml (if you're still using old AppBuilder, using the proasmref command-line tool).
From there on you should be able to use it via normal class-referencing syntax.
Thanks for the answer.
I'm still using the old AppBuilder (11.3). They give examples in C, C# and java. The one I posted was indeed C#.
I have no knowledge on how to use .Net assembly in OpenEdge. You mention I need to add it to the assemblies.xml. Is that only in development or also in deployment ?
And the next question is, where can I found documentation on how to use class-referencing syntax in OpenEdge ?
The assemblies.xml is required at both sides (development & deployment).
>>where can I found documentation on how to use class-referencing syntax in OpenEdge ?
You can start with the OpenEdge Product Documentation, section "OpenEdge GUI for .Net"
Hi,
Thanks for the link. Seems like I need to do a lot of reading. But it's a good to time to start with it.
I hope it isn't to complicated ....
don't remember the exact details but think we got better results using the interop wrapper (http://www.pkcs11interop.net) instead of the one from sf.net (http://sf.net/p/pkcs11net/)...
using Progress.Lang.*. using Net.Pkcs11Interop.Common.*. using Net.Pkcs11Interop.HighLevelAPI.*. using System.BitConverter. using System.Collections.IEnumerator. using System.Collections.ArrayList. routine-level on error undo, throw. class com.xpower.beid.ReadDataInterop: define private variable moduleFile as character no-undo. define private variable pkcsModule as Pkcs11 no-undo. constructor public ReadDataInterop ( ): this-object('beidpkcs11.dll':u). end constructor. constructor public ReadDataInterop ( moduleFile as character ): this-object:moduleFile = moduleFile. end constructor. destructor public ReadDataInterop ( ): if valid-object(pkcsModule) then pkcsModule:Dispose() no-error. delete object pkcsModule no-error. end destructor. method public character GetSurname(): return GetData('surname':u). end method. method public character GetFirstName(): return GetData('firstnames':u). end method. method public character GetNameInitials(): return GetData('first_letter_of_third_given_name':u). end method. method public character GetNationality(): return GetData('nationality':u). end method. method public character GetCardNumber(): return GetData('card_number':u, true). end method. method public character GetChipNumber(): return GetData('chip_number':u). end method. method public character GetSerialNumber(): return GetData('carddata_serialnumber':u). end method. method public character GetNationalNumber(): return GetData('national_number':u). end method. method public character GetDocumentType(): return GetData('document_type':u). end method. method public character GetAddressStreet(): return GetData('address_street_and_number':u). end method. method public character GetAddressZip(): return GetData('address_zip':u). end method. method public character GetAddressMunicipality(): return GetData('address_municipality':u). end method. method public character GetPhoto(): return GetData('photo_hash':u). end method. method public character GetDateOfBirth(): return GetData('date_of_birth':u). end method. method public character GetPlaceOfBirth(): return GetData('location_of_birth':u). end method. method public character GetValidityDateStart(): return GetData('validity_begin_date':u). end method. method public character GetValidityDateEnd(): return GetData('validity_end_date':u). end method. method public character GetGender(): return GetData('gender':u). end method. method public character GetData(labelName as character): return GetData(labelName, false). end method. method public character GetData(labelName as character, displayBytes as logical): define variable retValue as character no-undo. define variable numItem as integer no-undo. define variable pkcsSession as Session no-undo. define variable classAttribute as ObjectAttribute no-undo. define variable labelAttribute as ObjectAttribute no-undo. define variable readAttribute as ObjectAttribute no-undo. define variable pkcsObject as ObjectHandle no-undo. define variable colEnum as IEnumerator no-undo. define variable attrEnum as IEnumerator no-undo. define variable slotList as 'System.Collections.Generic.List<Slot>' no-undo. define variable attrArray as 'System.Collections.Generic.List<ObjectAttribute>' no-undo. define variable foundObjects as 'System.Collections.Generic.List<ObjectHandle>' no-undo. define variable objAttr as 'System.Collections.Generic.List<CKA>' no-undo. if not valid-object(pkcsModule) then pkcsModule = new Pkcs11(moduleFile, true). /* Get the first slot (cardreader) with a token */ slotList = pkcsModule:GetSlotList(true). if slotlist:Count > 0 then do: colEnum = slotList:GetEnumerator(). if colEnum:MoveNext() then pkcsSession = cast(colEnum:Current, 'Slot'):OpenSession(true). delete object colEnum. /* Search for objects First, define a search template */ /* 'The label attribute of the objects should equal ...' */ classAttribute = new ObjectAttribute(CKA:CKA_CLASS, CKO:CKO_DATA). labelAttribute = new ObjectAttribute(CKA:CKA_LABEL, labelName). attrArray = new 'System.Collections.Generic.List<ObjectAttribute>' (2). attrArray:Add(classAttribute). attrArray:Add(labelAttribute). pkcsSession:FindObjectsInit(attrArray). delete object classAttribute. delete object labelAttribute. delete object attrArray. foundObjects = pkcsSession:FindObjects(1). message 'found objects' skip foundObjects:Count view-as alert-box. colEnum = foundObjects:GetEnumerator(). objAttr = new 'System.Collections.Generic.List<CKA>' (2). objAttr:Add(CKA:CKA_LABEL). objAttr:Add(CKA:CKA_VALUE). do while colEnum:MoveNext(): pkcsObject = cast(colEnum:current, 'ObjectHandle':u). if not valid-object(pkcsObject) or pkcsObject:ObjectId eq 0 then do: message 'invalid object' view-as alert-box. next. end. message 'object' skip pkcsObject:ToString() view-as alert-box. attrArray = pkcsSession:GetAttributeValue(pkcsObject, objAttr). message 'attributes list' skip attrArray:count view-as alert-box. if attrArray:count > 0 then do: attrEnum = attrArray:GetEnumerator(). do while attrEnum:MoveNext(): readAttribute = cast(attrEnum:Current, 'ObjectAttribute'). message 'attribute' skip readAttribute:GetValueAsString() view-as alert-box. end. delete object attrEnum no-error. return readAttribute:GetValueAsString(). end. delete object pkcsObject no-error. delete object attrArray no-error. end. delete object colEnum. delete object objAttr. delete object foundObjects. pkcsSession:FindObjectsFinal(). end. undo, throw new AppError('Can not read card slot', -1). finally: if valid-object (pkcsSession) then do: if valid-object(pkcsObject) then pkcsSession:DestroyObject(pkcsObject) no-error. pkcsSession:CloseSession() no-error. end. if valid-object (pkcsModule) then pkcsModule:Dispose() no-error. delete object pkcsObject no-error. delete object pkcsSession no-error. delete object pkcsModule no-error. delete object attrArray no-error. delete object attrEnum no-error. delete object colEnum no-error. delete object objAttr no-error. delete object foundObjects no-error. end. end method. end class.
Hi,
Marian, thanks a lot ! Seems exactly what I'm looking for !!!
Do I need to add something to the assemblies.xml ? Because when I just copy your code in the procedure editor (Old Appbuilder) I get syntax error 15214 on :
define variable slotList as 'System.Collections.Generic.List<Slot>' no-undo.
define variable attrArray as 'System.Collections.Generic.List<ObjectAttribute>' no-undo.
define variable foundObjects as 'System.Collections.Generic.List<ObjectHandle>' no-undo.
define variable objAttr as 'System.Collections.Generic.List<CKA>' no-undo.
I'm completely new on using .NET,and started reading the documents as suggested. But it's seems that I have to do a lot of reading ...
How can I call this class from an ABL Window or procedure ?
King regards
Bart Syryn
Bart,
you need to get the interop assembly from www.pkcs11interop.net, add pkcs11interop.dll in your assemblies.xml and then the er ror will hopefully go away.
The module file (beidpkcs11.dll) i think you can get it from here unless you already have that... eid.belgium.be/.../de_eid-middleware_installeren
To call the class something like this should do it...
define variable pkcsRead as com.xpower.beid.ReadDataInterop no-undo.
pkcsRead = new com.xpower.beid.ReadDataInterop().
message pkcsRead:GetSurname() view-as alert-box.
catch e as Progress.Lang.Error :
message e:getmessage(1) view-as alert-box.
end catch.
finally:
delete object pkcsRead no-error.
end finally.
Hi Marian,
Thanks for the quick response !!!
I'm new in the use of .net in OE, it's hard ...
I've searched the website www.pkcs11interop.net for the last hour and I didn't find any download for the pkcs11interop.dll
I've googled the .dll and also no results .... Do you have a link to the file itself ?
I still get errors ofcourse because I'm missing the dll (error 5638 on define private variable pkcsModule as Pkcs11 no-undo.)
Any help or hints ? Thanks !
Bart,
you can download source code from sf.net and compile but guess this is not that straight forward so go for the binaries:
- get NuGet command line from here: http://nuget.org/nuget.exe
- install Pkcs11interop 'package' using: nuget.exe install Pkcs11Interop
- get the dll from Pkcs11Interop folder created by install above, go for .net 4.0 or 2.0 depending on your OE version (try 4.0 first and see if it works)
Mind you that code is just something quickly and blindly crafted but not tested... so it's more to get you started.
Hi Marian,
Thanks !
Now I was able to download it and got the .dll. I've added it to the assemblies.xml file in my procedure editor but I still get the error 5638 (unknown class) on define private variable pkcsModule as Pkcs11 no-undo. The assemblies.xml file is in my working directory.
I think it's better to read more documentation from the Progress Site to understand what the cause is of the error.
Kind regards
Bart Syryn
Hi Marian,
I'm sorry, but I have another question. I finaly got your example working, main reason was that I'm not familier with using gui .net.
I can read out the data, but I also need the picture on the EID. In a CSharp example I see that they use GetFile('PHOTO_FILE'). So I assume that it's a memptr with the photo in it. So I added GetFile like the CSharp example, but the only thing that is returned are ????. Probably I do something wrong with GetValueAs???? like it's described in Pkcs11Interop.xml, but I don't know what to use, and I also don't know what type of variable I need to use in the class.
Do you have any experience on reading the picture ?
kind regards
Bart Syryn
Bart,
glad you did get it to work... most probably something can be done for the picture, time is scarce now but if that turn out in consulting/billable something could be arranged :)
Regards,
Marian
Marian,
Thanks for answering. I agree with your proposal. Maybe it's better to contact me directly. If it's alright with you, I can add you in linkedIn and then you've got my emailadres to contact me directly.
Kind regards
Bart Syryn