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 include : "res.g"
17
18 define
19 {
20 LINK_GUI = 0x0001 // GUI application
21 LINK_ONE = 0x0002 // Just one copy can be run
22 LINK_SIZE = 0x0004 // Check the minimum size of exe file
23 // LINK_PACK = 0x0008 // Compress the data
24 LINK_DLL = 0x0010 // Use gentee.dll
25 LINK_CHAR = 0x0020 // Print Window characters
26
27 LINKSAVE_EXE = 0x0001 // Установить exesize
28 LINKSAVE_MIN = 0x0002 // Установить minsize
29 LINKSAVE_EXT = 0x0004 // Добавить расширенный блок
30
31 LINKFLD = $"res\linker"
32
33 // error codes
34 LERR_OPEN = 0
35 LERR_NOTLAUNCH
36 LERR_WRITE
37 LERR_TMPRES
38 LERR_ADDRES
39 LERR_COPY
40 LERR_READ
41 LERR_SECTION
42 LERR_MANIFEST
43 }
44
45 type linkhead
46 {
47 uint sign1 // 'Gentee Launcher' sign
48 uint sign2 //
49 uint sign3 //
50 uint sign4 //
51 uint exesize // Размер exe-файла.
52 // Если не 0, то файл является SFX
53 // архивом и далее идут прикрепленныe данные
54 uint minsize // Если не 0, то выдавать ошибку если размер файла
55 // меньше указанного
56 ubyte console // 1 если консольное приложение
57 ubyte exeext // Количество дополнительных блоков
58 ubyte pack // 1 если байт код и dll упакованы
59 ushort reserve // Reserve value
60 uint dllsize // Упакованный размер Dll файла.
61 // Если 0, то динамическое подключение gentee.dll
62 uint gesize // Упакованный размер байт-кода.
63 uint mutex // ID для mutex, если не 0, то будет проверка
64 uint param // Зашитый параметр
65 uint offset // Смещение данной структуры
66 reserved extsize[ 64 ] // Зарезервированно для размеров 8 ext блоков
67 // Каждый размер занимает long
68 }
69
70 type linker {
71 str input // Input GE file
72 str output // Output executable filename
73 uint flag // Flags
74 uint param // Additional parameter
75 arrstr icons // Icons <idname,iconfile>
76 arrstr temps // Temporary files <id,tempfile>
77 arrstr res // Resource files to link
78 uint errfunc // Error message function
79 }
80
81 import "\$LINKFLD\\EXELink.dll"<exe>
82 {
83 uint Add_Res_Section( uint, uint )
84 uint Add_Data_Section( uint, uint, uint )
85 uint Set_Sub_System( uint, uint )
86 uint Set_OS_Version( uint, uint )
87 }
88
89 import "kernel32.dll"
90 {
91 Sleep( uint )
92 uint GetTickCount()
93 }
94
95 method linker.error( uint code, str param )
96 {
97 // print( "Linker error: \(msgtext)\nPress any key..." )
98 // getch()
99 if .errfunc : .errfunc->func( code, param )
100 else : exit( 0 )
101 }
102
103 method linker.error( uint code )
104 {
105 this.error( code, 0->str )
106 }
107
108 method uint linker.savehead( linkhead lnkhead, uint flags )
109 {
110 // Записываем заголовок linkhead
111 file fexe
112 uint handle fsize launchoff phead
113 spattern pattern
114 buf btemp
115
116 if !fexe.open( .output, 0 ) : this.error( $LERR_OPEN, .output )
117
118 pattern.init( '\"Gentee Launcher"', 0 )
119 btemp.expand( 0x20000 )
120
121 btemp.use = fexe.read( btemp.ptr(), 0x20000 )
122
123 launchoff = pattern.search( btemp, 0 )
124 if launchoff >= *btemp : this.error( $LERR_NOTLAUNCH, .output )
125
126 phead as lnkhead
127 if !&lnkhead
128 { // Читаем структуру linkhead из файла
129 phead as ( btemp.ptr() + launchoff )->linkhead
130 }
131 phead.offset = launchoff
132 fsize = fexe.getsize()
133
134 if flags & $LINKSAVE_EXE : phead.exesize = fsize
135 if flags & $LINKSAVE_MIN : phead.minsize = fsize
136 if flags & $LINKSAVE_EXT
137 {
138 long prevsize
139 uint i ptr
140 prevsize = long( phead.exesize )
141 ptr = &phead.extsize
142
143 fornum i, phead.exeext
144 {
145 prevsize += ptr->long
146 ptr += sizeof( long )
147 }
148 phead.exeext++
149 ptr->long = long( fsize ) - prevsize
150 // print("EXt=\( lahead.exeext ) size = \( ptr->long )\n")
151 }
152 if !fexe.writepos( launchoff, &phead, sizeof( linkhead ))
153 {
154 this.error( $LERR_WRITE, .output )
155 }
156 fexe.close()
157 return fsize
158 }
159
160 method uint linker.create
161 {
162 buf ge
163 str pattern
164 linkhead lnkhead
165 str tempdir stemp
166 uint ret last
167 file exefile
168 res exeres
169
170 this.input.ffullname( this.input )
171 if !ge.read( this.input ) : this.error( $LERR_READ, this.input )
172
173 if this.flag & $LINK_DLL
174 {
175 getmodulepath( pattern, "\$LINKFLD\\launcherd.exe" )
176 }
177 else
178 {
179 getmodulepath( pattern, "\$LINKFLD\\launcher.exe" )
180 }
181 if !*this.output : .output.fsetext( .input, "exe" )
182 this.output.ffullname( this.output )
183 if !( exefile.open( this.output, $OP_EXCLUSIVE | $OP_CREATE ))
184 {
185 this.error( $LERR_OPEN, .output )
186 }
187 last = this.output[ *this.output - 1 ]
188 this.output[ *this.output - 1 ] = '_'
189 if !copyfile( pattern, .output ) : this.error( $LERR_OPEN, .output )
190
191 lnkhead.sign1 = 0x746E6547
192 lnkhead.sign2 = 0x4C206565
193 lnkhead.sign3 = 0x636E7561
194 lnkhead.sign4 = 0x00726568
195
196 if !( this.flag & $LINK_GUI )
197 {
198 lnkhead.console = $G_CONSOLE
199 Set_Sub_System( .output.ptr(), 1 )
200 }
201 if this.flag & $LINK_CHAR : lnkhead.console |= $G_CHARPRN
202 if this.flag & $LINK_ONE : lnkhead.mutex = GetTickCount()
203
204 gettempdir( tempdir )
205 ( pattern = tempdir ).faddname( "gedata" )
206 lnkhead.gesize = *ge
207
208 if !ge.write( pattern ) : this.error( $LERR_WRITE, pattern )
209 if ret = Add_Data_Section( .output.ptr(), ".gentee".ptr(), pattern.ptr())
210 {
211 this.error( $LERR_SECTION )
212 // if ret == 4 : mustunicows()
213 }
214
215 // Добавляем иконки
216 exeres.icons( this.icons )
217 exeres.temps( this.temps )
218 exeres.resfiles( this.res )
219
220 if !exeres.ismanifest && this.flag & $LINK_GUI
221 {
222 this.output.fgetparts( 0->str, stemp, 0->str )
223 if !exeres.addmanifest( stemp ) : this.error( $LERR_MANIFEST )
224 }
225 if *exeres.data > 0x20
226 {
227 stemp = "\(tempdir)\\temp.res"
228 if !exeres.write( stemp ) : this.error( $LERR_TMPRES, stemp )
229 if ret = Add_Res_Section( .output.ptr(), stemp.ptr())
230 {
231 this.error( $LERR_ADDRES, stemp )
232 // if ret == 4 : mustunicows()
233 }
234 }
235
236 ret = this.savehead( lnkhead, $LINKSAVE_EXE | ?( this.flag & $LINK_SIZE,
237 $LINKSAVE_MIN, 0 ))
238 stemp = .output
239 this.output[ *this.output - 1 ] = last
240 exefile.close()
241 deletefile( .output )
242 if !movefile( stemp, .output ) : this.error( $LERR_COPY, .output )
243 Sleep( 100 )
244
245 return 1
246 }