exerb 6.0.1

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