Module: RdlLibrary

Extended by:
Fiddle::Importer
Defined in:
lib/majorsilence_reporting/report_native.rb

Overview

Ruby Fiddle wrapper for the rdlnative shared library.

Loads the Majorsilence Reporting engine in-process via Fiddle — no subprocess is spawned, no .NET runtime is required on the host.

Platform-specific library filenames:

Linux:   librdlnative.so
macOS:   librdlnative.dylib
Windows: rdlnative.dll

Usage:

require 'majorsilence_reporting/report_native'

lib = RdlLibrary.load('/path/to/librdlnative.so')

rpt = ReportNative.new(lib, '/path/to/report.rdl')
rpt.set_parameter('Country', 'Germany')
rpt.set_connection_string('Data Source=myserver.db')

# Export to a file
rpt.export('pdf', '/tmp/output.pdf')

# Export to bytes
data = rpt.export_to_memory('pdf')

Supported export types: "pdf", "csv", "xlsx", "xlsx_table", "xml", "rtf", "tif", "tifb", "html", "mht"

Class Method Summary collapse

Class Method Details

.load(lib_path) ⇒ Object

Load the rdlnative shared library and initialize the engine. Returns a Hash of bound Fiddle::Function objects. Call this once per process before creating any ReportNative instances.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/majorsilence_reporting/report_native.rb', line 41

def self.load(lib_path)
  lib_path = File.expand_path(lib_path)
  lib_dir  = File.dirname(lib_path)

  # Tell the C# resolver where to find P/Invoke sibling libraries (libSkiaSharp.so,
  # libe_sqlite3.so, etc.) — must be set before rdl_init() is called.
  ENV['RDLNATIVE_LIB_DIR'] = lib_dir

  # Pre-load all shared libraries in the directory with RTLD_GLOBAL (Fiddle's
  # default).  On .NET 10+, libSystem.Native.so and sibling P/Invoke targets are
  # shared libraries — they must be globally visible before rdlnative.so runs.
  ext = RUBY_PLATFORM =~ /darwin/ ? '*.dylib' : '*.so'
  Dir.glob(File.join(lib_dir, ext)).sort.each do |f|
    begin Fiddle.dlopen(f) rescue Fiddle::DLError; end
  end

  handle = Fiddle.dlopen(lib_path)

  fns = {
    rdl_init: Fiddle::Function.new(
      handle['rdl_init'], [], Fiddle::TYPE_INT
    ),
    rdl_report_open: Fiddle::Function.new(
      handle['rdl_report_open'],
      [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
      Fiddle::TYPE_VOIDP
    ),
    rdl_report_set_param: Fiddle::Function.new(
      handle['rdl_report_set_param'],
      [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
      Fiddle::TYPE_INT
    ),
    rdl_dataset_set_field: Fiddle::Function.new(
      handle['rdl_dataset_set_field'],
      [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
      Fiddle::TYPE_INT
    ),
    rdl_dataset_commit_row: Fiddle::Function.new(
      handle['rdl_dataset_commit_row'],
      [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
      Fiddle::TYPE_INT
    ),
    rdl_report_render_file: Fiddle::Function.new(
      handle['rdl_report_render_file'],
      [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
      Fiddle::TYPE_INT
    ),
    rdl_free: Fiddle::Function.new(
      handle['rdl_free'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOID
    ),
    rdl_report_close: Fiddle::Function.new(
      handle['rdl_report_close'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOID
    ),
    rdl_last_error: Fiddle::Function.new(
      handle['rdl_last_error'], [], Fiddle::TYPE_VOIDP
    ),
  }

  ret = fns[:rdl_init].call
  raise "rdl_init failed: #{rdl_last_error_str(fns)}" unless ret.zero?

  fns
end

.rdl_last_error_str(fns) ⇒ Object



105
106
107
108
109
110
# File 'lib/majorsilence_reporting/report_native.rb', line 105

def self.rdl_last_error_str(fns)
  ptr = fns[:rdl_last_error].call
  return 'unknown error' if ptr.nil? || ptr.zero?

  Fiddle::Pointer.new(ptr).to_s
end