nwrfc 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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