Pelles C forum
C language => Tips & tricks => Topic started by: Vortex on September 14, 2004, 11:31:10 AM
-
Hi friends,
Here (http://board.win32asmcommunity.net/viewtopic.php?p=149703#149703), you can find a tiny C run-time startup module with asm command line parser for various C/C++ compilers ( including Pelle's compiler )
Pelle, could you add the attachment feature to the forum?
Thanks,
Vortex
-
Vortex: where is crtdll.lib ? :D
-
Hi TBD,
Yes, you are right. Here is the solution:
Build.bat
call povars32.bat
polib /machine:ix86 /out:crtdll.lib /def:crtdll.def
\pellesc\bin\pocc /Zx /Ze /Zl /Os Test.c
\pellesc\bin\polink /SUBSYSTEM:CONSOLE /OUT:Test.exe ..\startc.obj Test.obj ..\ParseCmdLine.obj kernel32.lib crtdll.lib
crtdll.def
LIBRARY crtdll
EXPORTS
printf
...which normally is enough for this small example.
If you would like to get the zip file,y ou can send me a PM with your e.mail address.
-
thanks Vortex.
I created the lib myself using podump.exe /exports, removing the extra, adding LIBRARY crtdll, EXPORTS.
-
Here is the attachment.
-
Here is the startup module for GUI applications.
The code in C:
#include <windows.h>
extern UINT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
HMODULE hInstance;
void WINAPI WinMainCRTStartup()
{
hInstance=GetModuleHandle(NULL);
ExitProcess(WinMain(hInstance,NULL,GetCommandLine(),SW_SHOWDEFAULT));
}
The equivalent code in asm with some manual optimizations, wcrt0.asm :
[cpu 486]
[global _WinMainCRTStartup]
[section .text]
[function _WinMainCRTStartup]
_WinMainCRTStartup:
push dword (0)
call dword [(__imp__GetModuleHandleA@4)]
mov dword [(_hInstance)],eax
call dword [(__imp__GetCommandLineA@0)]
push dword 10
push dword eax
push dword (0)
push dword [(_hInstance)]
call _WinMain@16
push dword eax
call dword [(__imp__ExitProcess@4)]
..?X_WinMainCRTStartup:
[section .bss]
[global _hInstance]
[common _hInstance 4]
[extern _WinMain@16]
[extern __imp__GetCommandLineA@0]
[extern __imp__GetModuleHandleA@4]
[extern __imp__ExitProcess@4]
No need to use an external assembler to generate the object code.
An example of building a GUI based application:
call "povars32.bat"
pocc wcrt0.asm
pocc /Ze /Zl /Os Window.c
polink /SUBSYSTEM:WINDOWS /OUT:Window.exe wcrt0.obj Window.obj kernel32.lib user32.lib
The attachment contains a demo using this tiny C run-time startup code, the size of the final executable - a simple window is only 2048 bytes.
Click here (http://www.geocities.com/wortex00/Wcrt0_2.zip) to download the attachment.
-
Bug fixed : The lpCmdLine parameter should point the first command line parameter not the filename.
[cpu 486]
[global _WinMainCRTStartup]
[section .text]
[function _WinMainCRTStartup]
_WinMainCRTStartup:
push dword (0)
call dword [(__imp__GetModuleHandleA@4)]
mov dword [(_hInstance)],eax
call dword [(__imp__GetCommandLineA@0)]
dec eax
@100:
inc eax
mov cl,byte [eax]
or cl,cl
jz @102
cmp cl,32
jne @100
dec eax
@101:
inc eax
mov cl,byte [eax]
cmp cl,32
je @101
@102:
push dword 10
push dword eax
push dword (0)
push dword [(_hInstance)]
call _WinMain@16
push dword eax
call dword [(__imp__ExitProcess@4)]
..?X_WinMainCRTStartup:
[section .bss]
[global _hInstance]
[common _hInstance 4]
[extern _WinMain@16]
[extern __imp__GetCommandLineA@0]
[extern __imp__GetModuleHandleA@4]
[extern __imp__ExitProcess@4]
New attachment uploaded at the top.
-
Nice work vortex :).
I am not quite sure, but I think that code might fail if the filename or path at the start of the string returned by GetCommandLine contains spaces?
-
Hi Jibz,
GetCommandLine removes those leading spaces, so there is no problem.
-
What I meant was that if the filename of the executable itself contains spaces, then GetCommandLine will return something like:
"C:\Foo\With Space.exe" arg1 arg2
where the filename with path is quoted because it contains a space.
Try in your example to show the contents of lpCmdLine in a messagebox, and then rename the executable to something with a space.
-
Hi Jibz,
Thanks for pointing me the right direction.
Here is the code:
[cpu 486]
[global _WinMainCRTStartup]
[section .text]
[function _WinMainCRTStartup]
_WinMainCRTStartup:
push dword (0)
call dword [(__imp__GetModuleHandleA@4)]
mov dword [(_hInstance)],eax
call dword [(__imp__GetCommandLineA@0)]
cmp byte [eax],34 ;check for leading quote
jne @102
@100: ;look for the second quote
inc eax
mov cl,byte [eax]
or cl,cl
jz @104
cmp cl,34
jne @100
jmp @103 ;look for space chars
@101:
inc eax
@102: ;skip file name
mov cl,byte [eax]
or cl,cl
jz @104
cmp cl,32
jne @101
dec eax
@103: ;skip space chars
inc eax
mov cl,byte [eax]
cmp cl,32
je @103
@104:
push dword 10
push dword eax
push dword (0)
push dword [(_hInstance)]
call _WinMain@16
push dword eax
call dword [(__imp__ExitProcess@4)]
..?X_WinMainCRTStartup:
[section .bss]
[global _hInstance]
[common _hInstance 4]
[extern _WinMain@16]
[extern __imp__GetCommandLineA@0]
[extern __imp__GetModuleHandleA@4]
[extern __imp__ExitProcess@4]
-
Project file for WCRT0:
#
# PROJECT FILE generated by "Pelles C for Windows, version 2.80".
# NOTE! Manual changes of this file is done at your own risk.
#
POC_PROJECT_VERSION = 1.00#
POC_PROJECT_TYPE = 2#
POC_PROJECT_PATH = .#
POC_PROJECT_ARGUMENTS = #
POC_PROJECT_WORKPATH = #
POC_PROJECT_EXECUTOR = #
CC = pocc.exe#
AS = pocc.exe#
AR = polib.exe#
CCFLAGS = #
ASFLAGS = #
ARFLAGS = #
.SILENT:
#
# Build WCRT0.LIB.
#
"$(POC_PROJECT_PATH)\WCRT0.LIB": \
"$(POC_PROJECT_PATH)\output\wcrt0.OBJ"
$(AR) $(ARFLAGS) -out:"$@" $**
#
# Build wcrt0.OBJ.
#
"$(POC_PROJECT_PATH)\output\wcrt0.OBJ": \
"$(POC_PROJECT_PATH)\wcrt0.asm"
$(AS) $(ASFLAGS) -Fo"$@" "$!"
Then you can use it in source file with
#pragma nodefaultlib
#pragma comment(lib, "wcrt0.lib")
-
Hi timovjl,
That's nice, I will try it. :)
-
Here is another example using Pelle's C run-time DLL pocrt.dll
#define WIN32_LEAN_AND_MEAN
#define IDC_EDIT 4001
#include <stdio.h>
#include <windows.h>
HINSTANCE hInstance;
FILE *file;
char buffer[75];
char k;
char i=0;
BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
EndDialog(hwnd,0);
break;
case WM_INITDIALOG:
file=fopen("Text.txt","r");
while ( k=fgetc(file)) {
if (k==EOF) {
buffer[i]=0;
break;
}
if (k==10) {
buffer[i]=13;
++i;
}
buffer[i]=k;
++i;
}
fclose(file);
SetDlgItemText(hwnd,(int)IDC_EDIT,buffer);
break;
default:
return FALSE;
}
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
LPCTSTR DlgName="MyDialog";
hInstance=GetModuleHandle(0);
return(DialogBoxParam(hInstance,DlgName,0,DlgProc,0));
}
[/code]
-
Hi friends,
Here is the latest release of my C startup code very easy to use, now this time the sample projects both GUI and console are supported with ppj files. The startup codes are assembler with Masm.
-
Hi Vortex,
Very nice additions :)
This can be eventually added to the PellesC distro ?
It can be interesting to have several ways of making Executables :)
BTW, do you have the equivalent tiny CRTs for a DLL and a Static LIB please ?
Thanks again for this wonderful job !
Hi friends,
Here is the latest release of my C startup code very easy to use, now this time the sample projects both GUI and console are supported with ppj files. The startup codes are assembler with Masm.
-
Hi Gerome,
Thanks for your kind words. The linker extracts and links only the necessary member functions from static libraries, these ones doesn't require any startup code.
I will post an example for DLLs.
-
Hi Gerome,
The tricks to create small DLLs are again avoiding using static C run-time libraries, plus setting the entry point of the DLL to:
DllMain@12
The project I posted is an example of an autotyper. The application launches notepad.exe and characters of a message starts to appear one by one on the notepad! :)
The autotyping function is called from a DLL sized only 3072 bytes.
-
Hi friends,
Here is another C run-time startup module coded with GoAsm
-
Here is a new version of the library coded with POASM
-
vortex, the console startup code didn't check for 'tab'.. it failed to read correct argv[] when running the program with batch file that exist tab as commandline separator.
i make fixup like this:
; POASM
.586
.model flat,c
option casemap:none
WINBASEAPI_GetCommandLineA typedef proto stdcall
externdef stdcall _imp__GetCommandLineA@0: ptr WINBASEAPI_GetCommandLineA
GetCommandLine equ <_imp__GetCommandLineA@0>
WINBASEAPI_ExitProcess typedef proto stdcall :DWORD
externdef stdcall _imp__ExitProcess@4: ptr WINBASEAPI_ExitProcess
ExitProcess equ <_imp__ExitProcess@4>
main proto c :DWORD,:VARARG
.data?
_p__args db 144 dup(?) ; 32 for argv[x8], 128 for buffer
.code
_setargv proc uses esi edi
invoke GetCommandLine
mov esi,eax
mov edx,offset _p__args
push edx
lea edi,[edx+32]
xor ecx,ecx
mov ah,32
@@:
lodsb
test al,al
jz @5
cmp al,9
jz @b
cmp al,ah
jz @b
@0:
mov [edx],edi
add edx,4
inc ecx
jmp @2
@1:
lodsb
cmp al,ah
jz @3
cmp al,9
jz @3
@2:
cmp al,34
jnz @4
xor ah,32
jmp @1
@3:
mov al,0
@4:
stosb
test al,al
jnz @1
dec esi
jmp @b
@5:
mov eax,ecx ; argc
pop ecx ; argv[1]
ret
_setargv endp
public mainCRTStartup
mainCRTStartup proc
push ebp
mov ebp,esp
invoke _setargv
invoke main,eax,ecx ; argc,argv
invoke ExitProcess,eax
mainCRTStartup endp
end
-
This version checks the TAB character.
-
New version of the tiny C run-time startup library ( Wcrt0_7.zip ) :
The NULL terminator character of the last command-line argument was not copied to the destination buffer by the module crt0cons. This bug is fixed now.
ParseCmdLineParam.zip : Command-line parser for Jwasm \ Masm \ Poasm console applications
-
Thanks Vortex.
Here is similar code converted to C :
//#define WIN32_LEAN_AND_MEAN
//#include <windows.h>
#ifndef _WINDOWS_H
void _stdcall ExitProcess(unsigned int);
char __stdcall *GetCommandLineA(void);
#define GetCommandLine GetCommandLineA
int __stdcall lstrlenA(char *);
#define lstrlen lstrlenA
int __cdecl wsprintfA(char *, char *, ...);
#define wsprintf wsprintfA
#define DWORD unsigned long
int __stdcall WriteFile(void *, char *, DWORD, DWORD*, void*);
void * __stdcall GetStdHandle(DWORD);
#define STD_OUTPUT_HANDLE -11
#endif
#pragma comment(lib, "kernel32")
#pragma comment(lib, "user32")
char szCmdLine[1024];
int ParseCmdLine(char *pCmdLine)
{
char *pPos, *pP2, cSp, cTab;
int iArgs;
pPos = GetCommandLine();
pP2 = pCmdLine;
cSp = 32;
cTab = 9;
iArgs = 0;
do { // scan commandline
if (*pPos == ' ' || *pPos == '\t') // strip whitespaces off
continue;
iArgs++;
do { // loop cmdline
if (!*pPos) {
*pP2 = *pPos; // store 0 too
break;
}
if (*pPos == cSp || *pPos == cTab) { // if not quoted it is separator
break; // end of parameter
}
if (*pPos == '"') { // quote ?
cSp ^= 32;
cTab ^= 9;
continue;
}
*pP2++ = *pPos; // store char
} while (*pPos++);
*pP2++ = 0;
} while (*pPos++);
return iArgs;
}
int __cdecl mainCRTStartup(void)
{
int nLen, nIdx, nCnt;
DWORD dwWrite;
char *pPos, szTmp[1024];
nCnt = ParseCmdLine(szCmdLine);
pPos = szCmdLine;
nIdx = 0;
do {
nLen = wsprintf(szTmp, "par %d = %s\n", nIdx++, pPos);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), szTmp, nLen, &dwWrite, 0);
pPos += lstrlen(pPos) + 1;
} while(--nCnt);
ExitProcess(0);
return 0;
}