From: Vincent Fatica on
Thanks for the ExitProcess tip.

__stdcall/WINAPI is not mentioned in crtexe.c. Aren't they all __cdecl?

static
int
__tmainCRTStartup(
void
);

#ifdef _WINMAIN_

#ifdef WPRFLAG
int wWinMainCRTStartup(
#else /* WPRFLAG */
int WinMainCRTStartup(
#endif /* WPRFLAG */

#else /* _WINMAIN_ */

#ifdef WPRFLAG
int wmainCRTStartup(
#else /* WPRFLAG */
int mainCRTStartup(
#endif /* WPRFLAG */

#endif /* _WINMAIN_ */
void
)
{

On Tue, 8 Sep 2009 13:29:35 +0800, "xiaosi" <xiaosi(a)cn99.com> wrote:

|Besides call convention, ExitProcess should be used instead of return, because both tmainCRTStartup and tWinMainCRTStartup call
|kernel32!ExitProcess(status) after tmain or tWinMain return status.
|
|If you use Common Dialog Box in your app, and return (instead of ExitProcess) to exit app, the process will not exit (the thread of
|Common Dialog Box is still existing).
|
|#pragma comment(linker, "/subsystem:windows")
|#pragma comment(linker, "/entry:mywinmain")
|int __stdcall mywinmain() {
| ....
| ExitProcess(msg.wParam);
|}
|
|#pragma comment(linker, "/subsystem:console")
|#pragma comment(linker, "/entry:mymain")
|int __cdecl mymain() {
| ....
| ExitProcess(status);
|}
|
|"Vincent Fatica" <vince(a)blackholespam.net> wrote:
|> On Mon, 7 Sep 2009 21:44:17 +0300, "Alex Blekhman" <tkfx.REMOVE(a)yahoo.com>
|> wrote:
|>
|> |Even if you use a custom entry point it is still must conform to
|> |the expected signature of [w]WinMain or [w]main. Also, calling
|> |convention must be __stdcall for Windows subsystem and __cdecl for
|> |console subsystem.
|>
|> To avoid the RTL I often use a custom entry point and I often violate the
|> conventions you mentioned. I haven't gotten into trouble yet. Please
|> elaborate.
|> --
|> - Vince
--
- Vince
From: Vincent Fatica on
How do I ensure my app get them from ntdll.dll and not try to get them from the
CRT lib?

On Tue, 8 Sep 2009 13:32:29 +0800, "xiaosi" <xiaosi(a)cn99.com> wrote:

|One day I dumpbin /headers /exports ntdll.dll > exports_ntdll.txt, and find ntdll.dll has many "built-in" crt functions. When system
|loads an app, it always firstly maps ntdll.dll to the app's process. This means every app has these "built-in" crt functions, so why
|bother to import these functions from the crt lib (except using inline for speed). wcstoul/wcstol/strtoul/strtol are also "built-in"
|in ntdll.dll.
|
| 1180 49B 0000E5C6 _CIcos = __CIcos
| 1181 49C 0000E682 _CIlog = __CIlog
| 1182 49D 0000E002 _CIpow = __CIpow
| 1183 49E 000012D1 _CIsin = __CIsin
| 1184 49F 0000137F _CIsqrt = __CIsqrt
| 1185 4A0 0002C8A2 __isascii = ___isascii
| 1186 4A1 0006F64B __iscsym = ___iscsym
| 1187 4A2 0006F605 __iscsymf = ___iscsymf
| 1188 4A3 0006F5F3 __toascii = ___toascii
| 1189 4A4 0000143B _alldiv = __alldiv
| 1190 4A5 000014E5 _alldvrm = __alldvrm
| 1191 4A6 000015C4 _allmul = __allmul
| 1192 4A7 000015F8 _alloca_probe = __alloca_probe
| 1193 4A8 00001635 _allrem = __allrem
| 1194 4A9 000016E9 _allshl = __allshl
| 1195 4AA 00001708 _allshr = __allshr
| 1196 4AB 0006F691 _atoi64 = __atoi64
| 1197 4AC 00001729 _aulldiv = __aulldiv
| 1198 4AD 00001791 _aulldvrm = __aulldvrm
| 1199 4AE 00001826 _aullrem = __aullrem
| 1200 4AF 0000189B _aullshr = __aullshr
| 1201 4B0 000015F8 _chkstk = __alloca_probe
| 1202 4B1 0007B048 _fltused = __fltused
| 1203 4B2 000018BA _ftol = __ftol
| 1204 4B3 0006F80D _i64toa = __i64toa
| 1205 4B4 0006F92F _i64tow = __i64tow
| 1206 4B5 0002E964 _itoa = __itoa
| 1207 4B6 0002DC81 _itow = __itow
| 1208 4B7 0006F989 _lfind = __lfind
| 1209 4B8 0006F74E _ltoa = __ltoa
| 1210 4B9 0006F867 _ltow = __ltow
| 1211 4BA 000018E1 _memccpy = __memccpy
| 1212 4BB 0006F9C2 _memicmp = __memicmp
| 1213 4BC 0006F9D2 _snprintf = __snprintf
| 1214 4BD 0001BBCA _snwprintf = __snwprintf
| 1215 4BE 0006FA30 _splitpath = __splitpath
| 1216 4BF 00012E44 _strcmpi = __stricmp
| 1217 4C0 00012E44 _stricmp = __stricmp
| 1218 4C1 0006FB78 _strlwr = __strlwr
| 1219 4C2 0001987D _strnicmp = __strnicmp
| 1220 4C3 0006FBA5 _strupr = __strupr
| 1221 4C4 0006FBD2 _tolower = __tolower
| 1222 4C5 0006FC1F _toupper = __toupper
| 1223 4C6 0006F845 _ui64toa = __ui64toa
| 1224 4C7 0006F967 _ui64tow = __ui64tow
| 1225 4C8 0006F77A _ultoa = __ultoa
| 1226 4C9 0006F893 _ultow = __ultow
| 1227 4CA 0002FB67 _vsnprintf = __vsnprintf
| 1228 4CB 0006FC31 _vsnwprintf = __vsnwprintf
| 1229 4CC 00013358 _wcsicmp = __wcsicmp
| 1230 4CD 00024849 _wcslwr = __wcslwr
| 1231 4CE 000181CD _wcsnicmp = __wcsnicmp
| 1232 4CF 0006FCA7 _wcsupr = __wcsupr
| 1233 4D0 0006FCDD _wtoi = __wtoi
| 1234 4D1 0006FCED _wtoi64 = __wtoi64
| 1235 4D2 0003684A _wtol = __wtol
| 1236 4D3 0006FD8A abs = _labs
| 1237 4D4 00001934 atan = _atan
| 1238 4D5 00024889 atoi = _atoi
| 1239 4D6 00024896 atol = _atol
| 1240 4D7 000151D3 bsearch = _bsearch
| 1241 4D8 000019D7 ceil = _ceil
| 1242 4D9 0000E5DA cos = _cos
| 1243 4DA 0006FD9F fabs = _fabs
| 1244 4DB 00001B18 floor = _floor
| 1245 4DC 0006F518 isalnum = _isalnum
| 1246 4DD 0006F3DC isalpha = _isalpha
| 1247 4DE 0006F5C0 iscntrl = _iscntrl
| 1248 4DF 0002C879 isdigit = _isdigit
| 1249 4E0 0006F588 isgraph = _isgraph
| 1250 4E1 0006F447 islower = _islower
| 1251 4E2 0006F550 isprint = _isprint
| 1252 4E3 0006F4E5 ispunct = _ispunct
| 1253 4E4 0006F4B2 isspace = _isspace
| 1254 4E5 0006F414 isupper = _isupper
| 1255 4E6 0006FE57 iswalpha = _iswalpha
| 1256 4E7 000269D1 iswctype = _iswctype
| 1257 4E8 00026A75 iswdigit = _iswdigit
| 1258 4E9 0006FE72 iswlower = _iswlower
| 1259 4EA 0006FEA5 iswspace = _iswspace
| 1260 4EB 0006FE8A iswxdigit = _iswxdigit
| 1261 4EC 0006F47A isxdigit = _isxdigit
| 1262 4ED 0006FD8A labs = _labs
| 1263 4EE 0000E67E log = _log
| 1264 4EF 0002490C mbstowcs = _mbstowcs
| 1265 4F0 00001C60 memchr = _memchr
| 1266 4F1 00001D07 memcmp = _memcmp
| 1267 4F2 00001DB3 memcpy = _memcpy
| 1268 4F3 000020F5 memmove = _memmove
| 1269 4F4 00002435 memset = _memset
| 1270 4F5 0000DFFD pow = _pow
| 1271 4F6 000203B8 qsort = _qsort
| 1272 4F7 000012E5 sin = _sin
| 1273 4F8 00025BA4 sprintf = _sprintf
| 1274 4F9 00001393 sqrt = _sqrt
| 1275 4FA 0006FEBD sscanf = _sscanf
| 1276 4FB 0000249D strcat = _strcat
| 1277 4FC 0000E7ED strchr = _strchr
| 1278 4FD 00002583 strcmp = _strcmp
| 1279 4FE 0000248D strcpy = _strcpy
| 1280 4FF 00002608 strcspn = _strcspn
| 1281 500 00002645 strlen = _strlen
| 1282 501 000026C0 strncat = _strncat
| 1283 502 000027E5 strncmp = _strncmp
| 1284 503 0000281D strncpy = _strncpy
| 1285 504 0000291D strpbrk = _strpbrk
| 1286 505 00002956 strrchr = _strrchr
| 1287 506 0000297D strspn = _strspn
| 1288 507 0000E75E strstr = _strstr
| 1289 508 000700B2 strtol = _strtol
| 1290 509 000700D1 strtoul = _strtoul
| 1291 50A 000184BB swprintf = _swprintf
| 1292 50B 000029CE tan = _tan
| 1293 50C 0006FBE4 tolower = _tolower
| 1294 50D 00023D13 toupper = _toupper
| 1295 50E 0002A826 towlower = _towlower
| 1296 50F 000700F0 towupper = _towupper
| 1297 510 00020304 vDbgPrintEx = _vDbgPrintEx(a)16
| 1298 511 0001EA5B vDbgPrintExWithPrefix = _vDbgPrintExWithPrefix(a)20
| 1299 512 00070104 vsprintf = _vsprintf
| 1300 513 00018112 wcscat = _wcscat
| 1301 514 00014962 wcschr = _wcschr
| 1302 515 00035424 wcscmp = _wcscmp
| 1303 516 00012F40 wcscpy = _wcscpy
| 1304 517 000356EE wcscspn = _wcscspn
| 1305 518 0000FE2A wcslen = _wcslen
| 1306 519 00018B24 wcsncat = _wcsncat
| 1307 51A 0001E40F wcsncmp = _wcsncmp
| 1308 51B 0001055F wcsncpy = _wcsncpy
| 1309 51C 00070162 wcspbrk = _wcspbrk
| 1310 51D 00014671 wcsrchr = _wcsrchr
| 1311 51E 000701AB wcsspn = _wcsspn
| 1312 51F 0002380F wcsstr = _wcsstr
| 1313 520 00029F03 wcstol = _wcstol
| 1314 521 000701F9 wcstombs = _wcstombs
| 1315 522 00034D91 wcstoul = _wcstoul
|
|"Vincent Fatica" <vince(a)blackholespam.net> wrote:
|> Thanks for that. After grep-ing through an archive of projects for "BOOL
|> bInQuotes" I'm embarrassed to admit how many times I have done something
|> similar. :-)
|>
|> Have you got any other tips on avoiding the RTL?
|>
|> wsprintf() is invaluable as are the lstr* functions (now I've learned that some
|> of the wcs* functions have intrinsic/inline versions).
|>
|> I have often wanted something to turn a string into a number. If I insist on
|> avoiding the RTL, I use StrToIntEx and feel a bit guilty dragging in shlwapi.dll
|> for only that reason.
|> --
|> - Vince
--
- Vince
From: Alex Blekhman on
"Vincent Fatica" wrote:
> If you look at the CRT startup routines (the typical entry
> points, crtexe.c) for EXEs, you see that they are __cdecl,
> taking, no args and returning an int. They examine a command
> line, do their thing, and eventually call main, wmain, or
> WinMain. So the signatures of main, wmain, and WinMain are very
> important. But if you're not using the CRT startup routines and
> you are specifying an entry point, it would seem that int
> __cdecl ...(void) is appropriate.

I found the requirements here:

"/ENTRY (Entry-Point Symbol)"
http://msdn.microsoft.com/en-us/library/f9t8842e.aspx

<quote>
The function must be defined with the __stdcall calling
convention. The parameters and return value must be defined as
documented in the Win32 API for WinMain (for an .exe file) or
DllEntryPoint (for a DLL).
</quote>

However, after reading your answer I looked into crtexe.c file I
discovered that CRT startup routines don't respect this
requirement, exactly as you noticed. Moreover, BaseProcessStart
routine from kernel32.dll doesn't care neither about parameters
nor calling convention. The call looks like this:

call dword ptr [ebp+8]
push eax
call _ExitThread@4

Where "dword ptr [ebp+8]" is the address of the process entry
point. The process entry point address is passed as a parameter to
BaseProcessStart, as well.

So, actually the linker documentation is incorrect and one must
use int __cdecl(*)(void) function as a custom entry point. It is
only by sheer luck BaseProcessStart and subsequent code don't
change anything on stack, so there is no access violation
exception.

I would be very interested in hearing from MSFT people about the
issue.

Alex


From: Alex Blekhman on
"xiaosi" wrote:
> Besides call convention, ExitProcess should be used instead of
> return, because both tmainCRTStartup and tWinMainCRTStartup call
> kernel32!ExitProcess(status) after tmain or tWinMain return
> status.

This is incorrect. tmainCRTStartup and tWinMainCRTStartup call
ExitProcess only if there is an exception thrown from
main/WinMain. Otherwise, both CRT startup routines just return.
kernel32!BaseProcessStart routine calls ExitThread, which in its
turn calls ExitProcess.

Alex


From: Alex Blekhman on
"Vincent Fatica" wrote:
> How do I ensure my app get them from ntdll.dll and not try to
> get them from the CRT lib?

You can re-create an import lib for ntdll.dll and link with it:

KB131313 - "How To Create 32-bit Import Libraries Without .OBJs or
Source"
http://support.microsoft.com/kb/131313

HTH
Alex