exerb 6.0.1

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.
Files changed (179) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/ChangeLog.ja.rd +305 -0
  4. data/README.en.txt +12 -0
  5. data/README.ja.html +143 -0
  6. data/README.ja.txt +6 -0
  7. data/README.md +50 -0
  8. data/Rakefile +205 -0
  9. data/bin/exerb +185 -0
  10. data/bin/mkexy +47 -0
  11. data/doc/LGPL +513 -0
  12. data/doc/class.ja.html +92 -0
  13. data/doc/command.ja.html +109 -0
  14. data/doc/core.ja.html +72 -0
  15. data/doc/example.ja.html +89 -0
  16. data/doc/faq.ja.html +59 -0
  17. data/doc/inside.ja.rd +404 -0
  18. data/doc/license.ja.html +62 -0
  19. data/doc/logo.gif +0 -0
  20. data/doc/misc.ja.html +72 -0
  21. data/doc/navi.gif +0 -0
  22. data/doc/recipe.ja.html +317 -0
  23. data/doc/style.css +187 -0
  24. data/doc/tutorial.ja.html +182 -0
  25. data/example/Makefile +54 -0
  26. data/example/cat_n.rb +14 -0
  27. data/example/exception.rb +9 -0
  28. data/example/ext/Win32API.so +0 -0
  29. data/example/ext/swin.so +0 -0
  30. data/example/msgbox.rb +14 -0
  31. data/example/rubytk.rb +22 -0
  32. data/example/runtime.ico +0 -0
  33. data/example/runtime.rb +19 -0
  34. data/example/vr/clipboard.rb +106 -0
  35. data/example/vr/compat/rubycompat.rb +18 -0
  36. data/example/vr/compat/vrcomctl.rb +12 -0
  37. data/example/vr/compat/vrcontrol.rb +50 -0
  38. data/example/vr/compat/vrmmedia.rb +24 -0
  39. data/example/vr/contrib/inifile.rb +116 -0
  40. data/example/vr/contrib/msgboxconst.rb +55 -0
  41. data/example/vr/contrib/toolbar.rb +371 -0
  42. data/example/vr/contrib/vrctlcolor.rb +110 -0
  43. data/example/vr/contrib/vrhotkey.rb +35 -0
  44. data/example/vr/contrib/vrlistviewex.rb +71 -0
  45. data/example/vr/contrib/vrstdscrollbar.rb +414 -0
  46. data/example/vr/contrib/vrwincomponent.rb +54 -0
  47. data/example/vr/dragdropformat.rb +209 -0
  48. data/example/vr/rscutil.rb +168 -0
  49. data/example/vr/sysmod.rb +249 -0
  50. data/example/vr/vractivex.rb +56 -0
  51. data/example/vr/vrclipboard.rb +53 -0
  52. data/example/vr/vrcomctl.rb +1819 -0
  53. data/example/vr/vrcontrol.rb +1374 -0
  54. data/example/vr/vrdde.rb +623 -0
  55. data/example/vr/vrddrop.rb +190 -0
  56. data/example/vr/vrdialog.rb +406 -0
  57. data/example/vr/vrhandler.rb +195 -0
  58. data/example/vr/vrlayout.old.rb +209 -0
  59. data/example/vr/vrlayout.rb +173 -0
  60. data/example/vr/vrlayout2.rb +340 -0
  61. data/example/vr/vrmargin.rb +141 -0
  62. data/example/vr/vrmgdlayout.rb +381 -0
  63. data/example/vr/vrmmedia.rb +287 -0
  64. data/example/vr/vrolednd.rb +192 -0
  65. data/example/vr/vrowndraw.rb +108 -0
  66. data/example/vr/vrrichedit.rb +366 -0
  67. data/example/vr/vrtimer.rb +148 -0
  68. data/example/vr/vrtooltip.rb +273 -0
  69. data/example/vr/vrtray.rb +143 -0
  70. data/example/vr/vrtvitem.rb +118 -0
  71. data/example/vr/vrtwopane.rb +223 -0
  72. data/example/vr/vruby.rb +1051 -0
  73. data/example/vr/winconst.rb +158 -0
  74. data/example/vruby.rb +38 -0
  75. data/exerb.gemspec +26 -0
  76. data/extconf.rb +7 -0
  77. data/lib/exerb/archive.rb +143 -0
  78. data/lib/exerb/config.rb +51 -0
  79. data/lib/exerb/error.rb +15 -0
  80. data/lib/exerb/executable.rb +68 -0
  81. data/lib/exerb/file_table.rb +189 -0
  82. data/lib/exerb/mkexy.rb +81 -0
  83. data/lib/exerb/name_table.rb +120 -0
  84. data/lib/exerb/recipe.rb +465 -0
  85. data/lib/exerb/resource.rb +190 -0
  86. data/lib/exerb/resource/base.rb +29 -0
  87. data/lib/exerb/resource/binary.rb +31 -0
  88. data/lib/exerb/resource/dialog.rb +30 -0
  89. data/lib/exerb/resource/group_icon.rb +85 -0
  90. data/lib/exerb/resource/icon.rb +52 -0
  91. data/lib/exerb/resource/version_info.rb +155 -0
  92. data/lib/exerb/resource_library.rb +120 -0
  93. data/lib/exerb/utility.rb +95 -0
  94. data/lib/exerb/utility2.rb +122 -0
  95. data/lib/exerb/version.rb +13 -0
  96. data/lib/exerb/win32/const/resource.rb +51 -0
  97. data/lib/exerb/win32/icon_file.rb +78 -0
  98. data/lib/exerb/win32/pe_file.rb +59 -0
  99. data/lib/exerb/win32/resource_directory.rb +105 -0
  100. data/lib/exerb/win32/resource_directory_root.rb +67 -0
  101. data/lib/exerb/win32/resource_entry.rb +98 -0
  102. data/lib/exerb/win32/struct/base.rb +43 -0
  103. data/lib/exerb/win32/struct/icon_dir_entry.rb +83 -0
  104. data/lib/exerb/win32/struct/icon_header.rb +43 -0
  105. data/lib/exerb/win32/struct/icon_res_entry.rb +48 -0
  106. data/lib/exerb/win32/struct/image_dos_header.rb +73 -0
  107. data/lib/exerb/win32/struct/image_file_header.rb +47 -0
  108. data/lib/exerb/win32/struct/image_nt_headers32.rb +53 -0
  109. data/lib/exerb/win32/struct/image_optional_header32.rb +107 -0
  110. data/lib/exerb/win32/struct/image_resource_data_entry.rb +45 -0
  111. data/lib/exerb/win32/struct/image_resource_directory.rb +47 -0
  112. data/lib/exerb/win32/struct/image_resource_directory_entry.rb +72 -0
  113. data/lib/exerb/win32/struct/image_section_header.rb +53 -0
  114. data/lib/exerb/win32/struct/version_info_block.rb +75 -0
  115. data/lib/exerb/win32/struct/vs_fixed_file_info.rb +62 -0
  116. data/src/exerb/cui.c +48 -0
  117. data/src/exerb/default.rb +1 -0
  118. data/src/exerb/exerb.c +877 -0
  119. data/src/exerb/exerb.h +92 -0
  120. data/src/exerb/gui.c +176 -0
  121. data/src/exerb/module.c +138 -0
  122. data/src/exerb/module.h +7 -0
  123. data/src/exerb/patch.c +27 -0
  124. data/src/exerb/resource.h +22 -0
  125. data/src/exerb/resource.rc +121 -0
  126. data/src/exerb/ruby.ico +0 -0
  127. data/src/exerb/utility.c +263 -0
  128. data/src/exerb/utility.h +33 -0
  129. data/test/alltests.rb +16 -0
  130. data/test/test-argv.rb +26 -0
  131. data/test/test-argv/test-argv.rb +9 -0
  132. data/test/test-argv/test-argv.ret +1 -0
  133. data/test/test-dollarzero.rb +26 -0
  134. data/test/test-dollarzero/test-dollarzero.rb +10 -0
  135. data/test/test-dollarzero/test-dollarzero.ret +2 -0
  136. data/test/test-dot.rb +26 -0
  137. data/test/test-dot/dot.dot.dot.rb +9 -0
  138. data/test/test-dot/dot.dot.rb +9 -0
  139. data/test/test-dot/test-dot.rb +13 -0
  140. data/test/test-dot/test-dot.ret +5 -0
  141. data/test/test-exitcode.rb +28 -0
  142. data/test/test-exitcode/test-exitcode.rb +9 -0
  143. data/test/test-kcode.rb +43 -0
  144. data/test/test-kcode/euc.rb +10 -0
  145. data/test/test-kcode/euc.ret +2 -0
  146. data/test/test-kcode/none.rb +10 -0
  147. data/test/test-kcode/none.ret +2 -0
  148. data/test/test-kcode/sjis.rb +10 -0
  149. data/test/test-kcode/sjis.ret +2 -0
  150. data/test/test-kcode/utf8.rb +10 -0
  151. data/test/test-kcode/utf8.ret +2 -0
  152. data/test/test-loadpath.rb +24 -0
  153. data/test/test-loadpath/test-loadpath.rb +9 -0
  154. data/test/test-nest.rb +18 -0
  155. data/test/test-nest/foo.rb +1 -0
  156. data/test/test-nest/foo/bar.rb +2 -0
  157. data/test/test-nest/foo/foo.rb +1 -0
  158. data/test/test-nest/test-nest.rb +1 -0
  159. data/test/test-nest/test-nest.ret +1 -0
  160. data/test/test-preload.rb +24 -0
  161. data/test/test-preload/test-preload.rb +9 -0
  162. data/test/test-regexp.rb +26 -0
  163. data/test/test-regexp/test-regexp.rb +23 -0
  164. data/test/test-regexp/test-regexp.ret +13 -0
  165. data/test/test-require1.rb +26 -0
  166. data/test/test-require1/require1.rb +9 -0
  167. data/test/test-require1/require2.rb +9 -0
  168. data/test/test-require1/require3.rb +9 -0
  169. data/test/test-require1/require4.rb +9 -0
  170. data/test/test-require1/require5.rb +9 -0
  171. data/test/test-require1/require6.rb +9 -0
  172. data/test/test-require1/test-require1.rb +41 -0
  173. data/test/test-require1/test-require1.ret +27 -0
  174. data/test/test-socket.rb +26 -0
  175. data/test/test-socket/test-socket.rb +7 -0
  176. data/test/test-socket/test-socket.ret +1 -0
  177. data/test/testcase.rb +66 -0
  178. data/vendor/mkexports.rb +167 -0
  179. metadata +352 -0
