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/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