2010 Oct 25 4:01 PM
It is not ordinary but very easy to use DLL calls in ABAP language. Yuri Popov programmed a module, called DynamicWrapperX. It is an ActiveX component, which allow to call each function in a DLL you want via COM. A great module, you find the module here.
It is necessary before, with the transaction code SOLE, register the OLE application DynamicWrapperX in the SAP system. Type in:
And it is necessary to register DynamicWrapperX on the client system too, with regsvr32.exe dynwrapx.dll.
Look at the following example how easy it is to use a Windows function from USER32.DLL:
INCLUDE OLE2INCL.
DATA: IDYes TYPE i VALUE 6,
IDNo TYPE i VALUE 7.
DATA: Win32 TYPE OLE2_OBJECT,
ret TYPE i.
CREATE OBJECT Win32 'DynamicWrapperX'.
CALL METHOD OF Win32 'Register'
EXPORTING
#1 = 'user32.dll'
#2 = 'MessageBoxW'
#3 = 'i=hwwu'
#4 = 'r=l'.
CALL METHOD OF Win32 'MessageBoxW' = ret
EXPORTING
#1 = 0
#2 = 'Hello World'
#3 = 'Test'#4 = 4.
IF ret = IDYes.
WRITE 'Ja'.
ELSEIF ret = IDNo.
WRITE 'Nein'.
ELSE.
WRITE '?'.
ENDIF.
FREE OBJECT Win32.
Important hint: This method works only with foreground jobs and online processes and not with background jobs and batch processes.
Enjoy the possibilities.
2010 Oct 25 4:15 PM
Thanks for sharing, please create an entry in the ABAP section of the SDN wiki with this information.
Thomas
2012 Aug 28 1:12 PM
Thanks a lot!
Can you show example, when METHOD has to return the value.
For example: I need to use some AddInISC.dll.
it works whith VB in our project like this:
Set DX = CreateObject("DynamicWrapperX")
DX.Register "AddInISC.dll", "CalcRic"
_value = DX.CalcRic( "MANYSYMBOLS", 0)
now _value has data.
How do use this example in ABAP?
I try to use as in your example, but ... I don't understand where I do mistake.
CREATE OBJECT Win32 'DynamicWrapperX'.
CALL METHOD OF Win32 'Register'
EXPORTING
#1 = 'C:\WINDOWS\system\AddInISC.dll' #2 = 'CalcRic'.
CALL METHOD OF Win32 'CalcRic'
EXPORTING
#1 = 'MANYSYMBOLS' #2 = 0.
GET PROPERTY OF Win32 'CalcRic' = cik.
WRITE: cik. " nothing here.
2012 Aug 28 1:55 PM
Hello Sergei,
you register the function CalcRic and it seems that the function has import parameters and a result value. You must define the import and result at the registration, e.g.
CALL METHOD OF Win32 'Register'
EXPORTING
#1 = 'C:\WINDOWS\system\AddInISC.dll' #2 = 'CalcRic'. #3 = 'i=wl' #4 = 'r=l'.
CALL METHOD OF Win32 'CalcRic' = _value
EXPORTING
#1 = 'MANYSYMBOLS' #2 = 0.
Hope it works, let us know.
Cheers
Stefan
2012 Sep 03 5:47 AM
Hello Stefan!
Thanks a lot again.
Your example doesn't work ..... Perhaps that dll has special import-export parameters.
Can you give me link to describing about defining the import and result parameters.
For example, I don't understand this part #3 = 'i=wl' #4 = 'r=l' ... shame of me.
I hope my questions doesn't make you nervous.
Cheers
Sergei
2012 Sep 03 6:19 AM
Hello Sergei,
I am very calm.
You find a detailed explanation of DynamicWrapperX here: http://www.script-coding.com/dynwrapx_eng.html
i means the import parameter and r means result of the function.
i = wl means the import parameter are an unicode string (w) and a signed 32bit integer value (l), in your case w = 'MANSYMBOLS' and l = 0.
The DLL function delivers a return value, in your case _value, also a 32bit integer value (l), that means r = l.
That is the "secret" behind i and r.
But you must look at the description of the library which are the right types of the arguments, I supposed the types.
Hope it helps, let us know.
Cheers
Stefan
2012 Sep 03 7:57 AM
Hello Stefan!
I read this web link before I tried to do something, but I wasn't carefully with rules.
Ok, I have suggestion about specific of AddInISC.dll. When we use it in non-ABAP program
AddInISC.dll requires to create a new instant. Like that:
LoadExternalLibrary (AddInISC.DLL);
ObjectNew = New("AddIn.ISC");
_vslue = ObjectNew.CalcRic("MANYSYMBOLS ", 0);
But a way, _value has string type.
When I remove this code to ABAP I missed one command "ObjectNew = New("AddIn.ISC");".
Because I don't understand how I can use two methods together.
CREATE OBJECT Win32 'DynamicWrapperX'.
And
CREATE OBJECT Win32 ' AddIn.ISC'.
Have you any ideas?
2012 Sep 03 8:31 AM
Hello Sergei,
is the AddInISC.DLL an ActiveX library?
Analyze the library with Dependency Walker http://www.dependencywalker.com/
If you find the functions:
- DLLCanUnloadNow
- DLLGetClassObject
- DLLRegisterServer
- DLLUnregisterServer
it is an ActiveX library.
If it is an ActiveX library, you can use this library direct with ABAP. So it is not possible to use DynamicWrapperX.
If it is a mixed library - ActiveX and Shared - you can use the ActiveX methods with ABAP and the non-ActiveX functions with DynamicWrapperX.
Let us know.
Cheers
Stefan
2012 Sep 03 10:35 AM
well......
Thank you very much for your attention and help.
However it doesn't work, despite that was made as ActivX kind. Perhaps, author of that "dll" made it
not correctly.
I leave it for later temporary.
Cheers
Sergei
2013 Dec 26 3:05 PM
Hi Stefan,
Greetings!!
need your help for one of my requirement, mentioned below.Any help from you would be higly appriciated.
We have got requirement to call DLL functions from SAP for POS device(Point of Sale i.e Card swipe machine during Payment).
Here POS device has certain functions like api_CheckExistance, api_TriggerTrxTrack2 and api_GetTransactionResult to use POS. we tried to implement the same methods by using above approach that you mentioned, but could not success. Could you please let us know, how to handle POS device functions, especially importing parameter?
Example : Below function need to call in SAP
Function Name:
api_GetTerminalParams
Function Usage:
Can be used to read the Terminal Identification Number and Retailer Identification Number from the terminal’s Non- volatile configuration memory for the host application’s internal purposes.
One common use of it is to stamp the transaction with the terminal ID that processed the transaction.
Input Parameter:
N/A
Return Parameter:
The function requires two parameters, which will be filled with appropriate data.
Function Declaration in C++:
extern "C" int FAR PASCAL EXPORT api_GetTerminalParams(char FAR *szTerminalID, char FAR *szRetailerID);
An example C++ code is present in the C++ project source supplied along with this document
2013 Dec 27 7:17 AM
Hello Harjyot,
I am no C expert but as far as I understand it correct the signature
extern "C" int FAR PASCAL EXPORT api_GetTerminalParams(char FAR *szTerminalID, char FAR *szRetailerID);
means that szTerminalID and szRetailerID are pointers to a character area.
I am not really sure but I hope the following code could help you:
"-Begin-----------------------------------------------------------------
Report zPointOfSale.
"-Type Pools--------------------------------------------------------
Type-Pools OLE2.
"-Variables---------------------------------------------------------
Data DX Type OLE2_OBJECT.
Data TerminalID Type String Value ''.
Data strTerminalID Type String Value ''.
Data ptrTerminalID Type i Value 0.
Data RetailerID Type String Value ''.
Data strRetailerID Type String Value ''.
Data ptrRetailerID Type i Value 0.
Data ret Type Integer Value 0.
"-Main--------------------------------------------------------------
Create Object DX 'DynamicWrapperX'.
If sy-subrc = 0 And DX-Handle <> 0 And DX-Type = 'OLE2'.
"-Definitions of character areas with a pointers to it----------
Call Method Of DX 'Space' = strTerminalID
Exporting #1 = 9 #2 = ''.
Call Method Of DX 'StrPtr' = ptrTerminalID
Exporting #1 = strTerminalID #2 = 's'.
Call Method Of DX 'Space' = strRetailerID
Exporting #1 = 17 #2 = ''.
Call Method Of DX 'StrPtr' = ptrRetailerID
Exporting #1 = strRetailerID #2 = 's'.
Call Method Of DX 'Register'
Exporting
#1 = 'POS.dll'
#2 = 'API_GETTERMINALPARAMS'
#3 = 'i=uu' #4 = 'r=l'.
If sy-subrc = 0.
Call Method Of DX 'API_GETTERMINALPARAMS' = ret
Exporting #1 = ptrTerminalID #2 = ptrRetailerID.
"-Get content of character areas via pointer------------------
Call Method Of DX 'StrGet' = TerminalID
Exporting #1 = ptrTerminalID #2 = 's'.
Call Method Of DX 'StrGet' = RetailerID
Exporting #1 = ptrRetailerID #2 = 's'.
EndIf.
Write: / ret.
Write: / TerminalID.
Write: / RetailerID.
Free Object DX.
EndIf.
"-End-------------------------------------------------------------------
Let us know the results.
Cheers
Stefan
2013 Dec 31 9:44 AM
Hi Stefan,
Thank you for your reply and appriciate your help.
We tried the solution that you provided, but it did not work.
any other configuration do we need to do to make this working?
we did SOLE configuration, before using your solution.
Is there anything else we need to configure to achieve the solution?
one isse with the code i am getting, whenever i am applying sy-subrc check in the code as given by you, always sy-subrc failes(value is 2), but when remove sy-subrc from the code then sy-subrc is value is zero in later part of code.
2014 Jan 02 6:51 AM
Hello Harjyot,
first of all a happy new year.
I need to simulate your environment, because don't have one. So I code a POS simulation library, here the source:
'-Begin------------------------------------------------------------
'-Directives-----------------------------------------------------
#Compile DLL
Option Explicit
'-api_GetTerminalParams------------------------------------------
Function api_GetTerminalParams (_
ByVal ptrszTerminalID As Dword, _
ByVal ptrszRetailerID As Dword) Export BDecl As Long
Poke$ ptrszTerminalID, "12345678" & $Nul
Poke$ ptrszRetailerID, "0123456789ABCDEF" & $Nul
api_GetTerminalParams = 1
End Function
'-End--------------------------------------------------------------
There is only the function API_GETERMINALPARAMS in BDecl declaration, which means Pascal.
As you can see I write the IDs to the given addresses.
To check it out I code a VBScript, here the source:
'-Begin------------------------------------------------------------
'-Directives-----------------------------------------------------
Option Explicit
'-Main-----------------------------------------------------------
'-Variables----------------------------------------------------
Dim DX, rc
Dim TerminalID, strTerminalID, ptrTerminalID
Dim RetailerID, strRetailerID, ptrRetailerID
Set DX = CreateObject("DynamicWrapperX")
If IsObject(DX) Then
strTerminalID = DX.Space(9)
ptrTerminalID = DX.StrPtr(strTerminalID, "s")
strRetailerID = DX.Space(17)
ptrRetailerID = DX.StrPtr(strRetailerID, "s")
DX.Register "C:\Dummy\POS.dll", "API_GETTERMINALPARAMS", _
"i=uu", "r=l"
rc = DX.API_GETTERMINALPARAMS(ptrRetailerID, ptrTerminalID)
TerminalID = DX.StrGet(ptrTerminalID, "s")
RetailerID = DX.StrGet(ptrRetailerID, "s")
MsgBox "TerminalID: " & TerminalID & " RetailerID: " & _
RetailerID
Set DX = Nothing
Else
MsgBox "Can not create DynamicWrapperX object"
End If
'-End--------------------------------------------------------------
It works as expected.
To your question:
It is not necessary to configure the SOLE transaction. OLE access via ABAP works without this configuration. That's history I think. Other configurations are, as far as I know, not necessary.
Error 2 means incorrect function call. Look at the example codes of your POS library as they are called, I don't know it.
Be sure that you register DynWrapX.dll correct. You must have admin rights on your presentation server to use regsvr32 dynwrapx.dll in the command line.
My tip:
Try to use the functions via DynamicWrapperX from your POS library on your presentation server via VBScript first, like above. It is easier to find the correct way and it is very easy to port it to ABAP, as you can see.
Let us know the results.
Good luck.
Cheers
Stefan
2014 Jan 13 10:25 AM
Hi Stefan,
Thank you for your reply and appreciate your help. Finally your code is working partially, once we have registered Dynamic wrapper.Dll.
Now in below code, first method is not returning any value and second method returning retailer ID but it should return terminal ID.
First Method for retailer ID:
CALL METHOD OF
win32
'StrGet' = retailerid
EXPORTING
#1 = ptrretailerid
#2 = 's'.
Second method for terminal ID:
CALL METHOD OF
win32
'StrGet' = terminalid
EXPORTING
#1 = ptrterminalid
#2 = 's'.
Apart from above issue, now we have to export some value to Dll functions, code is not working.
CALL METHOD OF
win32
'Register'
EXPORTING
#1 = 'Spanapi.dll'
#2 = 'api_TriggerTrxTrack2'
#3 = 'i=lll'
#4 = 'r=l'.
IF sy-subrc = 0.
CALL METHOD OF
win32
'api_TriggerTrxTrack2' = ret
EXPORTING
#1 = '2233333'
#2 = '22555'
#3 = '33'.
ENDIF.
Below is the function which we are trying to achieve.
Function Name:
api_TriggerTrxTrack2
Function Usage:
transaction function is used to activate an online transaction through the terminal. If you are using Magnetic cards then you must pass Track2 read through external card reader. In this case terminal will accept these information and start the transaction. The terminal in this case will never ask the customer again to swipe his card using POS terminal.
If the customer is holding EMV chip card then the card should be read through POS Chip card reader. External card reader cannot read Chip card details. In this case, Track2 data of the magnetic card is not available. To trigger the transaction with missing Track2 Data two spaces should be used as replacement for Track2 data and passed through the function parameter.
In case Track2 data read for EMV chip cards using external card reader and passed to the terminal then terminal will recognize that these data are for card having Chip and request the customer to insert his card again into the POS Chip card reader.
In this case a message saying “PLEASE INSERT CARD” and then a “0x80” frame will be sent from EFTPOS to PC.
And then the terminal will wait for 40 seconds till card is inserted. If the card not inserted the transaction will be suspended and declined.
Differentiate between MAG strip cards and EMV chip cards: You can identify the card type from track2 data available on the card. The fifth digit after the character “=” in track 2 data has two possible values:
1= Magnetic card
Example:
585265012634101026=070612000000306101
2=EMV chip card
Example:
585265012634101026=070622000000306101
Input Parameter:
The function takes 3 parameters
;585265987987987=12129879879879?
Ie; starting with a semicolon (;) and ending with (?) with fields separated using equal sign (=).
In case Chip card will be used to compelte the payment transaction then this parameter should contain two spaces only “ “ as replacement for Track2 data.
Thank you.
Harjyot
2014 Jan 20 6:37 AM
Hello Harjyot,
> first method is not returning any value and second method returning retailer ID but it should return terminal ID
I tested the code in ABAP and it delivers a different result in comparison with the equal VBScript code. Also I get the same result as you.
Please download Pointer for COM from here and try the following code.
"-Begin-----------------------------------------------------
Program zPointOfSale.
"-Type Pools--------------------------------------------
Type-Pools OLE2.
"-Variables---------------------------------------------
Data DX Type OLE2_OBJECT.
Data Ptr Type OLE2_OBJECT.
Data TerminalID Type String Value ''.
Data ptrTerminalID Type i Value 0.
Data RetailerID Type String Value ''.
Data ptrRetailerID Type i Value 0.
Data ret Type i Value 0.
"-Main--------------------------------------------------
Create Object DX 'DynamicWrapperX'.
If sy-subrc = 0 And DX-Handle <> 0 And
DX-Type = 'OLE2'.
Call Method Of DX 'Register'
Exporting
#1 = 'C:\Dummy\POS.dll'
#2 = 'API_GETTERMINALPARAMS'
#3 = 'i=uu' #4 = 'r=l'.
If sy-subrc = 0.
Create Object Ptr 'P4Com'.
If sy-subrc = 0 And Ptr-Handle <> 0 And
Ptr-Type = 'OLE2'.
Call Method Of Ptr 'CreateVar' = ptrRetailerID
Exporting #1 = 'RetailerID' #2 = 'String'
#3 = 9.
Call Method Of Ptr 'CreateVar' = ptrTerminalID
Exporting #1 = 'TerminalID' #2 = 'String'
#3 = 17.
Call Method Of DX 'API_GETTERMINALPARAMS' = ret
Exporting #1 = ptrRetailerID
#2 = ptrTerminalID.
Call Method Of DX 'StrGet' = TerminalID
Exporting #1 = ptrTerminalID #2 = 's'.
Call Method Of DX 'StrGet' = RetailerID
Exporting #1 = ptrRetailerID #2 = 's'.
Call Method Of Ptr 'DestroyVar'
Exporting #1 = 'RetailerID'.
Call Method Of Ptr 'DestroyVar'
Exporting #1 = 'TerminalID'.
EndIf.
EndIf.
Write: / ret.
Write: / TerminalID.
Write: / RetailerID.
Free Object Ptr.
Free Object DX.
EndIf.
"-End-------------------------------------------------------
Important hint: I twist the sequence of the API_GETTERMINALPARAMS arguments, because it is Pascal calling convention.
As far as I can say seems DynamicWrapperX pointer functions not work 100% correct in the context of the SAP GUI for Windows. If you use Pointer for COM (P4Com) with DynamicWrapperX in the context of SAP GUI for Windows, all works well.
I think api_TriggerTrxTrack2 use also pointer to strings, so you can use the same way as I described above.
Let us know the results.
Cheers
Stefan
2014 Jan 21 6:22 AM
Hello Harjyot,
I expand the Pointer for COM (P4COM) library. Now it is also possible to call functions in a dynamic link library - not so comfortable but it works.
Here an example:
"-Begin-----------------------------------------------------
Program zPointOfSale.
"-Type Pools--------------------------------------------
Type-Pools OLE2.
"-Variables---------------------------------------------
Data Ptr Type OLE2_OBJECT.
Data TerminalID Type String Value ''.
Data ptrTerminalID Type i Value 0.
Data RetailerID Type String Value ''.
Data ptrRetailerID Type i Value 0.
Data hDLL Type i Value 0.
Data Vars Type i Value 0.
Data ret Type i Value 0.
"-Main--------------------------------------------------
Create Object Ptr 'P4Com'.
If sy-subrc = 0 And Ptr-Handle <> 0 And
Ptr-Type = 'OLE2'.
"-Create variables in memory------------------------
Call Method Of Ptr 'CreateVar' = ptrTerminalID
Exporting #1 = 'TerminalID' #2 = 'String'
#3 = 9.
Call Method Of Ptr 'CreateVar' = ptrRetailerID
Exporting #1 = 'RetailerID' #2 = 'String'
#3 = 17.
"-Open the library----------------------------------
Call Method Of Ptr 'OpenLibrary' = hDLL
Exporting #1 = 'C:\Dummy\POS.dll'.
If hDLL <> 0 And ptrTerminalID <> 0 And
ptrRetailerID <> 0.
"-Create stack for function call------------------
Call Method Of Ptr 'CreateVar' = Vars
Exporting #1 = 'Vars' #2 = 'Array' #3 = 8.
If Vars <> 0.
"-Push variables on the stack-------------------
"
" Hint: It is in reverse order, because it is
" Pascal calling convention
"
"-----------------------------------------------
Call Method Of Ptr 'SetArrayLong'
Exporting #1 = 'Vars' #2 = 0
#3 = ptrRetailerID.
Call Method Of Ptr 'SetArrayLong'
Exporting #1 = 'Vars' #2 = 4
#3 = ptrTerminalID.
"-Call the function in the library--------------
Call Method Of Ptr 'CallFunction' = ret
Exporting #1 = hDLL
#2 = 'API_GETTERMINALPARAMS'
#3 = 2 #4 = Vars.
"-Get result------------------------------------
Call Method Of Ptr 'GetStringVar' = TerminalID
Exporting #1 = 'TerminalID'.
Call Method Of Ptr 'GetStringVar' = RetailerID
Exporting #1 = 'RetailerID'.
"-Destroy stack---------------------------------
Call Method Of Ptr 'DestroyVar' = ret
Exporting #1 = 'Vars'.
EndIf.
"-Destroy variables-------------------------------
Call Method Of Ptr 'DestroyVar' = ret
Exporting #1 = 'RetailerID'.
Call Method Of Ptr 'DestroyVar' = ret
Exporting #1 = 'TerminalID'.
"-Close the library-------------------------------
Call Method Of Ptr 'CloseLibrary' = ret
Exporting #1 = hDLL.
EndIf.
Write: / TerminalID.
Write: / RetailerID.
Free Object Ptr.
EndIf.
"-End-------------------------------------------------------
Cheers
Stefan
2014 Jan 23 6:59 PM
2014 Jan 27 6:31 AM
2014 Jan 27 1:11 PM
2014 Jan 27 1:38 PM
Hello Marcelo,
thank you very much for your reply and your post.
The way you describe is via a COM DLL. You must register your DLL in the Windows registry to use it via SAP GUI for Windows inside ABAP. In this thread we discuss the possibility to use functions from non COM DLLs.
Two tips from my side:
1. Check the necessity of the entries in the TAC SOLE. In my cases it works without these entries.
2. Don't use the hive CLASSES_ROOT in your registry, you need local admin rights to write the keys. It is better to use the CURRENT_USER hive.
Cheers
Stefan
2015 Apr 21 3:19 PM
Hi Stefan
I tried to follow your example to test my VC++ dll but failed, could you please help to have a look? Thank you very much
2. Copy the DLL_Tutorial.dll and dynwrapx.dll to a local folder
3. Register dynwrapx.dll
4. Run TCode SOLE to add OLE application
5. Tried to call DLL_Tutorial.dll but failed
report z_testdll.
include ole2incl.
"-Variables------------------------------
data Win32 type ole2_object.
data ret type i.
CREATE OBJECT Win32 'DYNAMICWRAPPERX'.
CALL METHOD OF Win32 'Register'
EXPORTING
#1 = 'c:\work\DLL_Tutorial.dll'
#2 = 'Add'
#3 = 'i=ll'
#4 = 'r=l'.
CALL METHOD OF Win32 'Add' = ret
EXPORTING #1 = 6 #2 = 8.
write ret.
free object win32.
Best regards
James
2015 Apr 21 9:05 PM
Hello James,
welcome to this forum and thanks for your reply.
At first, to retrace your error, I create a C similar library to yours:
; Begin----------------------------------------------------
ProcedureCDLL.l Add(a.l, b.l)
ProcedureReturn a + b
EndProcedure
; End------------------------------------------------------
After the build of the DLL I create a VBS program to check the functionality:
'-Begin----------------------------------------------------
Set DX = CreateObject("DynamicWrapperX")
DX.Register "DLL_Tutorial.dll", "Add", "i=ll", "r=l"
res = DX.Add(2, 😎
MsgBox res '10
'-End------------------------------------------------------
Up to this point all works correct, the message box shows 10.
Now I take your ABAP program and my library and runs it in my environment and all works as expected.
Generally it works.... Your ABAP code is perfect.
What could be your problem?
Are you working with a 64-bit Windows environment? If so, register dynwrapx.dll from syswow64 directory and not from system32.
That is the only reason I can see for the moment.
Hint: It is not necessary to register the dynwrapx library with the TAC SOLE.
Let us know your results.
Cheers
Stefan
2015 Apr 23 3:47 PM
Hi Stefan
Thanks for your reply.
It's a good idea to test dll firstly via VBS 🙂
Yes, my testing OS is 64bit based. I copied the file dynwrapx to folder syswow64 and run regsvr32 dynwrapx.dll, is that right?
But seems the testing VBS does not work
Best regards
James
2015 Apr 24 8:05 AM
Hello James,
you are registering the library correct.
But you call the VBScript via the Explorer, so it starts the 64-bit WSH. Call the script via the command line in the directory syswow64.
With this way you start the 32-bit WSH and now it should work.
Let us know your results.
Cheers
Stefan
2015 Apr 24 5:39 PM
Dear Stefan
I finially got the right result in VBS and ABAP, it's because of the dll file which should be complied in Release but not in Debug. Really appraciate your help. Thank you, thank you very much
Best regards
James
2021 Mar 13 2:48 PM
Unfortunately, the DLL of DynamicWrapperX was put into quarantine by Windows Security because of threat HackTool:Win32/Daoak.A, so unfortunately I can't/must not use it on my professional laptop.