@@ -0,0 +1,72 @@
1
+
2
+ #==============================================================================#
3
+ # $Id: image_resource_directory_entry.rb,v 1.5 2005/04/17 15:56:25 yuya Exp $
4
+ #==============================================================================#
5
+
6
+ require 'exerb/win32/struct/base'
7
+ require 'exerb/win32/const/resource'
8
+
9
+ #==============================================================================#
10
+
11
+ module Exerb
12
+ module Win32
13
+ module Struct
14
+ end # Struct
15
+ end # Win32
16
+ end # Exerb
17
+
18
+ #==============================================================================#
19
+
20
+ class Exerb::Win32::Struct::ImageResourceDirectoryEntry < Exerb::Win32::Struct::Base
21
+
22
+ FORMAT = 'LL'
23
+
24
+ def initialize
25
+ super()
26
+ @name = 0
27
+ @offset_to_data = 0
28
+ end
29
+
30
+ attr_accessor :name, :offset_to_data
31
+
32
+ def pack
33
+ return [@name, @offset_to_data].pack(FORMAT)
34
+ end
35
+
36
+ def unpack(bin)
37
+ @name, @offset_to_data = bin.unpack(FORMAT)
38
+ return self
39
+ end
40
+
41
+ def id
42
+ return @name & 0xFFFF
43
+ end
44
+
45
+ def name_is_string?
46
+ return (@name & Exerb::Win32::Const::IMAGE_RESOURCE_NAME_IS_STRING > 0 ? true : false)
47
+ end
48
+
49
+ def offset_to_string
50
+ return @name & ~Exerb::Win32::Const::IMAGE_RESOURCE_NAME_IS_STRING
51
+ end
52
+
53
+ def offset_to_string=(value)
54
+ @name = value | Exerb::Win32::Const::IMAGE_RESOURCE_NAME_IS_STRING
55
+ end
56
+
57
+ def data_is_directory?
58
+ return (@offset_to_data & Exerb::Win32::Const::IMAGE_RESOURCE_DATA_IS_DIRECTORY > 0 ? true : false)
59
+ end
60
+
61
+ def offset_to_directory
62
+ return @offset_to_data & ~Exerb::Win32::Const::IMAGE_RESOURCE_DATA_IS_DIRECTORY
63
+ end
64
+
65
+ def offset_to_directory=(value)
66
+ @offset_to_data = value | Exerb::Win32::Const::IMAGE_RESOURCE_DATA_IS_DIRECTORY
67
+ end
68
+
69
+ end # Exerb::Win32::Struct::ImageResourceDirectoryEntry
70
+
71
+ #==============================================================================#
72
+ #==============================================================================#
@@ -0,0 +1,53 @@
1
+
2
+ #==============================================================================#
3
+ # $Id: image_section_header.rb,v 1.4 2005/04/17 15:56:25 yuya Exp $
4
+ #==============================================================================#
5
+
6
+ require 'exerb/win32/struct/base'
7
+
8
+ #==============================================================================#
9
+
10
+ module Exerb
11
+ module Win32
12
+ module Struct
13
+ end # Struct
14
+ end # Win32
15
+ end # Exerb
16
+
17
+ #==============================================================================#
18
+
19
+ class Exerb::Win32::Struct::ImageSectionHeader < Exerb::Win32::Struct::Base
20
+
21
+ FORMAT = 'Z8LLLLLLSSL'
22
+
23
+ def initialize
24
+ @name = ""
25
+ @virtual_size = 0
26
+ @virtual_address = 0
27
+ @size_of_raw_data = 0
28
+ @pointer_to_raw_data = 0
29
+ @pointer_to_relocations = 0
30
+ @pointer_to_linenumbers = 0
31
+ @number_of_relocations = 0
32
+ @number_of_linenumbers = 0
33
+ @characteristics = 0
34
+ end
35
+
36
+ attr_accessor :name, :virtual_size, :virtual_address, :size_of_raw_data, :pointer_to_raw_data, :pointer_to_relocations, :pointer_to_linenumbers, :number_of_relocations, :number_of_linenumbers, :characteristics
37
+
38
+ def pack
39
+ return [@name, @virtual_size, @virtual_address, @size_of_raw_data, @pointer_to_raw_data, @pointer_to_relocations, @pointer_to_linenumbers, @number_of_relocations, @number_of_linenumbers, @characteristics].pack(FORMAT)
40
+ end
41
+
42
+ def unpack(bin)
43
+ @name, @virtual_size, @virtual_address, @size_of_raw_data, @pointer_to_raw_data, @pointer_to_relocations, @pointer_to_linenumbers, @number_of_relocations, @number_of_linenumbers, @characteristics = bin.unpack(FORMAT)
44
+ return self
45
+ end
46
+
47
+ alias :physical_address :virtual_size
48
+ alias :physical_address= :virtual_size=
49
+
50
+ end # Exerb::Win32::Struct::ImageSectionHeader
51
+
52
+ #==============================================================================#
53
+ #==============================================================================#
@@ -0,0 +1,75 @@
1
+
2
+ #==============================================================================#
3
+ # $Id: version_info_block.rb,v 1.5 2005/04/30 15:16:04 yuya Exp $
4
+ #==============================================================================#
5
+
6
+ require 'exerb/utility'
7
+ require 'exerb/win32/struct/base'
8
+
9
+ #==============================================================================#
10
+
11
+ module Exerb
12
+ module Win32
13
+ module Struct
14
+ end # Struct
15
+ end # Win32
16
+ end # Exerb
17
+
18
+ #==============================================================================#
19
+
20
+ class Exerb::Win32::Struct::VersionInfoBlock < Exerb::Win32::Struct::Base
21
+
22
+ def initialize
23
+ @total_length = 0
24
+ @value_length = 0
25
+ @type = 0
26
+ @key = ""
27
+ @data = ""
28
+ end
29
+
30
+ attr_accessor :total_length, :value_length, :type, :key, :data
31
+
32
+ def pack
33
+ return Exerb::Utility.alignment(self.pack_header + self.pack_string, 4) + @data.to_s
34
+ end
35
+
36
+ def pack_header
37
+ return [@total_length, @value_length, @type].pack('SSS')
38
+ end
39
+
40
+ def pack_string
41
+ return @key.to_s + "\0\0"
42
+ end
43
+ protected :pack_string
44
+
45
+ def unpack
46
+ raise NotImplementedError
47
+ end
48
+
49
+ def read(io)
50
+ @total_length = io.read(2).unpack('S')[0]
51
+ @value_length = io.read(2).unpack('S')[0]
52
+ @type = io.read(2).unpack('S')[0]
53
+ @key = self.read_string(io)
54
+ @data = io.read(@value_length)
55
+
56
+ return self
57
+ end
58
+
59
+ def read_string(io)
60
+ str = ''
61
+
62
+ while (ch = io.read(2)) != "\0\0"
63
+ str << ch
64
+ end
65
+
66
+ io.seek((io.pos % 4 == 0 ? 0 : 4 - io.pos % 4), IO::SEEK_CUR)
67
+
68
+ return str
69
+ end
70
+ protected :read_string
71
+
72
+ end # Exerb::Win32::Struct::VersionInfoBlock
73
+
74
+ #==============================================================================#
75
+ #==============================================================================#
@@ -0,0 +1,62 @@
1
+
2
+ #==============================================================================#
3
+ # $Id: vs_fixed_file_info.rb,v 1.3 2005/04/17 15:56:25 yuya Exp $
4
+ #==============================================================================#
5
+
6
+ require 'exerb/win32/struct/base'
7
+
8
+ #==============================================================================#
9
+
10
+ module Exerb
11
+ module Win32
12
+ module Struct
13
+ end # Struct
14
+ end # Win32
15
+ end # Exerb
16
+
17
+ #==============================================================================#
18
+
19
+ class Exerb::Win32::Struct::VsFixedFileInfo < Exerb::Win32::Struct::Base
20
+
21
+ FORMAT = 'LLLLLLLLLLLLL'
22
+
23
+ def initialize
24
+ super()
25
+ @signature = 0
26
+ @struct_version = 0
27
+ @file_version_ms = 0
28
+ @file_version_ls = 0
29
+ @product_version_ms = 0
30
+ @product_version_ls = 0
31
+ @file_flags_mask = 0
32
+ @file_flags = 0
33
+ @file_os = 0
34
+ @file_type = 0
35
+ @file_subtype = 0
36
+ @file_date_ms = 0
37
+ @file_date_ls = 0
38
+ end
39
+
40
+ attr_accessor :signature, :struct_version, :file_version_ms, :file_version_ls, :product_version_ms, :product_version_ls, :file_flags_mask, :file_flags, :file_os, :file_type, :file_subtype, :file_date_ms, :file_date_ls
41
+
42
+ def pack
43
+ return [@signature, @struct_version, @file_version_ms, @file_version_ls, @product_version_ms, @product_version_ls, @file_flags_mask, @file_flags, @file_os, @file_type, @file_subtype, @file_date_ms, @file_date_ls].pack(FORMAT)
44
+ end
45
+
46
+ def unpack(bin)
47
+ @signature, @struct_version, @file_version_ms, @file_version_ls, @product_version_ms, @product_version_ls, @file_flags_mask, @file_flags, @file_os, @file_type, @file_subtype, @file_date_ms, @file_date_ls = bin.unpack(FORMAT)
48
+ return self
49
+ end
50
+
51
+ def file_version
52
+ return format('%x.%x.%x.%x', @file_version_ms >> 16, @file_version_ms & 0x0000FFFF, @file_version_ls >> 16, @file_version_ls & 0x0000FFFF)
53
+ end
54
+
55
+ def product_version
56
+ return format('%x.%x.%x.%x', @product_version_ms >> 16, @product_version_ms & 0x0000FFFF, @product_version_ls >> 16, @product_version_ls & 0x0000FFFF)
57
+ end
58
+
59
+ end # Exerb::Win32::Struct::VsFixedFileInfo
60
+
61
+ #==============================================================================#
62
+ #==============================================================================#
@@ -0,0 +1,48 @@
1
+ // $Id: cui.cpp,v 1.10 2005/04/18 14:40:32 yuya Exp $
2
+
3
+ #include <ruby.h>
4
+
5
+ ////////////////////////////////////////////////////////////////////////////////
6
+
7
+ int exerb_main(int argc, char** argv, void (*on_init)(VALUE, VALUE, VALUE), void (*on_fail)(VALUE)); // exerb.cpp
8
+
9
+ int main(int argc, char** argv);
10
+ static void on_fail(VALUE errinfo);
11
+
12
+ ////////////////////////////////////////////////////////////////////////////////
13
+
14
+ int
15
+ main(int argc, char** argv)
16
+ {
17
+ #ifdef _DEBUG
18
+ __asm { int 3 }
19
+ #endif
20
+ return exerb_main(argc, argv, NULL, on_fail);
21
+ }
22
+
23
+ static void
24
+ on_fail(VALUE errinfo)
25
+ {
26
+ const VALUE message = rb_funcall(errinfo, rb_intern("message"), 0);
27
+ const VALUE backtrace = rb_funcall(errinfo, rb_intern("backtrace"), 0);
28
+ const VALUE backtrace1 = rb_ary_shift(backtrace);
29
+ const VALUE backtrace2 = rb_str_concat(rb_str_new2("\tfrom "), rb_ary_join(backtrace, rb_str_new2("\n\tfrom ")));
30
+
31
+ #ifdef RUBY19
32
+ fprintf(stderr, "%s: %s (%s)\n",
33
+ rb_string_value_ptr((volatile VALUE*) &backtrace1),
34
+ rb_string_value_ptr((volatile VALUE*) &message),
35
+ rb_obj_classname(errinfo));
36
+ #else
37
+ fprintf(stderr, "%s: %s (%s)\n", STR2CSTR(backtrace1), STR2CSTR(message), rb_obj_classname(errinfo));
38
+ #endif
39
+ if ( FIX2INT(rb_funcall(backtrace, rb_intern("size"), 0)) > 0 ) {
40
+ #ifdef RUBY19
41
+ fprintf(stderr, "%s\n", rb_string_value_ptr((volatile VALUE*) &backtrace2));
42
+ #else
43
+ fprintf(stderr, "%s\n", STR2CSTR(backtrace2));
44
+ #endif
45
+ }
46
+ }
47
+
48
+ ////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1 @@
1
+ raise("please replace an archive.")
@@ -0,0 +1,877 @@
1
+ // $Id: exerb.cpp,v 1.198 2009/09/08 12:25:47 arton Exp $
2
+
3
+ #include <ruby.h>
4
+
5
+ /* Use crtdbg with Visual Studio or make it no-op */
6
+ #ifdef _MSC_VER
7
+ # include <crtdbg.h>
8
+ #else
9
+ # define _CRT_WARN
10
+ # define _RPT1(...)
11
+ # define _RPT2(...)
12
+ # define _RPT3(...)
13
+ #endif
14
+
15
+ #include "exerb.h"
16
+ #include "config.h"
17
+ #include "module.h"
18
+ #include "utility.h"
19
+ #include "resource.h"
20
+
21
+ ////////////////////////////////////////////////////////////////////////////////
22
+
23
+ typedef struct {
24
+ char *filepath;
25
+ HMODULE handle;
26
+ } LOADED_LIBRARY_ENTRY;
27
+
28
+ typedef struct {
29
+ DWORD base_of_file;
30
+ IMAGE_DOS_HEADER *dos_header;
31
+ IMAGE_NT_HEADERS *nt_headers;
32
+ IMAGE_SECTION_HEADER *section;
33
+ DWORD base_of_import_table;
34
+ DWORD delta_of_import_table;
35
+ DWORD base_of_name_pool;
36
+ DWORD size_of_name_pool;
37
+ } IMPORT_TABLE_INFO;
38
+
39
+ ////////////////////////////////////////////////////////////////////////////////
40
+
41
+ VALUE rb_mExerbRuntime = 0;
42
+ VALUE rb_eExerbRuntimeError = 0;
43
+
44
+ ARCHIVE_HEADER *g_archive_header = NULL;
45
+ NAME_TABLE_HEADER *g_name_table_header = NULL;
46
+ FILE_TABLE_HEADER *g_file_table_header = NULL;
47
+
48
+ int g_loaded_library_count = 0;
49
+ LOADED_LIBRARY_ENTRY g_loaded_library_table[32] = {0};
50
+ LOADED_LIBRARY_ENTRY g_pre_loaded_library_table[8] = {0};
51
+
52
+ int g_loaded_resource_count = 0;
53
+ HMODULE g_loaded_resource_table[4] = {0};
54
+
55
+ VALUE rb_load_path;
56
+ VALUE rb_argv0;
57
+ #ifndef RUBY19
58
+ VALUE rb_progname;
59
+ #endif
60
+
61
+ ////////////////////////////////////////////////////////////////////////////////
62
+
63
+ #ifdef RUBY19
64
+ /* miniprelude.c, prelude.c */
65
+ void Init_prelude(void);
66
+ #endif
67
+
68
+ #ifdef RUBY19_COMPILED_CODE
69
+ /* not exposed by Ruby headers (only in iseq.h), so we define it here */
70
+ VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
71
+ #endif
72
+
73
+ ////////////////////////////////////////////////////////////////////////////////
74
+
75
+ int exerb_main(int argc, char** argv, void (*on_init)(VALUE, VALUE, VALUE), void (*on_fail)(VALUE));
76
+ static VALUE exerb_main_in_protect(VALUE replace_io);
77
+ static void exerb_mapping();
78
+ static void exerb_set_script_name(char* name);
79
+ static void exerb_setup_kcode();
80
+ static void exerb_setup_resource_library();
81
+ static void exerb_execute();
82
+ static void exerb_cleanup();
83
+ static int exerb_find_ruby_pre_loaded(const VALUE filename);
84
+ static int exerb_find_file_pre_loaded(const VALUE filename, VALUE *feature, LOADED_LIBRARY_ENTRY **loaded_library_entry);
85
+ static int exerb_find_file_inside(const VALUE filename, WORD *id, VALUE *feature, VALUE *realname);
86
+ static int exerb_find_file_outside(const VALUE filename, VALUE *feature, VALUE *realname);
87
+ static VALUE exerb_load_ruby_script(const FILE_ENTRY_HEADER *file_entry);
88
+ static VALUE exerb_load_ruby_script_from_file(const char *filepath);
89
+ #ifdef RUBY19_COMPILED_CODE
90
+ static VALUE exerb_load_compiled_script(const FILE_ENTRY_HEADER *file_entry);
91
+ #endif
92
+ static void exerb_load_extension_library(const FILE_ENTRY_HEADER *file_entry);
93
+ static void exerb_load_extension_library_from_file(const char *filepath);
94
+ static HMODULE exerb_load_library(const FILE_ENTRY_HEADER *file_entry);
95
+ static HMODULE exerb_load_library_ex(const char *base_of_file, const int size_of_file, const char* filepath, int no_replace_function);
96
+ static HMODULE exerb_preload_library(const FILE_ENTRY_HEADER *file_entry);
97
+ static int exerb_replace_import_dll(const char *base_of_file);
98
+ static void exerb_replace_import_dll_name(IMPORT_TABLE_INFO *info, const char *src_name, const char* new_name);
99
+ static int exerb_get_import_table_info(const char *base_of_file, IMPORT_TABLE_INFO *info);
100
+ static IMAGE_SECTION_HEADER* exerb_get_enclosing_section_header(const IMAGE_NT_HEADERS *nt_headers, const DWORD rva);
101
+ static void exerb_call_initialize_function(const HMODULE handle, const char *filepath);
102
+ static int exerb_find_resource(const DWORD base_of_image, const int type, const int id, DWORD *base_of_item, DWORD *size_of_item);
103
+
104
+ static void exerb_replace_import_function(const HMODULE module);
105
+ static int exerb_replace_import_function_thunk(const HMODULE module, const FARPROC src_proc, const FARPROC new_proc);
106
+ static HMODULE WINAPI exerb_hook_load_library(LPCTSTR filename);
107
+ static HMODULE WINAPI exerb_hook_load_library_ex(LPCTSTR filename, HANDLE file, DWORD flags);
108
+ static HMODULE WINAPI exerb_hook_get_module_handle(LPCTSTR filename);
109
+ static FARPROC WINAPI exerb_hook_get_proc_address(HMODULE module, LPCTSTR procname);
110
+
111
+ ////////////////////////////////////////////////////////////////////////////////
112
+
113
+ int
114
+ exerb_main(int argc, char** argv, void (*on_init)(VALUE, VALUE, VALUE), void (*on_fail)(VALUE))
115
+ {
116
+ #ifdef RUBY19
117
+ ruby_sysinit(&argc, &argv);
118
+ RUBY_INIT_STACK;
119
+ ruby_init();
120
+ #else
121
+ NtInitialize(&argc, &argv);
122
+ ruby_init();
123
+ rb_ary_push(rb_load_path, rb_str_new2("."));
124
+ #endif
125
+ // argc = rb_w32_cmdvector(GetCommandLine(), &argv);
126
+ ruby_set_argv(argc - 1, argv + 1);
127
+ exerb_set_script_name((char *)"exerb");
128
+
129
+ int state = 0, result_code = 0;
130
+ rb_protect(exerb_main_in_protect, UINT2NUM((DWORD)on_init), &state);
131
+
132
+ if ( state ) {
133
+ #ifdef RUBY19
134
+ VALUE errinfo = rb_errinfo();
135
+ #else
136
+ VALUE errinfo = ruby_errinfo;
137
+ #endif
138
+ if ( rb_obj_is_kind_of(errinfo, rb_eSystemExit) ) {
139
+ result_code = FIX2INT(rb_iv_get(errinfo, "status"));
140
+ } else {
141
+ on_fail(errinfo);
142
+ result_code = 1;
143
+ }
144
+ }
145
+
146
+ ruby_finalize();
147
+ exerb_cleanup();
148
+
149
+ return result_code;
150
+ }
151
+
152
+ static VALUE
153
+ exerb_main_in_protect(VALUE on_init_proc)
154
+ {
155
+ Init_ExerbRuntime();
156
+
157
+ void (*on_init)(VALUE, VALUE, VALUE) = (void(*)(VALUE, VALUE, VALUE))NUM2UINT(on_init_proc);
158
+ if ( on_init ) on_init(rb_stdin, rb_stdout, rb_stderr);
159
+
160
+ /* Hack require */
161
+ rb_define_global_function("require", exerb_rb_f_require, 1);
162
+
163
+ exerb_mapping();
164
+ exerb_setup_kcode();
165
+ exerb_setup_resource_library();
166
+ exerb_execute();
167
+
168
+ return Qnil;
169
+ }
170
+
171
+ static void
172
+ exerb_mapping()
173
+ {
174
+ const DWORD base_of_image = (DWORD)GetModuleHandle(NULL);
175
+ DWORD base_of_archive = 0, size_of_archive = 0;
176
+ if ( !exerb_find_resource(base_of_image, RT_EXERB, ID_EXERB, &base_of_archive, &size_of_archive) ) {
177
+ rb_raise(rb_eExerbRuntimeError, "The executable hasn't an archive.");
178
+ }
179
+
180
+ g_archive_header = (ARCHIVE_HEADER*)base_of_archive;
181
+ if ( g_archive_header->signature1 != ARCHIVE_HEADER_SIGNATURE1 ||
182
+ g_archive_header->signature2 != ARCHIVE_HEADER_SIGNATURE2 ) {
183
+ rb_raise(rb_eExerbRuntimeError, "The executable has invalid signature of archive header.");
184
+ }
185
+ if ( g_archive_header->offset_of_name_table == 0 ||
186
+ g_archive_header->offset_of_file_table == 0 ) {
187
+ rb_raise(rb_eExerbRuntimeError, "The executable has invalid archive header.");
188
+ }
189
+
190
+ g_name_table_header = (NAME_TABLE_HEADER*)(base_of_archive + g_archive_header->offset_of_name_table);
191
+ g_file_table_header = (FILE_TABLE_HEADER*)(base_of_archive + g_archive_header->offset_of_file_table);
192
+
193
+ if ( g_name_table_header->signature != NAME_TABLE_HEADER_SIGNATURE ) {
194
+ rb_raise(rb_eExerbRuntimeError, "The executable has invalid signature of the name table header.");
195
+ }
196
+ if ( g_file_table_header->signature != FILE_TABLE_HEADER_SIGNATURE ) {
197
+ rb_raise(rb_eExerbRuntimeError, "The executable has invalid signature of the file table header.");
198
+ }
199
+ }
200
+
201
+ static void
202
+ exerb_set_script_name(char* name)
203
+ {
204
+ ruby_script(name);
205
+ #ifdef RUBY19
206
+ rb_argv0 = rb_str_new2(name);
207
+ #else
208
+ rb_argv0 = rb_progname;
209
+ #endif
210
+ }
211
+
212
+ static void
213
+ exerb_setup_kcode()
214
+ {
215
+ #ifndef RUBY19
216
+ switch ( g_archive_header->kcode ) {
217
+ case ARCHIVE_HEADER_OPTIONS_KCODE_NONE: rb_set_kcode("n"); break;
218
+ case ARCHIVE_HEADER_OPTIONS_KCODE_EUC: rb_set_kcode("e"); break;
219
+ case ARCHIVE_HEADER_OPTIONS_KCODE_SJIS: rb_set_kcode("s"); break;
220
+ case ARCHIVE_HEADER_OPTIONS_KCODE_UTF8: _from_filerb_set_kcode("u"); break;
221
+ }
222
+ #else
223
+ exerb_require(rb_str_new2("enc/encdb"));
224
+ exerb_require(rb_str_new2("enc/utf_16le"));
225
+ exerb_require(rb_str_new2("enc/trans/transdb"));
226
+ exerb_require(rb_str_new2("enc/trans/utf_16_32"));
227
+ exerb_require(rb_str_new2("enc/trans/single_byte"));
228
+ Init_prelude();
229
+ #endif
230
+ }
231
+
232
+ static void
233
+ exerb_setup_resource_library()
234
+ {
235
+ FILE_ENTRY_HEADER *file_entry = exerb_get_first_file_entry();
236
+
237
+ for ( int i = 0; i < g_file_table_header->number_of_headers; i++, file_entry++ ) {
238
+ if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_RESOURCE_LIBRARY ) {
239
+ if ( (unsigned int)g_loaded_resource_count > sizeof(g_loaded_resource_table) / sizeof(HMODULE) ) {
240
+ rb_raise(rb_eExerbRuntimeError, "the loaded recourse table is too big.");
241
+ }
242
+
243
+ g_loaded_resource_table[g_loaded_resource_count] = exerb_load_library(file_entry);
244
+ g_loaded_resource_count++;
245
+ }
246
+ }
247
+ }
248
+
249
+ static void
250
+ exerb_execute()
251
+ {
252
+ FILE_ENTRY_HEADER *file_entry = exerb_get_first_file_entry();
253
+
254
+ for ( int i = 0; i < g_file_table_header->number_of_headers; i++, file_entry++ ) {
255
+ if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_RUBY_SCRIPT ) {
256
+ exerb_set_script_name(exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id)));
257
+ exerb_load_ruby_script(file_entry);
258
+ return;
259
+ #ifdef RUBY19_COMPILED_CODE
260
+ } else if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_COMPILED_SCRIPT ) {
261
+ exerb_set_script_name(exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id)));
262
+ exerb_load_compiled_script(file_entry);
263
+ return;
264
+ #endif
265
+ }
266
+ }
267
+
268
+ rb_raise(rb_eExerbRuntimeError, "The startup script was not found.");
269
+ }
270
+
271
+ static void
272
+ exerb_cleanup()
273
+ {
274
+ for ( int i = g_loaded_library_count; i > 0; i-- ) {
275
+ const LOADED_LIBRARY_ENTRY *entry = &g_loaded_library_table[i - 1];
276
+ char filepath[MAX_PATH] = "";
277
+ GetModuleFileName(entry->handle, filepath, sizeof(filepath));
278
+ FreeLibrary(entry->handle);
279
+ DeleteFile(filepath);
280
+ free(entry->filepath);
281
+ }
282
+ }
283
+
284
+ VALUE
285
+ exerb_rb_f_require(VALUE obj, VALUE fname)
286
+ {
287
+ return exerb_require(fname);
288
+ }
289
+
290
+ VALUE
291
+ exerb_require(VALUE fname)
292
+ {
293
+ #ifdef RUBY19
294
+ SafeStringValue(fname);
295
+ #else
296
+ Check_SafeStr(fname);
297
+ #endif
298
+ LOADED_LIBRARY_ENTRY *loaded_library_entry = NULL;
299
+ WORD id = 0;
300
+ VALUE feature = Qnil, realname = Qnil;
301
+
302
+ if ( exerb_find_ruby_pre_loaded(fname) ) {
303
+ return Qfalse;
304
+ }
305
+
306
+ if ( exerb_find_file_pre_loaded(fname, &feature, &loaded_library_entry) ) {
307
+ rb_provide(RSTRING_PTR(feature));
308
+ exerb_call_initialize_function(loaded_library_entry->handle, loaded_library_entry->filepath);
309
+ free(loaded_library_entry->filepath);
310
+ loaded_library_entry->filepath = NULL;
311
+ loaded_library_entry->handle = NULL;
312
+ return Qtrue;
313
+ } else if ( exerb_find_file_inside(fname, &id, &feature, &realname) ) {
314
+ if ( rb_provided(RSTRING_PTR(feature)) ) return Qfalse;
315
+
316
+ FILE_ENTRY_HEADER *file_entry = exerb_find_file_entry(id);
317
+
318
+ switch ( file_entry->type_of_file ) {
319
+ case FILE_ENTRY_HEADER_TYPE_RUBY_SCRIPT:
320
+ rb_provide(RSTRING_PTR(feature));
321
+ exerb_load_ruby_script(file_entry);
322
+ return Qtrue;
323
+ #ifdef RUBY19_COMPILED_CODE
324
+ case FILE_ENTRY_HEADER_TYPE_COMPILED_SCRIPT:
325
+ rb_provide(RSTRING_PTR(feature));
326
+ exerb_load_compiled_script(file_entry);
327
+ return Qtrue;
328
+ #endif
329
+ case FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY:
330
+ rb_provide(RSTRING_PTR(feature));
331
+ exerb_load_extension_library(file_entry);
332
+ return Qtrue;
333
+ }
334
+ } else if ( exerb_find_file_outside(fname, &feature, &realname) ) {
335
+ if ( rb_provided(RSTRING_PTR(feature)) ) return Qfalse;
336
+
337
+ const char *ext = strrchr(RSTRING_PTR(feature), '.');
338
+
339
+ if ( stricmp(ext, ".rb") == 0 ) {
340
+ rb_provide(RSTRING_PTR(feature));
341
+ exerb_load_ruby_script_from_file(RSTRING_PTR(realname));
342
+ return Qtrue;
343
+ } else if ( stricmp(ext, ".so") == 0 ) {
344
+ rb_provide(RSTRING_PTR(feature));
345
+ exerb_load_extension_library_from_file(RSTRING_PTR(realname));
346
+ return Qtrue;
347
+ }
348
+ }
349
+
350
+ rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING_PTR(fname));
351
+
352
+ return Qfalse;
353
+ }
354
+
355
+ static char* EXTTBL[] = {(char *)"rb", (char *)"so", (char *)"dll" };
356
+
357
+ static int
358
+ exerb_find_ruby_pre_loaded(const VALUE filename)
359
+ {
360
+ const char* fname = RSTRING_PTR(filename);
361
+ if (strchr(fname, '.')) {
362
+ return rb_provided(fname) != Qfalse ? 1 : 0;
363
+ } else {
364
+ char* p = (char*)_alloca(strlen(fname) + 8);
365
+ for (int i = 0; (unsigned int)i < sizeof(EXTTBL)/sizeof(EXTTBL[0]); i++) {
366
+ sprintf(p, "%s.%s", fname, EXTTBL[i]);
367
+ if (rb_provided(p)) {
368
+ return 1;
369
+ }
370
+ }
371
+ }
372
+ return 0;
373
+ }
374
+
375
+ static int
376
+ exerb_find_file_pre_loaded(const VALUE filename, VALUE *feature, LOADED_LIBRARY_ENTRY **loaded_library_entry)
377
+ {
378
+ const char *fname = RSTRING_PTR(filename);
379
+
380
+ for ( int i = 0; (unsigned int)i < sizeof(g_pre_loaded_library_table) / sizeof(LOADED_LIBRARY_ENTRY); i++ ) {
381
+ const char *name = g_pre_loaded_library_table[i].filepath;
382
+ if ( !name ) continue;
383
+
384
+ if ( stricmp(name, fname) == 0 ) {
385
+ *feature = rb_str_new2(name);
386
+ *loaded_library_entry = &g_pre_loaded_library_table[i];
387
+ return 1;
388
+ } else if ( exerb_cmp_filename_with_ext(name, fname, "so") ) {
389
+ *feature = rb_str_new2(name);
390
+ *loaded_library_entry = &g_pre_loaded_library_table[i];
391
+ return 1;
392
+ } else if ( exerb_cmp_filename_with_ext(name, fname, "dll") ) {
393
+ *feature = rb_str_concat(rb_str_new2(fname), rb_str_new2(".so"));
394
+ *loaded_library_entry = &g_pre_loaded_library_table[i];
395
+ return 1;
396
+ }
397
+ }
398
+
399
+ return 0;
400
+ }
401
+
402
+ static int
403
+ exerb_find_file_inside(const VALUE filename, WORD *id, VALUE *feature, VALUE *realname)
404
+ {
405
+ #ifdef RUBY19
406
+ const char *fname = rb_string_value_ptr((volatile VALUE*) &filename);
407
+ #else
408
+ const char *fname = STR2CSTR(filename);
409
+ #endif
410
+
411
+ NAME_ENTRY_HEADER *name_entry = exerb_get_first_name_entry();
412
+
413
+ for ( int i = 0; i < g_name_table_header->number_of_headers; i++, name_entry++ ) {
414
+ const char *name = exerb_get_name_from_entry(name_entry);
415
+
416
+ if ( strcmp(name, fname) == 0 ) {
417
+ *id = name_entry->id;
418
+ *feature = rb_str_new2(name);
419
+ *realname = rb_str_new2(name);
420
+ return 1;
421
+ } else if ( exerb_cmp_filename_with_ext(name, fname, "rb") ) {
422
+ *id = name_entry->id;
423
+ *feature = rb_str_new2(name);
424
+ *realname = rb_str_new2(name);
425
+ return 1;
426
+ } else if ( exerb_cmp_filename_with_ext(name, fname, "so") ) {
427
+ *id = name_entry->id;
428
+ *feature = rb_str_new2(name);
429
+ *realname = rb_str_new2(name);
430
+ return 1;
431
+ } else if ( exerb_cmp_filename_with_ext(name, fname, "dll") ) {
432
+ FILE_ENTRY_HEADER* file_entry = exerb_find_file_entry(name_entry->id);
433
+ if (file_entry->type_of_file != FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY) continue;
434
+
435
+ *id = name_entry->id;
436
+ *feature = rb_str_concat(rb_str_new2(fname), rb_str_new2(".so"));
437
+ *realname = rb_str_new2(name);
438
+ return 1;
439
+ }
440
+ }
441
+
442
+ *id = 0;
443
+ *feature = Qnil;
444
+ *realname = Qnil;
445
+
446
+ return 0;
447
+ }
448
+
449
+ static int
450
+ exerb_find_file_outside(const VALUE filename, VALUE *feature, VALUE *realname)
451
+ {
452
+ const VALUE filename_rb = rb_str_concat(rb_str_dup(filename), rb_str_new2(".rb"));
453
+ const VALUE filename_so = rb_str_concat(rb_str_dup(filename), rb_str_new2(".so"));
454
+ const VALUE filename_dll = rb_str_concat(rb_str_dup(filename), rb_str_new2(".dll"));
455
+
456
+ if ( *realname = rb_find_file(*feature = filename) ) return 1;
457
+ if ( *realname = rb_find_file(*feature = filename_rb) ) return 1;
458
+ if ( *realname = rb_find_file(*feature = filename_so) ) return 1;
459
+ if ( *realname = rb_find_file(filename_dll) ) { *feature = filename_so; return 1; }
460
+
461
+ *feature = Qnil;
462
+ *realname = Qnil;
463
+
464
+ return 0;
465
+ }
466
+
467
+ static VALUE
468
+ exerb_load_ruby_script(const FILE_ENTRY_HEADER *file_entry)
469
+ {
470
+ ID id_eval = rb_intern("eval");
471
+ VALUE binding = rb_const_get(rb_mKernel, rb_intern("TOPLEVEL_BINDING"));
472
+ VALUE lineno = INT2FIX(1);
473
+
474
+ const VALUE code = exerb_get_file_from_entry2(file_entry);
475
+ const VALUE name = rb_str_new2(exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id)));
476
+
477
+ return rb_funcall(rb_mKernel, id_eval, 4, code, binding, name, lineno);
478
+ }
479
+
480
+ static VALUE
481
+ exerb_load_ruby_script_from_file(const char *filepath)
482
+ {
483
+ rb_load(rb_str_new2(filepath), 0);
484
+ return Qnil;
485
+ }
486
+
487
+ #ifdef RUBY19_COMPILED_CODE
488
+ static VALUE
489
+ exerb_load_compiled_script(const FILE_ENTRY_HEADER *file_entry)
490
+ {
491
+ ID id_eval = rb_intern("eval");
492
+ const VALUE code = exerb_get_file_from_entry2(file_entry);
493
+ const VALUE iseq_ary = rb_marshal_load(code);
494
+ const VALUE iseq = rb_iseq_load(iseq_ary, Qnil, Qnil);
495
+
496
+ return rb_funcall(iseq, id_eval, 0);
497
+ }
498
+ #endif
499
+
500
+ static void
501
+ exerb_load_extension_library(const FILE_ENTRY_HEADER *file_entry)
502
+ {
503
+ const HMODULE handle = exerb_load_library(file_entry);
504
+ const char *filepath = exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id));
505
+ exerb_call_initialize_function(handle, filepath);
506
+ }
507
+
508
+ static void
509
+ exerb_load_extension_library_from_file(const char *filepath)
510
+ {
511
+ const HANDLE file = exerb_fopen_for_read(filepath);
512
+ const DWORD size = exerb_fsize(file);
513
+ char *buffer = malloc(size);
514
+ exerb_fread(file, buffer, size);
515
+ exerb_fclose(file);
516
+
517
+ const HMODULE handle = exerb_load_library_ex(buffer, size, filepath, 0);
518
+ exerb_call_initialize_function(handle, filepath);
519
+
520
+ free(buffer);
521
+ }
522
+
523
+ static HMODULE
524
+ exerb_load_library(const FILE_ENTRY_HEADER *file_entry)
525
+ {
526
+ const char *base_of_file = exerb_get_file_from_entry1(file_entry);
527
+ const char *filepath = exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id));
528
+ return exerb_load_library_ex(base_of_file, file_entry->size_of_file, filepath, (int)file_entry->flag_no_replace_function);
529
+ }
530
+
531
+ static HMODULE
532
+ exerb_load_library_ex(const char *base_of_file, const int size_of_file, const char* filepath, int no_replace_function)
533
+ {
534
+ if ((unsigned int)g_loaded_library_count > sizeof(g_loaded_library_table) / sizeof(LOADED_LIBRARY_ENTRY) ) {
535
+ rb_raise(rb_eExerbRuntimeError, "the loaded library table is too big.");
536
+ }
537
+
538
+ DWORD protect = 0, dummy = 0;
539
+ VirtualProtect((void*)base_of_file, size_of_file, PAGE_READWRITE, &protect);
540
+ exerb_replace_import_dll(base_of_file);
541
+ VirtualProtect((void*)base_of_file, size_of_file, protect, &dummy);
542
+
543
+ char tmp_filepath[MAX_PATH] = "";
544
+ exerb_create_tmpfile("exerb", tmp_filepath, base_of_file, size_of_file);
545
+
546
+ const HMODULE handle = LoadLibraryEx(tmp_filepath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
547
+ if ( !handle ) {
548
+ DWORD error = GetLastError();
549
+ DeleteFile(tmp_filepath);
550
+ exerb_raise_runtime_error(error);
551
+ }
552
+
553
+ g_loaded_library_table[g_loaded_library_count].filepath = exerb_strdup(filepath);
554
+ g_loaded_library_table[g_loaded_library_count].handle = handle;
555
+ g_loaded_library_count++;
556
+
557
+ if ( !no_replace_function ) exerb_replace_import_function(handle);
558
+
559
+ return handle;
560
+ }
561
+
562
+ static HMODULE
563
+ exerb_preload_library(const FILE_ENTRY_HEADER *file_entry)
564
+ {
565
+ NAME_ENTRY_HEADER *name_entry = exerb_find_name_entry(file_entry->id);
566
+ const char *name = exerb_get_name_from_entry(name_entry);
567
+
568
+ for ( int i = 0; i < g_loaded_library_count; i++ ) {
569
+ if ( g_loaded_library_table[i].filepath && stricmp(g_loaded_library_table[i].filepath, name) == 0 ) {
570
+ return g_loaded_library_table[i].handle;
571
+ }
572
+ }
573
+
574
+ HMODULE module = exerb_load_library(file_entry);
575
+
576
+ if (file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ) {
577
+ for ( int i = 0; (unsigned int)i < sizeof(g_pre_loaded_library_table) / sizeof(LOADED_LIBRARY_ENTRY); i++ ) {
578
+ if ( !g_pre_loaded_library_table[i].handle ) {
579
+ g_pre_loaded_library_table[i].filepath = exerb_strdup(name);
580
+ g_pre_loaded_library_table[i].handle = module;
581
+ break;
582
+ }
583
+ }
584
+ }
585
+
586
+ return module;
587
+ }
588
+
589
+ static int
590
+ exerb_replace_import_dll(const char *base_of_file)
591
+ {
592
+ IMPORT_TABLE_INFO info = {0};
593
+ if ( !exerb_get_import_table_info(base_of_file, &info) ) return 0;
594
+
595
+ char self_filepath[MAX_PATH] = "";
596
+ const char *self_filename = exerb_get_self_filepath(self_filepath, sizeof(self_filepath));
597
+
598
+ exerb_replace_import_dll_name(&info, EXERB_LIBRUBY_SO, self_filename);
599
+
600
+ return 1;
601
+ }
602
+
603
+ static void
604
+ exerb_replace_import_dll_name(IMPORT_TABLE_INFO *info, const char *src_name, const char* new_name)
605
+ {
606
+ const DWORD base_of_name = info->base_of_file - info->delta_of_import_table;
607
+ const DWORD size_of_new_name = strlen(new_name);
608
+ FILE_ENTRY_HEADER *file_entry;
609
+
610
+ IMAGE_IMPORT_DESCRIPTOR *first_descriptor = (IMAGE_IMPORT_DESCRIPTOR*)(info->base_of_file + info->base_of_import_table);
611
+
612
+ for ( IMAGE_IMPORT_DESCRIPTOR *descriptor = first_descriptor; descriptor->Name; descriptor++ ) {
613
+ char *name = (char*)(base_of_name + descriptor->Name);
614
+
615
+ if ( stricmp(name, src_name) == 0 ) {
616
+ int found = 0;
617
+ for ( IMAGE_IMPORT_DESCRIPTOR *desc = first_descriptor; desc->Name; desc++ ) {
618
+ if ( strcmp((char*)(base_of_name + desc->Name), new_name) == 0 ) {
619
+ descriptor->Name = desc->Name;
620
+ found = 1;
621
+ break;
622
+ }
623
+ }
624
+ if ( found ) continue;
625
+
626
+ if ( strlen(name) >= size_of_new_name ) {
627
+ strcpy(name, new_name);
628
+ } else if ( size_of_new_name + 1 <= info->size_of_name_pool ) {
629
+ DWORD address_of_new_name = info->base_of_name_pool - (size_of_new_name + 1);
630
+
631
+ strcpy((char*)(info->base_of_file + address_of_new_name), new_name);
632
+ descriptor->Name = address_of_new_name + info->delta_of_import_table;
633
+
634
+ info->base_of_name_pool -= size_of_new_name + 1;
635
+ info->size_of_name_pool -= size_of_new_name + 1;
636
+ } else {
637
+ rb_raise(rb_eLoadError, "Couldn't modify DLL's name in the import table. The name of the executable file is too long.");
638
+ }
639
+ } else if ( file_entry = exerb_find_file_entry_by_filename(name, NULL) ) {
640
+ if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ||
641
+ file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_DYNAMIC_LIBRARY ) {
642
+ HMODULE module = exerb_preload_library(file_entry);
643
+ char filepath[MAX_PATH] = "";
644
+ const char *filename = exerb_get_module_filepath(module, filepath, sizeof(filepath));
645
+ exerb_replace_import_dll_name(info, name, filename);
646
+ }
647
+ }
648
+ }
649
+ }
650
+
651
+ static int
652
+ exerb_get_import_table_info(const char *base_of_file, IMPORT_TABLE_INFO *info)
653
+ {
654
+ info->base_of_file = (DWORD)base_of_file;
655
+ info->dos_header = (IMAGE_DOS_HEADER*)info->base_of_file;
656
+ info->nt_headers = (IMAGE_NT_HEADERS*)(info->base_of_file + info->dos_header->e_lfanew);
657
+
658
+ const DWORD rva_of_import_table = info->nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
659
+
660
+ info->section = exerb_get_enclosing_section_header(info->nt_headers, rva_of_import_table);
661
+ if ( !info->section ) return 0;
662
+
663
+ info->delta_of_import_table = info->section->VirtualAddress - info->section->PointerToRawData;
664
+ info->base_of_import_table = rva_of_import_table - info->delta_of_import_table;
665
+
666
+ if ( strnicmp((char*)info->section->Name, ".idata", 8) == 0 || // for Boland's Compiler
667
+ strnicmp((char*)info->section->Name, ".rdata", 8) == 0 ) { // for Microsoft's Compiler
668
+ info->base_of_name_pool = info->section->PointerToRawData + info->section->SizeOfRawData;
669
+ info->size_of_name_pool = info->section->SizeOfRawData - info->section->Misc.VirtualSize;
670
+ } else {
671
+ info->base_of_name_pool = 0;
672
+ info->size_of_name_pool = 0;
673
+ }
674
+
675
+ return 1;
676
+ }
677
+
678
+ static IMAGE_SECTION_HEADER*
679
+ exerb_get_enclosing_section_header(const IMAGE_NT_HEADERS *nt_headers, const DWORD rva)
680
+ {
681
+ IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(nt_headers);
682
+
683
+ for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++, section++ ) {
684
+ if ( (rva >= section->VirtualAddress) && (rva < (section->VirtualAddress + section->Misc.VirtualSize)) ) {
685
+ return section;
686
+ }
687
+ }
688
+
689
+ return NULL;
690
+ }
691
+
692
+ static void
693
+ exerb_call_initialize_function(const HMODULE handle, const char *filepath)
694
+ {
695
+ const char *filename = exerb_get_filename(filepath);
696
+ char funcname[128] = "Init_";
697
+ strncat(funcname, filename, sizeof(funcname) - strlen(funcname) - 1);
698
+
699
+ char *ext = strrchr(funcname, '.');
700
+ if ( ext && (stricmp(ext, ".so") == 0 || stricmp(ext, ".dll") == 0) ) {
701
+ *ext = '\0';
702
+ }
703
+
704
+ void (*init_proc)(void) = (void (*)(void))GetProcAddress(handle, funcname);
705
+ if ( !init_proc ) rb_raise(rb_eExerbRuntimeError, "Couldn't call the initialize function in the extension library. --- %s(%s)", filepath, funcname);
706
+
707
+ (*init_proc)();
708
+ }
709
+
710
+ static int
711
+ exerb_find_resource(const DWORD base_of_image, const int type, const int id, DWORD *base_of_item, DWORD *size_of_item)
712
+ {
713
+ const IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER*)base_of_image;
714
+ const IMAGE_NT_HEADERS *nt_headers = (IMAGE_NT_HEADERS*)(base_of_image + dos_header->e_lfanew);
715
+
716
+ const DWORD base_of_resource = base_of_image + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
717
+ if ( base_of_resource == base_of_image ) return 0;
718
+
719
+ const IMAGE_RESOURCE_DIRECTORY *root_dir = (IMAGE_RESOURCE_DIRECTORY*)base_of_resource;
720
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY *root_entries = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root_dir + 1);
721
+
722
+ for ( WORD i = 0; i < root_dir->NumberOfNamedEntries + root_dir->NumberOfIdEntries; i++ ) {
723
+ if ( !root_entries[i].NameIsString && root_entries[i].Id == type ) {
724
+ const IMAGE_RESOURCE_DIRECTORY *type_dir = (IMAGE_RESOURCE_DIRECTORY*)(base_of_resource + root_entries[i].OffsetToDirectory);
725
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY *type_entries = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(type_dir + 1);
726
+
727
+ for ( WORD j = 0; j < type_dir->NumberOfNamedEntries + type_dir->NumberOfIdEntries; j++ ) {
728
+ if ( !type_entries[j].NameIsString && type_entries[j].Id == id ) {
729
+ const IMAGE_RESOURCE_DIRECTORY *item_dir = (IMAGE_RESOURCE_DIRECTORY*)(base_of_resource + type_entries[j].OffsetToDirectory);
730
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY *item_entries = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(item_dir + 1);
731
+ const IMAGE_RESOURCE_DATA_ENTRY *data_entry = (IMAGE_RESOURCE_DATA_ENTRY*)(base_of_resource + item_entries[0].OffsetToData);
732
+
733
+ if ( base_of_item ) *base_of_item = base_of_image + data_entry->OffsetToData;
734
+ if ( size_of_item ) *size_of_item = data_entry->Size;
735
+
736
+ return 1;
737
+ }
738
+ }
739
+ }
740
+ }
741
+
742
+ return 0;
743
+ }
744
+
745
+ ////////////////////////////////////////////////////////////////////////////////
746
+ static void
747
+ exerb_replace_import_function(const HMODULE module)
748
+ {
749
+ HMODULE kernel32 = GetModuleHandle("kernel32.dll");
750
+ FARPROC load_library_proc = GetProcAddress(kernel32, "LoadLibraryA");
751
+ FARPROC load_library_ex_proc = GetProcAddress(kernel32, "LoadLibraryExA");
752
+ FARPROC get_module_handle = GetProcAddress(kernel32, "GetModuleHandleA");
753
+ FARPROC get_proc_address_proc = GetProcAddress(kernel32, "GetProcAddress");
754
+
755
+ HMODULE self = GetModuleHandle(NULL);
756
+ FARPROC rb_require_proc = GetProcAddress(self, "rb_require");
757
+
758
+ #ifdef RUBY19
759
+ FARPROC rb_require_safe_proc = GetProcAddress(self, "rb_require_safe");
760
+ #endif
761
+
762
+ exerb_replace_import_function_thunk(module, load_library_proc, (FARPROC)exerb_hook_load_library);
763
+ exerb_replace_import_function_thunk(module, load_library_ex_proc, (FARPROC)exerb_hook_load_library_ex);
764
+ exerb_replace_import_function_thunk(module, get_module_handle, (FARPROC)exerb_hook_get_module_handle);
765
+ exerb_replace_import_function_thunk(module, get_proc_address_proc, (FARPROC)exerb_hook_get_proc_address);
766
+
767
+ // replace rb_require and rb_require_safe used by extension with ours
768
+ exerb_replace_import_function_thunk(module, rb_require_proc, (FARPROC)rb_require);
769
+
770
+ #ifdef RUBY19
771
+ exerb_replace_import_function_thunk(module, rb_require_safe_proc, (FARPROC)rb_require_safe);
772
+ #endif
773
+ }
774
+
775
+ static int
776
+ exerb_replace_import_function_thunk(const HMODULE module, const FARPROC src_proc, const FARPROC new_proc)
777
+ {
778
+ const DWORD base_of_image = (DWORD)module;
779
+ const IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER*)base_of_image;
780
+ const IMAGE_NT_HEADERS *nt_headers = (IMAGE_NT_HEADERS*)(base_of_image + dos_header->e_lfanew);
781
+
782
+ const DWORD base_of_import = base_of_image + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
783
+ if ( base_of_import == base_of_image ) return 0;
784
+
785
+ for ( IMAGE_IMPORT_DESCRIPTOR *desc = (IMAGE_IMPORT_DESCRIPTOR*)base_of_import; desc->Name; desc++ ) {
786
+ for ( DWORD *thunk = (DWORD*)(base_of_image + desc->FirstThunk); *thunk; thunk++ ) {
787
+ if ( *thunk == (DWORD)src_proc ) {
788
+ DWORD protect = 0, dummy = 0;
789
+ VirtualProtect(thunk, sizeof(DWORD), PAGE_READWRITE, &protect);
790
+ *thunk = (DWORD)new_proc;
791
+ VirtualProtect(thunk, sizeof(DWORD), protect, &dummy);
792
+ return 1;
793
+ }
794
+ }
795
+ }
796
+
797
+ return 0;
798
+ }
799
+
800
+ static HMODULE WINAPI
801
+ exerb_hook_load_library(LPCTSTR filename)
802
+ {
803
+ _RPT1(_CRT_WARN, "exerb_hook_load_library('%s')\n", filename);
804
+
805
+ FILE_ENTRY_HEADER *file_entry;
806
+
807
+ if ( filename ) {
808
+ if ( stricmp(filename, EXERB_LIBRUBY_NAME) == 0 ||
809
+ stricmp(filename, EXERB_LIBRUBY_SO) == 0 ) {
810
+ return GetModuleHandle(NULL);
811
+ } else if ( file_entry = exerb_find_file_entry_by_filename(filename, "dll") ) {
812
+ if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ||
813
+ file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_DYNAMIC_LIBRARY ) {
814
+ return exerb_preload_library(file_entry);
815
+ }
816
+ }
817
+ }
818
+
819
+ return LoadLibrary(filename);
820
+ }
821
+
822
+ static HMODULE WINAPI
823
+ exerb_hook_load_library_ex(LPCTSTR filename, HANDLE file, DWORD flags)
824
+ {
825
+ _RPT3(_CRT_WARN, "exerb_hook_load_library_ex('%s', %i, %i)\n", filename, file, flags);
826
+
827
+ FILE_ENTRY_HEADER *file_entry;
828
+
829
+ if ( filename ) {
830
+ if ( stricmp(filename, EXERB_LIBRUBY_NAME) == 0 ||
831
+ stricmp(filename, EXERB_LIBRUBY_SO) == 0 ) {
832
+ return GetModuleHandle(NULL);
833
+ } else if (file_entry = exerb_find_file_entry_by_filename(filename, "dll") ) {
834
+ if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ||
835
+ file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_DYNAMIC_LIBRARY ) {
836
+ return exerb_preload_library(file_entry);
837
+ }
838
+ }
839
+ }
840
+
841
+ return LoadLibraryEx(filename, file, flags);
842
+ }
843
+
844
+ static HMODULE WINAPI
845
+ exerb_hook_get_module_handle(LPCTSTR filename)
846
+ {
847
+ _RPT1(_CRT_WARN, "exerb_hook_get_module_handle('%s')\n", filename);
848
+
849
+ if ( filename && (stricmp(filename, EXERB_LIBRUBY_NAME) == 0 ||
850
+ stricmp(filename, EXERB_LIBRUBY_SO) == 0) ) {
851
+ return GetModuleHandle(NULL);
852
+ }
853
+
854
+ return GetModuleHandle(filename);
855
+ }
856
+
857
+ static FARPROC WINAPI
858
+ exerb_hook_get_proc_address(HMODULE module, LPCTSTR procname)
859
+ {
860
+ _RPT2(_CRT_WARN, "exerb_hook_get_proc_address(0x%08X, '%s')\n", module, procname);
861
+
862
+ HMODULE kernel32 = GetModuleHandle("kernel32.dll");
863
+
864
+ // FIXME: �����ɂ��C���|�[�g�ɑΉ�����
865
+
866
+ if ( module == kernel32 ) {
867
+ if ( strcmp(procname, "LoadLibraryA") == 0 ) return (FARPROC)exerb_hook_load_library;
868
+ else if ( strcmp(procname, "LoadLibraryExA") == 0 ) return (FARPROC)exerb_hook_load_library_ex;
869
+ else if ( strcmp(procname, "GetModuleHandleA") == 0 ) return (FARPROC)exerb_hook_get_module_handle;
870
+ else if ( strcmp(procname, "GetProcAddress") == 0 ) return (FARPROC)exerb_hook_get_proc_address;
871
+ }
872
+
873
+ return GetProcAddress(module, procname);
874
+ }
875
+
876
+
877
+ ////////////////////////////////////////////////////////////////////////////////