nwrfc 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +85 -0
- data/Rakefile +8 -0
- data/lib/dev_rfc.trc +133 -0
- data/lib/nwrfc.old.rb +338 -0
- data/lib/nwrfc.rb +409 -0
- data/lib/nwrfc/nwrfclib.rb +449 -0
- metadata +71 -0
data/lib/nwrfc.rb
ADDED
@@ -0,0 +1,409 @@
|
|
1
|
+
# Author:: Martin Ceronio martin.ceronio@infosize.co.za
|
2
|
+
# Copyright:: Copyright (c) 2012 Martin Ceronio
|
3
|
+
# License:: MIT and/or Creative Commons Attribution-ShareAlike
|
4
|
+
# SAP, Netweaver, RFC and other names referred to in this code
|
5
|
+
# are, or may be registered trademarks and the property of SAP, AG
|
6
|
+
# No ownership over any of these is asserted by Martin Ceronio
|
7
|
+
|
8
|
+
require File.dirname(__FILE__)+'/nwrfc/nwrfclib'
|
9
|
+
|
10
|
+
require 'date'
|
11
|
+
require 'time'
|
12
|
+
|
13
|
+
# This library provides a way to call the functions of the SAP Netweaver RFC
|
14
|
+
# SDK, i.e. opening a connection to an ABAP system, calling functions etc., as
|
15
|
+
# well as running an RFC service
|
16
|
+
#---
|
17
|
+
# *TODO*: Create an error class that wraps the SAP error struct, so it can
|
18
|
+
# be raised and the caller can get all the information from there
|
19
|
+
#+++
|
20
|
+
|
21
|
+
module NWRFC
|
22
|
+
|
23
|
+
NW_TIME_FORMAT = "%H%M%S"
|
24
|
+
NW_DATE_FORMAT = "%Y%m%d"
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
self.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def NWRFC.get_version
|
31
|
+
# See custom method FFI::Pointer#read_string_dn in nwrfclib.rb
|
32
|
+
# http://stackoverflow.com/questions/9293307/ruby-ffi-ruby-1-8-reading-utf-16le-encoded-strings
|
33
|
+
major = FFI::MemoryPointer.new(:uint)
|
34
|
+
minor = FFI::MemoryPointer.new(:uint)
|
35
|
+
patch = FFI::MemoryPointer.new(:uint)
|
36
|
+
version = NWRFCLib.get_version(major, minor, patch)
|
37
|
+
[version.read_string_dn.uC, major.read_uint, minor.read_uint, patch.read_uint]
|
38
|
+
end
|
39
|
+
|
40
|
+
def NWRFC.check_error(error_handle)
|
41
|
+
raise "Error code #{error_handle[:code]} group #{error_handle[:group]} message #{error_handle[:message].get_str}" \
|
42
|
+
if error_handle[:code] > 0
|
43
|
+
end
|
44
|
+
|
45
|
+
# Represents a connection to a SAP system that can be used to invoke
|
46
|
+
# remote-enabled functions
|
47
|
+
class Connection
|
48
|
+
attr_reader :handle
|
49
|
+
|
50
|
+
# Opens a connection to the SAP system with the given connection parameters
|
51
|
+
# (described in the NW RFC SDK document), passed in the form of a Hash, e.g.
|
52
|
+
# Connection.new { 'ashost' :=> 'ajax.domain.com', ... }
|
53
|
+
def initialize(conn_params)
|
54
|
+
conn_params.untaint #For params loaded from file, e.g.
|
55
|
+
raise "Connection parameters must be a Hash" unless conn_params.instance_of? Hash
|
56
|
+
#NWRFCLib.init
|
57
|
+
@cparams = NWRFCLib.make_conn_params(conn_params)
|
58
|
+
raise "Could not create valid pointer from parameters" unless @cparams.instance_of? FFI::MemoryPointer
|
59
|
+
#@errp = FFI::MemoryPointer.new(NWRFCLib::RFCError)
|
60
|
+
@error = NWRFCLib::RFCError.new #@errp
|
61
|
+
@handle = NWRFCLib.open_connection(@cparams, conn_params.length, @error.to_ptr)
|
62
|
+
NWRFC.check_error(@error)
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# Call the NW RFC SDK's RfcCloseConnection() function with the current
|
67
|
+
# connection; this (should - *TODO* - check) invalidate the connection handle
|
68
|
+
# and cause an error on any subsequent use of this connection
|
69
|
+
def disconnect
|
70
|
+
NWRFCLib.close_connection(@handle, @error.to_ptr)
|
71
|
+
NWRFC.check_error(@error)
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_function(function_name)
|
75
|
+
Function.new(self, function_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return details about the current connection and the system
|
79
|
+
def connection_info
|
80
|
+
return @get_connection_attributes if @get_connection_attributes
|
81
|
+
conn_info = NWRFCLib::RFCConnection.new
|
82
|
+
rc = NWRFCLib.get_connection_attributes(@handle, conn_info.to_ptr, @error)
|
83
|
+
NWRFC.check_error(@error) if rc > 0
|
84
|
+
@get_connection_attributes = conn_info.members.inject({}) {|hash, member|
|
85
|
+
hash[member] = conn_info[member].get_str #get_str, own definition in nwrfclib.rb, FFI::StructLayout::CharArray#get_str
|
86
|
+
hash
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
# Represents a remote-enabled function module for RFC, can be instantiated either by the caller
|
93
|
+
# or by calling Connection#get_function. This only represents the description of the function;
|
94
|
+
# to call a function, an instance of a function call must be obtained with #get_function_call
|
95
|
+
class Function
|
96
|
+
attr_reader :desc, :connection, :function_name
|
97
|
+
|
98
|
+
# Get a function module instance; can also be obtained by calling Connection#get_function
|
99
|
+
def initialize(connection, function_name)
|
100
|
+
@function_name = function_name
|
101
|
+
@error = NWRFCLib::RFCError.new
|
102
|
+
@desc = NWRFCLib.get_function_desc(connection.handle, function_name.cU, @error.to_ptr)
|
103
|
+
@connection = connection
|
104
|
+
NWRFC.check_error(@error)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Create and return a callable instance of this function module
|
108
|
+
def get_function_call
|
109
|
+
FunctionCall.new(self)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Get the number of parameters this function has
|
113
|
+
def parameter_count
|
114
|
+
pcount = FFI::MemoryPointer.new(:uint)
|
115
|
+
rc = NWRFCLib.get_parameter_count(@desc, pcount, @error)
|
116
|
+
NWRFC.check_error(@error) if rc > 0
|
117
|
+
pcount.read_uint
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
# Representation of a data container (function, structure or table)
|
123
|
+
class DataContainer
|
124
|
+
attr_reader :handle, :desc
|
125
|
+
|
126
|
+
def initialize(handle)
|
127
|
+
@error = NWRFCLib::RFCError.new
|
128
|
+
@handle = handle
|
129
|
+
@desc = NWRFCLib.describe_type(@handle, @error)
|
130
|
+
@member_metadata = {} #Cache of metadata for members
|
131
|
+
NWRFC.check_error(@error)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Return the member specified by string or symbol
|
135
|
+
def [](element)
|
136
|
+
member = element.to_s.upcase
|
137
|
+
metadata = member_metadata(element)
|
138
|
+
case metadata[:type]
|
139
|
+
when :RFCTYPE_CHAR
|
140
|
+
# TODO: Try use :string parameter in get_chars
|
141
|
+
return read_chars(metadata)
|
142
|
+
when :RFCTYPE_DATE
|
143
|
+
return Date.parse(read_chars(metadata))
|
144
|
+
#return Date.new(date[0..3].to_i, date[4..5].to_i, date[6..7].to_i)
|
145
|
+
when :RFCTYPE_BCD
|
146
|
+
size = metadata[:ucLength]
|
147
|
+
cb = FFI::MemoryPointer.new :char, size * 2
|
148
|
+
rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, size * 2, @error.to_ptr)
|
149
|
+
NWRFC.check_error(@error) if rc > 0
|
150
|
+
cb.read_string(size).uC
|
151
|
+
when :RFCTYPE_TIME
|
152
|
+
# TODO: See whether we can optimize this
|
153
|
+
timec = read_chars(metadata)
|
154
|
+
return Time.parse("#{timec[0..1]}:#{timec[2..3]}:#{timec[4..5]}")
|
155
|
+
when :RFCTYPE_BYTE
|
156
|
+
return read_chars(metadata)
|
157
|
+
when :RFCTYPE_TABLE
|
158
|
+
new_handle = NWRFCLib::RFCDataContainer.new
|
159
|
+
rc = NWRFCLib.get_table(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
|
160
|
+
NWRFC.check_error(@error) if rc > 0
|
161
|
+
# CAVEAT: Other calls using the handle require "handle" field
|
162
|
+
# of the RFC_DATA_CONTAINER struct for some reason.
|
163
|
+
new_handle = new_handle[:handle]
|
164
|
+
value = Table.new(new_handle)
|
165
|
+
when :RFCTYPE_NUM
|
166
|
+
return read_chars(metadata).to_i
|
167
|
+
when :RFCTYPE_FLOAT
|
168
|
+
double = FFI::MemoryPointer.new :double
|
169
|
+
rc = NWRFCLib.get_float(@handle, member.cU, double, @error)
|
170
|
+
NWRFC.check_error(@error) if rc > 0
|
171
|
+
return double.get_double(0)
|
172
|
+
when :RFCTYPE_INT
|
173
|
+
int = FFI::MemoryPointer.new :int
|
174
|
+
rc = NWRFCLib.get_int(@handle, member.cU, int, @error)
|
175
|
+
NWRFC.check_error(@error) if rc > 0
|
176
|
+
return int.get_int(0)
|
177
|
+
when :RFCTYPE_INT2
|
178
|
+
short = FFI::MemoryPointer.new :short
|
179
|
+
rc = NWRFCLib.get_int2(@handle, member.cU, short, @error)
|
180
|
+
NWRFC.check_error(@error) if rc > 0
|
181
|
+
return short.get_short(0)
|
182
|
+
when :RFCTYPE_INT1
|
183
|
+
int1 = FFI::MemoryPointer.new :uint8
|
184
|
+
rc = NWRFCLib.get_int1(@handle, member.cU, int1, @error)
|
185
|
+
NWRFC.check_error(@error) if rc > 0
|
186
|
+
return int1.get_uint8(0)
|
187
|
+
when :RFCTYPE_NULL
|
188
|
+
raise "Unsupported type RFCTYPE_NULL" #You should never run into this
|
189
|
+
when :RFCTYPE_STRUCTURE
|
190
|
+
new_handle = NWRFCLib::RFCDataContainer.new
|
191
|
+
rc = NWRFCLib.get_structure(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
|
192
|
+
NWRFC.check_error(@error) if rc > 0
|
193
|
+
new_handle = new_handle[:handle]
|
194
|
+
value = Structure.new(new_handle)
|
195
|
+
when :RFCTYPE_DECF16
|
196
|
+
return read_chars(metadata).to_f
|
197
|
+
when :RFCTYPE_DECF34
|
198
|
+
return read_chars(metadata).to_f
|
199
|
+
when :RFCTYPE_XMLDATA
|
200
|
+
raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
|
201
|
+
when :RFCTYPE_STRING
|
202
|
+
return read_string(metadata)
|
203
|
+
when :RFCTYPE_XSTRING
|
204
|
+
else
|
205
|
+
raise "Illegal member type #{metadata[:type]}"
|
206
|
+
end
|
207
|
+
NWRFC.check_error(@error)
|
208
|
+
value
|
209
|
+
end
|
210
|
+
|
211
|
+
def []=(element, value)
|
212
|
+
member = element.to_s.upcase
|
213
|
+
metadata = member_metadata(element)
|
214
|
+
case metadata[:type]
|
215
|
+
when :RFCTYPE_CHAR
|
216
|
+
NWRFCLib.set_chars(@handle, member.cU, value.cU, value.length, @error.to_ptr)
|
217
|
+
when :RFCTYPE_DATE
|
218
|
+
value = value_to_date(value)
|
219
|
+
NWRFCLib.set_date(@handle, member.cU, value.cU, @error.to_ptr)
|
220
|
+
when :RFCTYPE_BCD
|
221
|
+
when :RFCTYPE_TIME
|
222
|
+
value = value_to_time(value)
|
223
|
+
NWRFCLib.set_time(@handle, member.cU, value.cU, @error.to_ptr)
|
224
|
+
when :RFCTYPE_BYTE
|
225
|
+
when :RFCTYPE_TABLE
|
226
|
+
when :RFCTYPE_NUM
|
227
|
+
when :RFCTYPE_FLOAT
|
228
|
+
NWRFCLib.set_float(@handle, member.cU, value.to_f, @error.to_ptr)
|
229
|
+
#NWRFCLib.set_chars(@handle, member.cU, value.to_s.cU, value.to_s.length, @error.to_ptr)
|
230
|
+
when :RFCTYPE_INT
|
231
|
+
NWRFCLib.set_int(@handle, member.cU, value.to_i, @error.to_ptr)
|
232
|
+
when :RFCTYPE_INT2
|
233
|
+
NWRFCLib.set_int2(@handle, member.cU, value.to_i, @error.to_ptr)
|
234
|
+
when :RFCTYPE_INT1
|
235
|
+
NWRFCLib.set_int1(@handle, member.cU, value.to_i, @error.to_ptr)
|
236
|
+
when :RFCTYPE_NULL
|
237
|
+
raise "Unsupported type RFCTYPE_NULL" #You should never run into this
|
238
|
+
when :RFCTYPE_STRUCTURE
|
239
|
+
when :RFCTYPE_DECF16
|
240
|
+
when :RFCTYPE_DECF34
|
241
|
+
when :RFCTYPE_XMLDATA
|
242
|
+
when :RFCTYPE_STRING
|
243
|
+
when :RFCTYPE_XSTRING
|
244
|
+
else
|
245
|
+
raise "Illegal member type #{@members[:type]}"
|
246
|
+
end
|
247
|
+
NWRFC.check_error(@error)
|
248
|
+
end
|
249
|
+
|
250
|
+
def value_to_time(value)
|
251
|
+
return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
|
252
|
+
value.to_s
|
253
|
+
end
|
254
|
+
|
255
|
+
def value_to_date(value)
|
256
|
+
return value.strftime(NW_DATE_FORMAT) if value.respond_to? :strftime
|
257
|
+
# Force the resulting string into 8 characters otherwise
|
258
|
+
value = value.to_s
|
259
|
+
value << ' ' until value.size == 8 if value.size < 8
|
260
|
+
value = value[0..7] if value.size > 8
|
261
|
+
value
|
262
|
+
end
|
263
|
+
|
264
|
+
def value_to_time(value)
|
265
|
+
return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
|
266
|
+
# Force the resulting string into 6 characters otherwise
|
267
|
+
value = value.to_s
|
268
|
+
value << ' ' until value.size == 6 if value.size < 6
|
269
|
+
value = value[0..6] if value.size > 6
|
270
|
+
value
|
271
|
+
end
|
272
|
+
|
273
|
+
# Get the metadata of a member (function, structure or table)
|
274
|
+
def member_metadata(member_name)
|
275
|
+
member = member_name.to_s.upcase
|
276
|
+
if self.class == NWRFC::FunctionCall
|
277
|
+
fpar = NWRFCLib::RFCFuncParam.new
|
278
|
+
rc = NWRFCLib.get_parameter_desc_by_name(@desc, member.cU, fpar.to_ptr, @error.to_ptr)
|
279
|
+
NWRFC.check_error(@error) if rc > 0
|
280
|
+
member_to_hash(fpar)
|
281
|
+
elsif self.class == NWRFC::Table || self.class == NWRFC::Structure
|
282
|
+
fd = NWRFCLib::RFCFieldDesc.new
|
283
|
+
rc = NWRFCLib.get_field_desc_by_name(@desc, member.cU, fd.to_ptr, @error.to_ptr)
|
284
|
+
NWRFC.check_error(@error) if rc > 0
|
285
|
+
member_to_hash(fd)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
private
|
290
|
+
# Returns the subset of metadata values common to both a function parameter
|
291
|
+
# and a type field
|
292
|
+
def member_to_hash(member)
|
293
|
+
{
|
294
|
+
:name => member[:name].get_str,
|
295
|
+
:type => NWRFCLib::RFCTYPE[member[:type]],
|
296
|
+
:nucLength => member[:nucLength],
|
297
|
+
:ucLength => member[:ucLength],
|
298
|
+
:decimals => member[:decimals],
|
299
|
+
:typeDescHandle => member[:typeDescHandle]
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
def read_chars(metadata)
|
304
|
+
size = metadata[:ucLength]
|
305
|
+
cb = FFI::MemoryPointer.new :char, size
|
306
|
+
rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, metadata[:nucLength], @error.to_ptr)
|
307
|
+
NWRFC.check_error(@error) if rc > 0
|
308
|
+
cb.read_string(size).uC
|
309
|
+
end
|
310
|
+
|
311
|
+
def read_string(metadata)
|
312
|
+
#size = metadata[:ucLength]
|
313
|
+
size = FFI::MemoryPointer.new(:uint)
|
314
|
+
rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
|
315
|
+
NWRFC.check_error(@error) if rc > 0
|
316
|
+
buf_len = size.read_uint + 1
|
317
|
+
sbuf = FFI::MemoryPointer.new :char, buf_len * NWRFCLib::B_SIZE
|
318
|
+
rc = NWRFCLib.get_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
|
319
|
+
NWRFC.check_error(@error) if rc > 0
|
320
|
+
sbuf.read_string(sbuf.size).uC
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
class FunctionCall < DataContainer
|
326
|
+
attr_reader :handle, :desc, :connection, :function
|
327
|
+
|
328
|
+
def initialize(function)
|
329
|
+
@error = NWRFCLib::RFCError.new
|
330
|
+
@function = function
|
331
|
+
@connection = function.connection
|
332
|
+
@handle = NWRFCLib.create_function(@function.desc, @error.to_ptr)
|
333
|
+
@desc = function.desc
|
334
|
+
NWRFC.check_error(@error)
|
335
|
+
end
|
336
|
+
|
337
|
+
def invoke
|
338
|
+
rc = NWRFCLib.invoke(@connection.handle, @handle, @error.to_ptr)
|
339
|
+
NWRFC.check_error(@error) if rc > 0
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
|
344
|
+
class Table < DataContainer
|
345
|
+
|
346
|
+
include Enumerable
|
347
|
+
|
348
|
+
def each(&block)
|
349
|
+
rc = NWRFCLib.move_to_first_row(@handle, @error)
|
350
|
+
NWRFC.check_error(@error) if rc > 0
|
351
|
+
size.times do |row|
|
352
|
+
struct_handle = NWRFCLib.get_current_row(@handle, @error)
|
353
|
+
NWRFC.check_error(@error)
|
354
|
+
# CAVEAT: Other calls using the handle require "handle" field
|
355
|
+
# of the RFC_DATA_CONTAINER struct
|
356
|
+
yield Structure.new(struct_handle)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def size
|
361
|
+
rows = FFI::MemoryPointer.new(:uint)
|
362
|
+
rc = NWRFCLib.get_row_count(@handle, rows, @error)
|
363
|
+
rows.read_uint
|
364
|
+
end
|
365
|
+
|
366
|
+
# Delete all rows from (empty) the table
|
367
|
+
def clear
|
368
|
+
rc = delete_all_rows(@handle, @error)
|
369
|
+
NWRFC.check_error(@error) if rc > 0
|
370
|
+
end
|
371
|
+
|
372
|
+
# Retrieve the row at the given index
|
373
|
+
def [](index)
|
374
|
+
rc = NWRFCLib.move_to(@handle, index, @error)
|
375
|
+
NWRFC.check_error(@error) if rc > 0
|
376
|
+
struct_handle = NWRFCLib.get_current_row(@handle, @error)
|
377
|
+
NWRFC.check_error(@error)
|
378
|
+
Structure.new(struct_handle)
|
379
|
+
end
|
380
|
+
|
381
|
+
end #class Table
|
382
|
+
|
383
|
+
# Represents a structure. An instance is obtained internally by passing the
|
384
|
+
# handle of a structure. A user can obtain an instance by invoking sub-field
|
385
|
+
# access of a structure or a function
|
386
|
+
class Structure < DataContainer
|
387
|
+
|
388
|
+
# Return a list (array) of symbols representing the names of the fields
|
389
|
+
# of this structure
|
390
|
+
#---
|
391
|
+
# TODO: This is not working!
|
392
|
+
def fields
|
393
|
+
fc = FFI::MemoryPointer.new(:uint)
|
394
|
+
rc = NWRFCLib.get_field_count(@handle, fc, @error)
|
395
|
+
NWRFC.check_error(@error) if rc > 0
|
396
|
+
fc = fc.read_uint
|
397
|
+
fd = NWRFCLib::RFCFieldDesc.new
|
398
|
+
fields = []
|
399
|
+
debugger
|
400
|
+
fc.times do |index|
|
401
|
+
rc = NWRFCLib.get_field_desc_by_index(@handle, index, fd.to_ptr, @error.to_ptr)
|
402
|
+
NWRFC.check_error(@error) if rc > 0
|
403
|
+
fields << fd[:name].get_str.to_sym
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
end # class Structure
|
408
|
+
|
409
|
+
end #module NWRFC
|
@@ -0,0 +1,449 @@
|
|
1
|
+
# Author:: Martin Ceronio martin.ceronio@infosize.co.za
|
2
|
+
# Copyright:: Copyright (c) 2012 Martin Ceronio
|
3
|
+
# License:: MIT and/or Creative Commons Attribution-ShareAlike
|
4
|
+
# SAP, Netweaver, RFC and other names referred to in this code
|
5
|
+
# are, or may be registered trademarks and the property of SAP, AG
|
6
|
+
# No ownership over any of these is asserted by Martin Ceronio
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'ffi'
|
10
|
+
require 'iconv'
|
11
|
+
|
12
|
+
RUBY_VERSION_18 = RUBY_VERSION[0..2] == "1.8"
|
13
|
+
|
14
|
+
# Provide an alias for FFI::MemoryPointer#read_int to `read_uint` in 1.8
|
15
|
+
# See http://stackoverflow.com/questions/9035661/ruby-ffi-memorypointer-read-int-present-in-1-9-but-not-1-8
|
16
|
+
# Probably not good to interpret an unsigned int as an int, but we don't expect to use it for big values
|
17
|
+
# that could result in sign conversion
|
18
|
+
if RUBY_VERSION_18
|
19
|
+
FFI::MemoryPointer.class_eval{ alias :read_uint :read_int}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Enhancement to FFI::Pointer to be able to read a double-null terminated string,
|
23
|
+
# which would be returned e.g. by RfcGetVersion() in the SDK
|
24
|
+
# See http://stackoverflow.com/questions/9293307/ruby-ffi-ruby-1-8-reading-utf-16le-encoded-strings
|
25
|
+
module FFI
|
26
|
+
class Pointer
|
27
|
+
|
28
|
+
# Enhancement to FFI::Pointer to be able to read a double-null terminated string,
|
29
|
+
# which would be returned e.g. by RfcGetVersion() in the SDK
|
30
|
+
# See http://stackoverflow.com/questions/9293307/ruby-ffi-ruby-1-8-reading-utf-16le-encoded-strings
|
31
|
+
# It should be safe to call this on a Pointer within the context of the NW RFC SDK library,
|
32
|
+
# because all strings are supposed to be UTF-16LE encoded and double-null terminated
|
33
|
+
def read_string_dn(max=0)
|
34
|
+
cont_nullcount = 0
|
35
|
+
offset = 0
|
36
|
+
until cont_nullcount == 2
|
37
|
+
byte = get_bytes(offset,1)
|
38
|
+
cont_nullcount += 1 if byte == "\000"
|
39
|
+
cont_nullcount = 0 if byte != "\000"
|
40
|
+
offset += 1
|
41
|
+
end
|
42
|
+
get_bytes(0,offset+1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Enhancement to the String class to put string values into double-null
|
48
|
+
# terminated UTF16 little endian encoded strings as required by the NW RFC
|
49
|
+
# SDK function, which should work on Linux and Windows (and maybe other
|
50
|
+
# architectures, though the plan is not to support them)
|
51
|
+
#String.class_eval{define_method(:cU){ Iconv.conv("UTF-16LE", "UTF8", self+"\0") }}
|
52
|
+
class String
|
53
|
+
def cU
|
54
|
+
NWRFCLib::Cutf8_to_utf16le.iconv(self+"\0")
|
55
|
+
end
|
56
|
+
|
57
|
+
def uC
|
58
|
+
NWRFCLib::Cutf16le_to_utf8.iconv(self).strip
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
#String.class_eval{define_method(:cU){ NWRFCLib::Cutf8_to_utf16le.iconv(self+"\0") }}
|
63
|
+
|
64
|
+
# Enhancement to FFI::StructLayout::CharArray to add a get_str method that changes the
|
65
|
+
# string value of the character array by enforcing encoding of UTF-16LE (as used in NW RFC SDK)
|
66
|
+
# and strips off blanks at the end to return a readable String
|
67
|
+
class FFI::StructLayout::CharArray
|
68
|
+
def get_str
|
69
|
+
#Iconv.conv("UTF8", "UTF-16LE", self.to_ptr.read_string(self.size)).strip
|
70
|
+
NWRFCLib::Cutf16le_to_utf8.iconv(self.to_ptr.read_string(self.size)).strip
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Library wrapper around NW RFC SDK shared library using RUBY-FFI
|
75
|
+
# FIXME: Make structs managed structs and deconstruct them on GC
|
76
|
+
module NWRFCLib
|
77
|
+
|
78
|
+
Cutf8_to_utf16le = Iconv.new("UTF-16LE", "UTF8")
|
79
|
+
Cutf16le_to_utf8 = Iconv.new("UTF8", "UTF-16LE")
|
80
|
+
|
81
|
+
extend FFI::Library
|
82
|
+
ffi_lib '/home/martin/nwrfcsdk/lib/libsapnwrfc.so'
|
83
|
+
|
84
|
+
# Multiplier for providing correct byte size for String passed to RFC library
|
85
|
+
#TODO: Make platform-dependent size based on RUBY_PLATFORM
|
86
|
+
B_SIZE = 2
|
87
|
+
|
88
|
+
RFC_RC = enum(
|
89
|
+
:RFC_OK,
|
90
|
+
:RFC_COMMUNICATION_FAILURE,
|
91
|
+
:RFC_LOGON_FAILURE,
|
92
|
+
:RFC_ABAP_RUNTIME_FAILURE,
|
93
|
+
:RFC_ABAP_MESSAGE,
|
94
|
+
:RFC_ABAP_EXCEPTION,
|
95
|
+
:RFC_CLOSED,
|
96
|
+
:RFC_CANCELED,
|
97
|
+
:RFC_TIMEOUT,
|
98
|
+
:RFC_MEMORY_INSUFFICIENT,
|
99
|
+
:RFC_VERSION_MISMATCH,
|
100
|
+
:RFC_INVALID_PROTOCOL,
|
101
|
+
:RFC_SERIALIZATION_FAILURE,
|
102
|
+
:RFC_INVALID_HANDLE,
|
103
|
+
:RFC_RETRY,
|
104
|
+
:RFC_EXTERNAL_FAILURE,
|
105
|
+
:RFC_EXECUTED,
|
106
|
+
:RFC_NOT_FOUND,
|
107
|
+
:RFC_NOT_SUPPORTED,
|
108
|
+
:RFC_ILLEGAL_STATE,
|
109
|
+
:RFC_INVALID_PARAMETER,
|
110
|
+
:RFC_CODEPAGE_CONVERSION_FAILURE,
|
111
|
+
:RFC_CONVERSION_FAILURE,
|
112
|
+
:RFC_BUFFER_TOO_SMALL,
|
113
|
+
:RFC_TABLE_MOVE_BOF,
|
114
|
+
:RFC_TABLE_MOVE_EOF,
|
115
|
+
:RFC_UNKNOWN_ERROR
|
116
|
+
)
|
117
|
+
|
118
|
+
RFC_ERROR_GROUP = enum(
|
119
|
+
:OK,
|
120
|
+
:ABAP_APPLICATION_FAILURE,
|
121
|
+
:ABAP_RUNTIME_FAILURE,
|
122
|
+
:LOGON_FAILURE,
|
123
|
+
:COMMUNICATION_FAILURE,
|
124
|
+
:EXTERNAL_RUNTIME_FAILURE,
|
125
|
+
:EXTERNAL_APPLICATION_FAILURE
|
126
|
+
)
|
127
|
+
|
128
|
+
RFC_DIRECTION = enum(
|
129
|
+
:RFC_IMPORT, 1,
|
130
|
+
:RFC_EXPORT, 2,
|
131
|
+
:RFC_CHANGING, 3,
|
132
|
+
:RFC_TABLES, 7
|
133
|
+
)
|
134
|
+
|
135
|
+
RFCTYPE = enum(
|
136
|
+
:RFCTYPE_CHAR , 0,
|
137
|
+
:RFCTYPE_DATE , 1,
|
138
|
+
:RFCTYPE_BCD , 2,
|
139
|
+
:RFCTYPE_TIME , 3,
|
140
|
+
:RFCTYPE_BYTE , 4,
|
141
|
+
:RFCTYPE_TABLE , 5,
|
142
|
+
:RFCTYPE_NUM , 6,
|
143
|
+
:RFCTYPE_FLOAT , 7,
|
144
|
+
:RFCTYPE_INT , 8,
|
145
|
+
:RFCTYPE_INT2 , 9,
|
146
|
+
:RFCTYPE_INT1 , 10,
|
147
|
+
:RFCTYPE_NULL , 14,
|
148
|
+
:RFCTYPE_STRUCTURE , 17,
|
149
|
+
:RFCTYPE_DECF16 , 23,
|
150
|
+
:RFCTYPE_DECF34 , 24,
|
151
|
+
:RFCTYPE_XMLDATA , 28,
|
152
|
+
:RFCTYPE_STRING , 29,
|
153
|
+
:RFCTYPE_XSTRING , 30
|
154
|
+
)
|
155
|
+
|
156
|
+
# Connection parameter wrapper (struct RFC_CONNECTION_PARAMETER in sapnwrfc.h)
|
157
|
+
class RFCConnParam < FFI::Struct
|
158
|
+
layout :name, :pointer,
|
159
|
+
:value, :pointer
|
160
|
+
end
|
161
|
+
|
162
|
+
# Connection Details (struct RFC_ATTRIBUTES in sapnwrfc.h)
|
163
|
+
class RFCConnection < FFI::Struct
|
164
|
+
layout :dest, [:char, (64+1)*B_SIZE],
|
165
|
+
:host, [:char, (100+1)*B_SIZE],
|
166
|
+
:partnerHost, [:char, (100+1)*B_SIZE],
|
167
|
+
:sysNumber, [:char, (2+1)*B_SIZE],
|
168
|
+
:sysId, [:char, (8+1)*B_SIZE],
|
169
|
+
:client, [:char, (3+1)*B_SIZE],
|
170
|
+
:user, [:char, (12+1)*B_SIZE],
|
171
|
+
:language, [:char, (2+1)*B_SIZE],
|
172
|
+
:trace, [:char, (1+1)*B_SIZE],
|
173
|
+
:isoLanguage, [:char, (2+1)*B_SIZE],
|
174
|
+
:codepage, [:char, (4+1)*B_SIZE],
|
175
|
+
:partnerCodepage, [:char, (4+1)*B_SIZE],
|
176
|
+
:rfcRole, [:char, (1+1)*B_SIZE],
|
177
|
+
:type, [:char, (1+1)*B_SIZE],
|
178
|
+
:partnerType, [:char, (1+1)*B_SIZE],
|
179
|
+
:rel, [:char, (4+1)*B_SIZE],
|
180
|
+
:partnerRel, [:char, (4+1)*B_SIZE],
|
181
|
+
:kernelRel, [:char, (4+1)*B_SIZE],
|
182
|
+
:cpicConvId, [:char, (8+1)*B_SIZE],
|
183
|
+
:progName, [:char, (128+1)*B_SIZE],
|
184
|
+
:reserved, [:char, (86+1)*B_SIZE]
|
185
|
+
end
|
186
|
+
|
187
|
+
# Error info wrapper (struct RFC_ERROR_INFO in sapnwrfc.h)
|
188
|
+
class RFCError < FFI::Struct
|
189
|
+
layout :code, :int,
|
190
|
+
:group, :int,
|
191
|
+
:key, [:char, (128)*B_SIZE],
|
192
|
+
:message, [:char, (512)*B_SIZE],
|
193
|
+
:abapMsgClass, [:char, (20+1)*B_SIZE],
|
194
|
+
:abapMsgType, [:char, (1+1)*B_SIZE],
|
195
|
+
:abapMsgNumber, [:char, (3+1)*B_SIZE],
|
196
|
+
:abapMsgV1, [:char, (50+1)*B_SIZE],
|
197
|
+
:abapMsgV2, [:char, (50+1)*B_SIZE],
|
198
|
+
:abapMsgV3, [:char, (50+1)*B_SIZE],
|
199
|
+
:abapMsgV4, [:char, (50+1)*B_SIZE]
|
200
|
+
end
|
201
|
+
|
202
|
+
# Function Parameter Description (struct RFC_PARAMETER_DESC in sapnwrfc.h)
|
203
|
+
class RFCFuncParam < FFI::Struct
|
204
|
+
layout :name, [:char, (30+1)*B_SIZE],
|
205
|
+
:type, :int, #enum RFCTYPE
|
206
|
+
:direction, :int, #enum RFC_DIRECTION
|
207
|
+
:nucLength, :uint,
|
208
|
+
:ucLength, :uint,
|
209
|
+
:decimals, :uint,
|
210
|
+
:typeDescHandle, :pointer, #RFC_TYPE_DESC_HANDLE
|
211
|
+
:defaultValue, [:char, (30+1)*B_SIZE], #RFC_PARAMETER_DEFVALUE
|
212
|
+
:parameterText, [:char, (79+1)*B_SIZE], #RFC_PARAMETER_TEXT
|
213
|
+
:optional, :uchar, #RFC_BYTE
|
214
|
+
:extendedDescription, :pointer
|
215
|
+
end
|
216
|
+
|
217
|
+
class RFCFieldDesc < FFI::Struct
|
218
|
+
layout :name, [:char, (30+1)*B_SIZE],
|
219
|
+
:type, :int, #enum RFCTYPE
|
220
|
+
:nucLength, :uint,
|
221
|
+
:nucOffset, :uint,
|
222
|
+
:ucLength, :uint,
|
223
|
+
:ucOffset, :uint,
|
224
|
+
:decimals, :uint,
|
225
|
+
:typeDescHandle, :pointer, #RFC_TYPE_DESC_HANDLE
|
226
|
+
:extendedDescription, :pointer
|
227
|
+
end
|
228
|
+
|
229
|
+
class RFCDataContainer < FFI::Struct
|
230
|
+
layout :handle, :pointer
|
231
|
+
end
|
232
|
+
|
233
|
+
# typedef :RFCDataContainer, RFCStructureHandle
|
234
|
+
# typedef :RFCDataContainer, RFCTableHandle
|
235
|
+
|
236
|
+
class RFC_FUNCTION_DESC_HANDLE < FFI::Struct
|
237
|
+
layout :handle, :pointer
|
238
|
+
end
|
239
|
+
|
240
|
+
class RFC_TYPE_DESC_HANDLE < FFI::Struct
|
241
|
+
layout :handle, :pointer
|
242
|
+
end
|
243
|
+
|
244
|
+
class DATA_CONTAINER_HANDLE < FFI::Struct
|
245
|
+
layout :handle, :pointer
|
246
|
+
end
|
247
|
+
|
248
|
+
#---
|
249
|
+
# attach_function :init, :RfcInit, [], :void
|
250
|
+
# # Connection handling:
|
251
|
+
# attach_function :open_connection, :RfcOpenConnection,
|
252
|
+
# [:pointer, :uint, :pointer], :pointer
|
253
|
+
# attach_function :close_connection, :RfcCloseConnection,
|
254
|
+
# [:pointer, :pointer], :void #(handle, error)
|
255
|
+
# attach_function :get_connection_attributes, :RfcGetConnectionAttributes,
|
256
|
+
# [:pointer, :pointer, :pointer], :void #(conn_handle, conninfo, error)
|
257
|
+
# # Function Handling & Calling
|
258
|
+
# attach_function :get_function_desc, :RfcGetFunctionDesc,
|
259
|
+
# [:pointer, :pointer, :pointer], :pointer #(conn_handle, func_name, error)
|
260
|
+
# attach_function :create_function, :RfcCreateFunction,
|
261
|
+
# [:pointer, :pointer], :pointer #(fd_handle, error), :func_handle
|
262
|
+
# attach_function :invoke, :RfcInvoke,
|
263
|
+
# [:pointer, :pointer, :pointer], :int #(conn_handle, func_handle, error), RC
|
264
|
+
# #TODO: Do we want to include RfcDestroyFunction for releasing its memory?
|
265
|
+
# attach_function :get_param_count, :RfcGetParameterCount,
|
266
|
+
# [:pointer, :pointer, :pointer], :void #(fd_handle, uint, error)
|
267
|
+
# attach_function :get_parameter_desc_by_index, :RfcGetParameterDescByIndex,
|
268
|
+
# [:pointer, :uint, :pointer, :pointer], :void #(fd_handle, idx, param, error)
|
269
|
+
# # Field Handling
|
270
|
+
# # RFC_RC RfcGetChars(handle, name, buffer, length, error)
|
271
|
+
# attach_function :get_chars, :RfcGetChars,
|
272
|
+
# [:pointer, :pointer, :pointer, :uint, :pointer], :RFC_RC
|
273
|
+
# # RFC_RC RfcGetChars(handle, name, buffer, length, error)
|
274
|
+
# attach_function :get_num, :RfcGetNum,
|
275
|
+
# [:pointer, :pointer, :pointer, :uint, :pointer], :RFC_RC
|
276
|
+
# # RFC_RC RfcGetDate
|
277
|
+
# attach_function :get_date, :RfcGetDate,
|
278
|
+
# [:pointer, :pointer, [:char, 8], :pointer], :RFC_RC
|
279
|
+
# # RFC_RC RfcGetDate
|
280
|
+
# attach_function :get_time, :RfcGetTime,
|
281
|
+
# [:pointer, :pointer, [:char, 6], :pointer], :RFC_RC
|
282
|
+
# # RFC_RC RfcGetString
|
283
|
+
# # attach_function :get_string, :RfcGetString,
|
284
|
+
# # [:pointer, :pointer, :pointer], :RFC_RC
|
285
|
+
# # RFC RfcGetBytes
|
286
|
+
# attach_function :get_bytes, :RfcGetBytes,
|
287
|
+
# [:pointer, :pointer, :pointer, :uint, :pointer], :RFC_RC
|
288
|
+
# # RFC_RC RfcGetXString
|
289
|
+
# attach_function :get_xstring, :RfcGetXString,
|
290
|
+
# [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :RFC_RC
|
291
|
+
# # RFC_RC RfcGetStringLength(dataHandle, name, *length, error)
|
292
|
+
# attach_function :get_string_length, :RfcGetStringLength,
|
293
|
+
# [:pointer, :pointer, :pointer, :pointer], :int
|
294
|
+
# # void RfcSetChars(dataHandle, name, value, length, error)
|
295
|
+
# attach_function :set_chars, :RfcSetChars,
|
296
|
+
# [:pointer, :pointer, :pointer, :uint, :pointer], :void
|
297
|
+
#+++
|
298
|
+
|
299
|
+
#############################################################################################################
|
300
|
+
# ATTACH FUNCTIONS
|
301
|
+
#############################################################################################################
|
302
|
+
[
|
303
|
+
[:add_exception, :RfcAddException, [:pointer, :pointer, :pointer], :int],
|
304
|
+
[:add_function_desc, :RfcAddFunctionDesc, [:pointer, :pointer, :pointer], :int],
|
305
|
+
[:add_parameter, :RfcAddParameter, [:pointer, :pointer, :pointer], :int],
|
306
|
+
[:add_type_desc, :RfcAddTypeDesc, [:pointer, :pointer, :pointer], :int],
|
307
|
+
[:add_type_field, :RfcAddTypeField, [:pointer, :pointer, :pointer], :int],
|
308
|
+
[:append_new_row, :RfcAppendNewRow, [:pointer, :pointer], :pointer],
|
309
|
+
[:append_row, :RfcAppendRow, [:pointer, :pointer, :pointer], :int],
|
310
|
+
[:clone_structure, :RfcCloneStructure, [:pointer, :pointer], :pointer],
|
311
|
+
[:clone_table, :RfcCloneTable, [:pointer, :pointer], :pointer],
|
312
|
+
[:close_connection, :RfcCloseConnection, [:pointer, :pointer], :int],
|
313
|
+
[:confirm_transaction, :RfcConfirmTransaction, [:pointer, :pointer], :int],
|
314
|
+
[:create_function, :RfcCreateFunction, [:pointer, :pointer], :pointer],
|
315
|
+
[:create_function_desc, :RfcCreateFunctionDesc, [:pointer, :pointer], :pointer],
|
316
|
+
[:create_structure, :RfcCreateStructure, [:pointer, :pointer], :pointer],
|
317
|
+
[:create_table, :RfcCreateTable, [:pointer, :pointer], :pointer],
|
318
|
+
[:create_transaction, :RfcCreateTransaction, [:pointer, :pointer, :pointer, :pointer], :pointer],
|
319
|
+
[:create_type_desc, :RfcCreateTypeDesc, [:pointer, :pointer], :pointer],
|
320
|
+
[:delete_all_rows, :RfcDeleteAllRows, [:pointer, :pointer], :int],
|
321
|
+
[:delete_current_row, :RfcDeleteCurrentRow, [:pointer, :pointer], :int],
|
322
|
+
[:describe_function, :RfcDescribeFunction, [:pointer, :pointer], :pointer],
|
323
|
+
[:describe_type, :RfcDescribeType, [:pointer, :pointer], :pointer],
|
324
|
+
[:destroy_function, :RfcDestroyFunction, [:pointer, :pointer], :int],
|
325
|
+
[:destroy_function_desc, :RfcDestroyFunctionDesc, [:pointer, :pointer], :int],
|
326
|
+
[:destroy_structure, :RfcDestroyStructure, [:pointer, :pointer], :int],
|
327
|
+
[:destroy_table, :RfcDestroyTable, [:pointer, :pointer], :int],
|
328
|
+
[:destroy_transaction, :RfcDestroyTransaction, [:pointer, :pointer], :int],
|
329
|
+
[:destroy_type_desc, :RfcDestroyTypeDesc, [:pointer, :pointer], :int],
|
330
|
+
[:enable_basxml, :RfcEnableBASXML, [:pointer, :pointer], :int],
|
331
|
+
[:get_bytes, :RfcGetBytes, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
332
|
+
[:get_cached_function_desc, :RfcGetCachedFunctionDesc, [:pointer, :pointer, :pointer], :pointer],
|
333
|
+
[:get_cached_type_desc, :RfcGetCachedTypeDesc, [:pointer, :pointer, :pointer], :pointer],
|
334
|
+
[:get_chars, :RfcGetChars, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
335
|
+
[:get_connection_attributes, :RfcGetConnectionAttributes, [:pointer, :pointer, :pointer], :int],
|
336
|
+
[:get_current_row, :RfcGetCurrentRow, [:pointer, :pointer], :pointer],
|
337
|
+
[:get_date, :RfcGetDate, [:pointer, :pointer, :pointer, :pointer], :int],
|
338
|
+
[:get_dec_f16, :RfcGetDecF16, [:pointer, :pointer, :pointer, :pointer], :int],
|
339
|
+
[:get_dec_f34, :RfcGetDecF34, [:pointer, :pointer, :pointer, :pointer], :int],
|
340
|
+
[:get_direction_as_string, :RfcGetDirectionAsString, [:pointer], :pointer],
|
341
|
+
[:get_exception_count, :RfcGetExceptionCount, [:pointer, :pointer, :pointer], :int],
|
342
|
+
[:get_exception_desc_by_index, :RfcGetExceptionDescByIndex, [:pointer, :uint, :pointer, :pointer], :int],
|
343
|
+
[:get_exception_desc_by_name, :RfcGetExceptionDescByName, [:pointer, :pointer, :pointer, :pointer], :int],
|
344
|
+
[:get_field_count, :RfcGetFieldCount, [:pointer, :pointer, :pointer], :int],
|
345
|
+
[:get_field_desc_by_index, :RfcGetFieldDescByIndex, [:pointer, :uint, :pointer, :pointer], :int],
|
346
|
+
[:get_field_desc_by_name, :RfcGetFieldDescByName, [:pointer, :pointer, :pointer, :pointer], :int],
|
347
|
+
[:get_float, :RfcGetFloat, [:pointer, :pointer, :pointer, :pointer], :int],
|
348
|
+
[:get_function_desc, :RfcGetFunctionDesc, [:pointer, :pointer, :pointer], :pointer],
|
349
|
+
[:get_function_name, :RfcGetFunctionName, [:pointer, :pointer, :pointer], :int],
|
350
|
+
[:get_int, :RfcGetInt, [:pointer, :pointer, :pointer, :pointer], :int],
|
351
|
+
[:get_int1, :RfcGetInt1, [:pointer, :pointer, :pointer, :pointer], :int],
|
352
|
+
[:get_int2, :RfcGetInt2, [:pointer, :pointer, :pointer, :pointer], :int],
|
353
|
+
[:get_num, :RfcGetNum, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
354
|
+
[:get_parameter_count, :RfcGetParameterCount, [:pointer, :pointer, :pointer], :int],
|
355
|
+
[:get_parameter_desc_by_index, :RfcGetParameterDescByIndex, [:pointer, :uint, :pointer, :pointer], :int],
|
356
|
+
[:get_parameter_desc_by_name, :RfcGetParameterDescByName, [:pointer, :pointer, :pointer, :pointer], :int],
|
357
|
+
[:get_partner_snc_key, :RfcGetPartnerSNCKey, [:pointer, :pointer, :pointer, :pointer], :int],
|
358
|
+
[:get_partner_snc_name, :RfcGetPartnerSNCName, [:pointer, :pointer, :uint, :pointer], :int],
|
359
|
+
[:get_partner_sso_ticket, :RfcGetPartnerSSOTicket, [:pointer, :pointer, :pointer, :pointer], :int],
|
360
|
+
[:get_rc_as_string, :RfcGetRcAsString, [:pointer], :pointer],
|
361
|
+
[:get_row_count, :RfcGetRowCount, [:pointer, :pointer, :pointer], :int],
|
362
|
+
[:get_string, :RfcGetString, [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :int],
|
363
|
+
[:get_string_length, :RfcGetStringLength, [:pointer, :pointer, :pointer, :pointer], :int],
|
364
|
+
[:get_structure, :RfcGetStructure, [:pointer, :pointer, :pointer, :pointer], :int],
|
365
|
+
[:get_table, :RfcGetTable, [:pointer, :pointer, :pointer, :pointer], :int],
|
366
|
+
[:get_time, :RfcGetTime, [:pointer, :pointer, :pointer, :pointer], :int],
|
367
|
+
[:get_transaction_id, :RfcGetTransactionID, [:pointer, :pointer, :pointer], :int],
|
368
|
+
[:get_type_as_string, :RfcGetTypeAsString, [:pointer], :pointer],
|
369
|
+
[:get_type_desc, :RfcGetTypeDesc, [:pointer, :pointer, :pointer], :pointer],
|
370
|
+
[:get_type_length, :RfcGetTypeLength, [:pointer, :pointer, :pointer, :pointer], :int],
|
371
|
+
[:get_type_name, :RfcGetTypeName, [:pointer, :pointer, :pointer], :int],
|
372
|
+
[:get_version, :RfcGetVersion, [:pointer, :pointer, :pointer], :pointer],
|
373
|
+
[:get_x_string, :RfcGetXString, [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :int],
|
374
|
+
[:init, :RfcInit, [:pointer], :int],
|
375
|
+
[:insert_new_row, :RfcInsertNewRow, [:pointer, :pointer], :pointer],
|
376
|
+
[:insert_row, :RfcInsertRow, [:pointer, :pointer, :pointer], :int],
|
377
|
+
[:install_generic_server_function, :RfcInstallGenericServerFunction, [:pointer, :pointer, :pointer], :int],
|
378
|
+
[:install_server_function, :RfcInstallServerFunction, [:pointer, :pointer, :pointer, :pointer], :int],
|
379
|
+
[:install_transaction_handlers, :RfcInstallTransactionHandlers, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int],
|
380
|
+
[:invoke, :RfcInvoke, [:pointer, :pointer, :pointer], :int],
|
381
|
+
[:invoke_in_transaction, :RfcInvokeInTransaction, [:pointer, :pointer, :pointer], :int],
|
382
|
+
[:is_basxml_supported, :RfcIsBASXMLSupported, [:pointer, :pointer, :pointer], :int],
|
383
|
+
#[:is_connection_handle_valid, :RfcIsConnectionHandleValid, [:pointer, :pointer, :pointer], :int],
|
384
|
+
[:is_parameter_active, :RfcIsParameterActive, [:pointer, :pointer, :pointer, :pointer], :int],
|
385
|
+
[:listen_and_dispatch, :RfcListenAndDispatch, [:pointer, :int, :pointer], :int],
|
386
|
+
[:move_to, :RfcMoveTo, [:pointer, :uint, :pointer], :int],
|
387
|
+
[:move_to_first_row, :RfcMoveToFirstRow, [:pointer, :pointer], :int],
|
388
|
+
[:move_to_last_row, :RfcMoveToLastRow, [:pointer, :pointer], :int],
|
389
|
+
[:move_to_next_row, :RfcMoveToNextRow, [:pointer, :pointer], :int],
|
390
|
+
[:move_to_previous_row, :RfcMoveToPreviousRow, [:pointer, :pointer], :int],
|
391
|
+
[:open_connection, :RfcOpenConnection, [:pointer, :uint, :pointer], :pointer],
|
392
|
+
[:ping, :RfcPing, [:pointer, :pointer], :int],
|
393
|
+
[:register_server, :RfcRegisterServer, [:pointer, :uint, :pointer], :pointer],
|
394
|
+
[:reload_ini_file, :RfcReloadIniFile, [:pointer], :int],
|
395
|
+
# [:remove_function_desc, :RfcRemoveFunctionDesc, [:pointer, :pointer, :pointer], :int],
|
396
|
+
# [:remove_type_desc, :RfcRemoveTypeDesc, [:pointer, :pointer, :pointer], :int],
|
397
|
+
[:reset_server_context, :RfcResetServerContext, [:pointer, :pointer], :int],
|
398
|
+
[:sapuc_to_utf8, :RfcSAPUCToUTF8, [:pointer, :uint, :pointer, :pointer, :pointer, :pointer], :int],
|
399
|
+
[:set_bytes, :RfcSetBytes, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
400
|
+
[:set_chars, :RfcSetChars, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
401
|
+
[:set_date, :RfcSetDate, [:pointer, :pointer, :pointer, :pointer], :int],
|
402
|
+
[:set_dec_f16, :RfcSetDecF16, [:pointer, :pointer, :pointer, :pointer], :int],
|
403
|
+
[:set_dec_f34, :RfcSetDecF34, [:pointer, :pointer, :pointer, :pointer], :int],
|
404
|
+
[:set_float, :RfcSetFloat, [:pointer, :pointer, :double, :pointer], :int],
|
405
|
+
[:set_ini_path, :RfcSetIniPath, [:pointer, :pointer], :int],
|
406
|
+
[:set_int, :RfcSetInt, [:pointer, :pointer, :long, :pointer], :int],
|
407
|
+
[:set_int1, :RfcSetInt1, [:pointer, :pointer, :uint8, :pointer], :int],
|
408
|
+
[:set_int2, :RfcSetInt2, [:pointer, :pointer, :short, :pointer], :int],
|
409
|
+
[:set_num, :RfcSetNum, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
410
|
+
[:set_parameter_active, :RfcSetParameterActive, [:pointer, :pointer, :int, :pointer], :int],
|
411
|
+
[:set_string, :RfcSetString, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
412
|
+
[:set_structure, :RfcSetStructure, [:pointer, :pointer, :pointer, :pointer], :int],
|
413
|
+
[:set_table, :RfcSetTable, [:pointer, :pointer, :pointer, :pointer], :int],
|
414
|
+
[:set_time, :RfcSetTime, [:pointer, :pointer, :pointer, :pointer], :int],
|
415
|
+
#[:set_trace_dir, :RfcSetTraceDir, [:pointer, :pointer], :int],
|
416
|
+
#[:set_trace_encoding, :RfcSetTraceEncoding, [:pointer, :pointer], :int],
|
417
|
+
#[:set_trace_level, :RfcSetTraceLevel, [:pointer, :pointer, :uint, :pointer], :int],
|
418
|
+
[:set_type_length, :RfcSetTypeLength, [:pointer, :uint, :uint, :pointer], :int],
|
419
|
+
[:set_x_string, :RfcSetXString, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
|
420
|
+
[:snc_key_to_name, :RfcSNCKeyToName, [:pointer, :pointer, :uint, :pointer, :uint, :pointer], :int],
|
421
|
+
[:snc_name_to_key, :RfcSNCNameToKey, [:pointer, :pointer, :pointer, :pointer, :pointer], :int],
|
422
|
+
[:start_server, :RfcStartServer, [:int, :pointer, :pointer, :uint, :pointer], :pointer],
|
423
|
+
[:submit_transaction, :RfcSubmitTransaction, [:pointer, :pointer], :int],
|
424
|
+
[:utf8_to_sapuc, :RfcUTF8ToSAPUC, [:pointer, :uint, :pointer, :pointer, :pointer, :pointer], :int]
|
425
|
+
].each{|funcsig|
|
426
|
+
# puts funcsig.to_s
|
427
|
+
attach_function(funcsig[0], funcsig[1], funcsig[2], funcsig[3])
|
428
|
+
}
|
429
|
+
|
430
|
+
# Take Hash of connection parameters and returns FFI pointer to an array
|
431
|
+
# for passing to connection
|
432
|
+
def NWRFCLib.make_conn_params(params) #https://github.com/ffi/ffi/wiki/Structs
|
433
|
+
par = FFI::MemoryPointer.new(RFCConnParam, params.length)
|
434
|
+
pars = params.length.times.collect do |i|
|
435
|
+
RFCConnParam.new(par + i * RFCConnParam.size)
|
436
|
+
end
|
437
|
+
#TODO Optimize this method
|
438
|
+
tpar = params.to_a
|
439
|
+
params.length.times do |n|
|
440
|
+
# str = (tpar[n][0].to_s + "\0").encode("UTF-16LE")
|
441
|
+
pars[n][:name] = FFI::MemoryPointer.from_string(tpar[n][0].to_s.cU)
|
442
|
+
# str = (tpar[n][1].to_s + "\0").encode("UTF-16LE")
|
443
|
+
# str = str.encode("UTF-16LE")
|
444
|
+
pars[n][:value] = FFI::MemoryPointer.from_string(tpar[n][1].to_s.cU)
|
445
|
+
end
|
446
|
+
par
|
447
|
+
end
|
448
|
+
|
449
|
+
end
|