1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2007, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * ID: linker 15.08.07 0.0.A.
11 *
12 * Author: Alexey Krivonogov ( gentee )
13 *
14 ******************************************************************************/
15
16 define
17 {
18 LINK_GUI = 0x0001 // GUI application
19 LINK_ONE = 0x0002 // Just one copy can be run
20 LINK_SIZE = 0x0004 // Check the minimum size of exe file
21 LINK_PACK = 0x0008 // Compress the byte-code & DLL
22 LINK_DLL = 0x0010 // Use gentee.dll
23 LINK_CHAR = 0x0020 // Print Window characters
24 LINK_ASM = 0x0040 // The bytecode can have ASM commands
25 LINK_ASMRT = 0x0080 // Run-time converting the bytecode to ASM commands
26 LINK_TMPRAND = 0x0100 // Random temporary folder
27 // res.flags
28 RES_ACCESS = 0x1000 // Manifest uiAccess = true
29 RES_ADMIN = 0x2000 // Manifest level = requireAdministrator
30
31 LINKSAVE_EXE = 0x0001 // Установить exesize
32 LINKSAVE_MIN = 0x0002 // Установить minsize
33 LINKSAVE_EXT = 0x0004 // Добавить расширенный блок
34
35 LINKFLD = $"res\linker"
36
37 // error codes
38 LERR_OPEN = 0
39 LERR_NOTLAUNCH
40 LERR_WRITE
41 LERR_TMPRES
42 LERR_ADDRES
43 LERR_COPY
44 LERR_READ
45 LERR_SECTION
46 LERR_MANIFEST
47 RERR_LOADICON
48 RERR_PACK
49 LNFY_ADDTEMP = 255
50 }
51
52 type linker {
53 str input // Input GE file
54 str output // Output executable filename
55 uint flag // Flags
56 uint param // Additional parameter
57 arrstr icons // Icons <idname,iconfile>
58 arrstr temps // Temporary files <id,tempfile>
59 arrstr res // Resource files to link
60 str geatemp // Ready temporary GEA file
61 uint errfunc // Error message function
62 uint geafunc // GEA message function
63 uint nfyfunc // Linker notify function
64 }
65
66 method linker.nfy( uint code, str param )
67 {
68 if .nfyfunc : .nfyfunc->func( code, param )
69 }
70
71 include
72 {
73 $"..\gea\gea.g"
74 "res.g"
75 }
76
77 type linkhead
78 {
79 uint sign1 // 'Gentee Launcher' sign
80 uint sign2 //
81 uint sign3 //
82 uint sign4 //
83 uint exesize // Размер exe-файла.
84 // Если не 0, то файл является SFX
85 // архивом и далее идут прикрепленныe данные
86 uint minsize // Если не 0, то выдавать ошибку если размер файла
87 // меньше указанного
88 ubyte console // 1 если консольное приложение
89 ubyte exeext // Количество дополнительных блоков
90 ubyte pack // 1 если байт код и dll упакованы
91 ushort flags // flags
92 uint dllsize // Упакованный размер Dll файла.
93 // Если 0, то динамическое подключение gentee.dll
94 uint gesize // Упакованный размер байт-кода.
95 uint mutex // ID для mutex, если не 0, то будет проверка
96 uint param // Зашитый параметр
97 uint offset // Смещение данной структуры
98 reserved extsize[ 64 ] // Зарезервированно для размеров 8 ext блоков
99 // Каждый размер занимает long
100 }
101
102 import "\$LINKFLD\\EXELink.dll"<exe>
103 {
104 uint Add_Res_Section( uint, uint )
105 uint Add_Data_Section( uint, uint, uint )
106 uint Set_Sub_System( uint, uint )
107 uint Set_OS_Version( uint, uint )
108 }
109
110 import "kernel32.dll"
111 {
112 Sleep( uint )
113 uint GetTickCount()
114 }
115
116 method linker.error( uint code, str param )
117 {
118 // print( "Linker error: \(msgtext)\nPress any key..." )
119 // getch()
120 if .errfunc : .errfunc->func( code, param )
121 else : exit( 0 )
122 }
123
124 method linker.error( uint code )
125 {
126 this.error( code, 0->str )
127 }
128
129 method uint linker.savehead( linkhead lnkhead, uint flags )
130 {
131 // Записываем заголовок linkhead
132 file fexe
133 uint handle fsize launchoff phead
134 spattern pattern
135 buf btemp
136
137 if !fexe.open( .output, 0 ) : this.error( $LERR_OPEN, .output )
138
139 pattern.init( '\"Gentee Launcher"', 0 )
140 btemp.expand( 0x20000 )
141
142 btemp.use = fexe.read( btemp.ptr(), 0x20000 )
143
144 launchoff = pattern.search( btemp, 0 )
145 if launchoff >= *btemp : this.error( $LERR_NOTLAUNCH, .output )
146
147 phead as lnkhead
148 if !&lnkhead
149 { // Читаем структуру linkhead из файла
150 phead as ( btemp.ptr() + launchoff )->linkhead
151 }
152 phead.offset = launchoff
153 fsize = fexe.getsize()
154
155 if flags & $LINKSAVE_EXE : phead.exesize = fsize
156 if flags & $LINKSAVE_MIN : phead.minsize = fsize
157 if flags & $LINKSAVE_EXT
158 {
159 long prevsize
160 uint i ptr
161 prevsize = long( phead.exesize )
162 ptr = &phead.extsize
163
164 fornum i, phead.exeext
165 {
166 prevsize += ptr->long
167 ptr += sizeof( long )
168 }
169 phead.exeext++
170 ptr->long = long( fsize ) - prevsize
171 // print("EXt=\( phead.exeext ) size = \( ptr->long ) exe=\(phead.exesize)\n")
172 }
173 if !fexe.writepos( launchoff, &phead, sizeof( linkhead ))
174 {
175 this.error( $LERR_WRITE, .output )
176 }
177 fexe.close()
178 return fsize
179 }
180
181 // gentee !!!
182 /*method uint buf.readappend( str filename )
183 {
184 file f
185 uint rd
186
187 if f.open( filename, $OP_READONLY )
188 {
189 uint size = f.getsize()
190 .expand( size + 128 ) // резервируем для возможного str
191 rd = f.read( this.data + this.use, size )
192 this.use += rd
193 f.close( )
194 }
195 return rd
196 }
197 */
198
199 method uint linker.create
200 {
201 buf ge
202 str pattern
203 linkhead lnkhead
204 str tempdir stemp launcher
205 uint ret last
206 file exefile
207 res exeres
208
209 this.input.ffullname( this.input )
210 if this.flag & $LINK_PACK
211 {
212 buf in
213 lzge lz
214
215 ge.expand( 4200000 )
216 getmodulepath( pattern, "\$LINKFLD\\genteert.bin" )
217 if !ge.read( pattern ) : this.error( $LERR_READ, pattern )
218 lnkhead.dllsize = *ge
219 lnkhead.pack = 1
220 this.flag &= ~( $LINK_ASMRT | $LINK_ASM | $LINK_DLL )
221
222 in.read( this.input )
223 lz.order = 10
224 ge.use += lzge_encode( in.ptr(), *in, ge.ptr() + lnkhead.dllsize + 4, lz ) + 4
225 ( ge.ptr() + lnkhead.dllsize )->uint = *in
226 // print("Exe=\(lnkhead.dllsize) \( *in) => \(ge.use - lnkhead.dllsize)\n")
227 }
228 elif !ge.read( this.input ) : this.error( $LERR_READ, this.input )
229
230 if this.flag & $LINK_DLL
231 {
232 if this.flag & $LINK_ASMRT : launcher = "launcherda"
233 else : launcher = "launcherd"
234 }
235 else
236 {
237 if this.flag & $LINK_ASMRT : launcher = "launcherart"
238 elif this.flag & $LINK_ASM : launcher = "launchera"
239 elif this.flag & $LINK_PACK : launcher = "minilauncher"
240 else : launcher = "launcher"
241 }
242 getmodulepath( pattern, "\$LINKFLD\\\(launcher).exe" )
243 if !*this.output : .output.fsetext( .input, "exe" )
244 this.output.ffullname( this.output )
245 if !( exefile.open( this.output, $OP_EXCLUSIVE | $OP_CREATE ))
246 {
247 this.error( $LERR_OPEN, .output )
248 }
249 last = this.output[ *this.output - 1 ]
250 this.output[ *this.output - 1 ] = '_'
251 if !copyfile( pattern, .output ) : this.error( $LERR_OPEN, .output )
252
253 lnkhead.sign1 = 0x746E6547
254 lnkhead.sign2 = 0x4C206565
255 lnkhead.sign3 = 0x636E7561
256 lnkhead.sign4 = 0x00726568
257
258 if !( this.flag & $LINK_GUI )
259 {
260 lnkhead.console = $G_CONSOLE
261 Set_Sub_System( .output.ptr(), 1 )
262 }
263 lnkhead.flags = 0
264 if this.flag & $LINK_CHAR : lnkhead.console |= $G_CHARPRN
265 if this.flag & $LINK_ONE : lnkhead.mutex = GetTickCount()
266 if this.flag & $LINK_TMPRAND : lnkhead.flags = $G_TMPRAND
267
268 gettempdir( tempdir )
269 ( pattern = tempdir ).faddname( "gedata" )
270 lnkhead.gesize = *ge - lnkhead.dllsize
271
272 if !ge.write( pattern ) : this.error( $LERR_WRITE, pattern )
273 if ret = Add_Data_Section( .output.ptr(), ".gentee".ptr(), pattern.ptr())
274 {
275 this.error( $LERR_SECTION )
276 // if ret == 4 : mustunicows()
277 }
278
279 exeres.owner = &this
280 // Добавляем иконки
281 exeres.icons( this.icons )
282 exeres.temps( this.temps, this.geatemp )
283 exeres.resfiles( this.res )
284
285 if !exeres.ismanifest && this.flag & $LINK_GUI
286 {
287 this.output.fgetparts( 0->str, stemp, 0->str )
288 exeres.flags |= this.flag & 0xF000
289 if !exeres.addmanifest( stemp ) : this.error( $LERR_MANIFEST )
290 }
291 if *exeres.data > 0x20
292 {
293 stemp = "\(tempdir)\\temp.res"
294 if !exeres.write( stemp ) : this.error( $LERR_TMPRES, stemp )
295 if ret = Add_Res_Section( .output.ptr(), stemp.ptr())
296 {
297 this.error( $LERR_ADDRES, stemp )
298 // if ret == 4 : mustunicows()
299 }
300 }
301
302 ret = this.savehead( lnkhead, $LINKSAVE_EXE | ?( this.flag & $LINK_SIZE,
303 $LINKSAVE_MIN, 0 ))
304 stemp = .output
305 this.output[ *this.output - 1 ] = last
306 exefile.close()
307 deletefile( .output )
308 if !movefile( stemp, .output ) : this.error( $LERR_COPY, .output )
309 Sleep( 100 )
310
311 return 1
312 }
313