As far as I have got from my C readings, many things I would like my pgms to perform
are not possible or very complicated with C ANSI Libs.
For example, I want to set up a standard win32 console with DOS characteristics: fixed size (80 x 25),
colors, direct positioning of output on it (rows and cols), validated input key after key, and so on.
What I have to do is just using some win32 APIs for everything, so the C language is a good
way for calling Windows API that were written with a C in their mind. :P
This means a simple program like
#include <stdio.h>
int main(void)
{
printf("Let's do something\n");
return 0;
}
is going to take some 30-40 lines to be properly accomplished
with fixed size console, colors, positioning on the screen and so on.
The good news is: when I've done it, I can use the same function from
then forward, and the next time it'll take considerable less time and
effort to do something similar. :lol
What's your C experts opininion?
This should be the code for buiding a win32 console fixed size:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
HANDLE wHnd; // Handle to write to the console.
HANDLE rHnd; // Handle to read from the console.
int main(int argc, char *argv[])
{
// Set up the handles for reading/writing:
wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
rHnd = GetStdHandle(STD_INPUT_HANDLE);
// Change the window title:
SetConsoleTitle("Win32 Console 80 x 25 Fixed Size");
// Set up the required window size:
SMALL_RECT windowSize = {0, 0, 79, 24};
// Change the console window size:
SetConsoleWindowInfo(wHnd, TRUE, &windowSize);
// Create a COORD to hold the buffer size:
COORD bufferSize = {80, 25};
// Change the internal buffer size:
SetConsoleScreenBufferSize(wHnd, bufferSize);
getchar();
return 0;
}
How do I compile it with Pelle's C? It gives a lot of errors when I try. ::)
Thanks
Frank
Project -> Project Options -> Compiler -> check the "Enable Microsoft extensions"
Quote from: TmX on June 03, 2010, 01:11:49 PM
Project -> Project Options -> Compiler -> check the "Enable Microsoft extensions"
Thanks TmX. Now It works :U
I can go on adding the more needed APIs :P
Frank
A couple of APIs later:
// ---------------------------------------------------------------------------------------------------------------
// Playing with Win32 Console.
// We first allocate a fixed size DOS style 80 x 25 Console, then we select colors
// and print some text into it at a specified location (cols, rows)
// ---------------------------------------------------------------------------------------------------------------
// To select the colors of the console we first use the system() call to the
// command "color" passing it the combination background/foreground color
// according to the following table:
// ---------- Italian Consoles :-) --------------------
// 0 = Nero
// 1 = Blu scuro
// 2 = Verde
// 3 = Verde acqua
// 4 = Bordeaux
// 5 = Viola
// 6 = Verde oliva
// 7 = Grigio chiaro
// 8 = Grigio
// 9 = Blu
// A = Verde limone
// B = Azzurro
// C = Rosso
// D = Fucsia
// E = Giallo
// F = Bianco
//---------- English Consoles :-) --------------------
// 0 = Black 8 = Gray
// 1 = Blue 9 = Light Blue
// 2 = Green a = Light Green
// 3 = Aqua b = Light Aqua
// 4 = Red c = Light Red
// 5 = Purple d = Light Purple
// 6 = Yellow e = Light Yellow
// 7 = White f = Bright White
// ---------------------------------------------------------------------------------------------------------------
// Afterwhile, we'll use the Windows APIs to perform the same operation.
// Once the colors have been set, we position the cursor at the centre of
// the screen and display the famous sentence "Let's do something".
//----------------------------------------------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
HANDLE wHnd; // Handle to write to the console.
HANDLE rHnd; // Handle to read from the console.
void Console80x25(void);
void DisplayAt(int x, int y, char *StringBuffer, int len);
int main(int argc, char *argv[])
{
Console80x25();
system("color 1e");
DisplayAt(32, 12, "Let\'s do something\n", 19);
getchar();
return 0;
}
void Console80x25()
{
// Set up the handles for reading/writing:
wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
rHnd = GetStdHandle(STD_INPUT_HANDLE);
// Change the window title:
SetConsoleTitle("Win32 Console 80 x 25 Fixed Size");
// Set up the required window size:
SMALL_RECT windowSize = {0, 0, 79, 24};
// Change the console window size:
SetConsoleWindowInfo(wHnd, TRUE, &windowSize);
// Create a COORD to hold the buffer size:
COORD bufferSize = {80, 25};
// Change the internal buffer size:
SetConsoleScreenBufferSize(wHnd, bufferSize);
}
// Console display at a particular screen position.
void DisplayAt(int x, int y, char *StringBuffer, int len)
{
DWORD n_of_chars;
COORD position = {x, y};
SetConsoleCursorPosition(wHnd, position);
WriteConsole(wHnd, StringBuffer, len, &n_of_chars, NULL);
return;
}
Including the <stdio.h> for getchar() bloated the size of the EXE 4 Kb. :(
How do I get rid of these unacceptable burden? Pragma directive again? ::)
P.S. Oh well I added the two infamous lines:
#undef getchar
#pragma comment(lib, "\\masm32\\lib\\msvcrt.lib")
and it shrinked from 19K to 9K :lol
Could anyone translate it into MASM just to see how it can
be done and how big it'll be?
Thanks
Frank
.EXE size of 2560 :U
.386
.model flat, STDCALL
option casemap:none
include C:\prog\include\windows.inc
include C:\prog\include\kernel32.inc
includelib ".\lib\kernel32.lib"
include C:\prog\include\user32.inc
includelib ".\lib\user32.lib"
Console80x25 PROTO
DisplayAt PROTO x:DWORD, y:DWORD, StringBuffer:DWORD, len:DWORD
.data?
wHnd HANDLE ?
rHnd HANDLE ?
inpbyte DWORD ?
.data
ConTitle db "Win32 Console 80 x 25 Fixed Size", 0
DispStr db "Let's do something",10,13
.code
start:
invoke AllocConsole
invoke Console80x25
invoke SetConsoleTextAttribute, wHnd, (BACKGROUND_BLUE OR FOREGROUND_BLUE OR FOREGROUND_GREEN)
invoke DisplayAt, 32, 12, ADDR DispStr, SIZEOF DispStr
invoke ReadConsole, rHnd, ADDR inpbyte, 1, NULL, NULL
invoke ExitProcess, 0
ret
Console80x25 PROC
LOCAL windowSize:SMALL_RECT
LOCAL bufferSize:COORD
mov windowSize.Left, 0
mov windowSize.Right, 0
mov windowSize.Top, 79
mov windowSize.Bottom, 24
mov bufferSize.x, 80
mov bufferSize.y, 25
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov wHnd,eax
invoke GetStdHandle, STD_INPUT_HANDLE
mov rHnd,eax
invoke SetConsoleTitle, ADDR ConTitle
invoke SetConsoleWindowInfo, wHnd, TRUE, ADDR windowSize
invoke SetConsoleScreenBufferSize, wHnd, DWORD PTR bufferSize
ret
Console80x25 ENDP
DisplayAt PROC x:DWORD, y:DWORD, StringBuffer:DWORD, len:DWORD
LOCAL n_of_chars:DWORD
LOCAL position:COORD
mov eax, x
mov position.x, ax
mov eax, y
mov position.y, ax
invoke SetConsoleCursorPosition, wHnd, DWORD PTR position
invoke WriteConsole, wHnd, StringBuffer, len, ADDR n_of_chars, NULL
ret
DisplayAt ENDP
end start
-r
That's really great - thanks RedSkull :U
In my pc it is still a little bloated: 3.00 KB (3.072 byte) :lol
I used:
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib
include C:\masm32\include\user32.inc
includelib C:\masm32\lib\user32.lib
instead of your:
include C:\prog\include\kernel32.inc
includelib ".\lib\kernel32.lib"
include C:\prog\include\user32.inc
includelib ".\lib\user32.lib"
Is it the same?
Frank
C:\MASM>\tools\masm615\ml -coff console.asm -link /SUBSYSTEM:CONSOLE /ALIGN:16
Microsoft (R) Macro Assembler Version 6.15.8803
Copyright (C) Microsoft Corp 1981-2000. All rights reserved.
Assembling: console.asm
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/SUBSYSTEM:CONSOLE /ALIGN:16
"console.obj"
"/OUT:console.exe"
LINK : warning LNK4108: /ALIGN specified without /DRIVER or /VXD; image may not
run
C:\MASM>dir console.exe
Volume in drive C is Windows
Volume Serial Number is 6801-E078
Directory of C:\MASM
06/03/2010 01:16 PM 1,296 console.exe
1 File(s) 1,296 bytes
0 Dir(s) 58,776,809,472 bytes free
Hi Clive :U
You mean that:
ml -coff console.asm -link /SUBSYSTEM:CONSOLE /ALIGN:16
just using the /ALIGN:16 reduces the size of the EXE file?
Well the warning
LINK : warning LNK4108: /ALIGN specified without /DRIVER; image may not run
was a good one, on my pc it refuses to run ::)
Any idea?
Quote from: frktons on June 03, 2010, 06:07:24 PMIs it the same?
Close enough; i use the tools and libraries from the most current SDK (7), and not the ones from MASM32 package. Also, I linked it as a WINDOWS application; if you link it as a CONSOLE, and then launch it from cmd (which causes it to inherit the same one), i predict it will not do what you want, and just overwrite the text that is there
-r
Well the default alignment for the 6.00 linker is 4K, which makes the EXE 16K
As /SUBSYSTEM:WINDOWS, my bad
C:\MASM>\tools\masm615\ml -coff console.asm -link /SUBSYSTEM:WINDOWS
Microsoft (R) Macro Assembler Version 6.15.8803
Copyright (C) Microsoft Corp 1981-2000. All rights reserved.
Assembling: console.asm
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/SUBSYSTEM:WINDOWS
"console.obj"
"/OUT:console.exe"
C:\MASM>dir console.exe
Volume in drive C is Windows
Volume Serial Number is 6801-E078
Directory of C:\MASM
06/03/2010 01:28 PM 16,384 console.exe
1 File(s) 16,384 bytes
0 Dir(s) 58,772,316,160 bytes free
C:\MASM>\tools\masm615\ml -coff console.asm -link /SUBSYSTEM:WINDOWS /ALIGN:16
Microsoft (R) Macro Assembler Version 6.15.8803
Copyright (C) Microsoft Corp 1981-2000. All rights reserved.
Assembling: console.asm
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/SUBSYSTEM:WINDOWS /ALIGN:16
"console.obj"
"/OUT:console.exe"
LINK : warning LNK4108: /ALIGN specified without /DRIVER or /VXD; image may not
run
C:\MASM>dir console.exe
Volume in drive C is Windows
Volume Serial Number is 6801-E078
Directory of C:\MASM
06/03/2010 01:27 PM 1,296 console.exe
1 File(s) 1,296 bytes
0 Dir(s) 58,772,725,760 bytes free
Quote from: redskull on June 03, 2010, 06:26:08 PM
Quote from: frktons on June 03, 2010, 06:07:24 PMIs it the same?
Close enough; i use the tools and libraries from the most current SDK (7), and not the ones from MASM32 package. Also, I linked it as a WINDOWS application; if you link it as a CONSOLE, and then launch it from cmd (which causes it to inherit the same one), i predict it will not do what you want, and just overwrite the text that is there
-r
Well I launched from cmd and it run without problem. :U
Black screen and cyan on blue string displayed at the correct position.
Well I checked, you were right, it overwrites the existing text.
Maybe a CLS would help :lol
@Clive:
The warning
LINK : warning LNK4108: /ALIGN specified without /DRIVER; image may not run
was a good one, on my pc it refuses to run ::)
Any idea?
Here's the 9.0 verions. Suppsoedly the alignment is still 4K, so I'm not sure where it's different...
C:\prog>ml /c /coff console.asm
Microsoft (R) Macro Assembler Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
Assembling: console.asm
C:\prog>link /SUBSYSTEM:WINDOWS console.obj
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
C:\prog>dir console.exe
Volume in drive C is IS-CUB3
Volume Serial Number is 4C6E-1410
Directory of C:\prog
06/03/2010 02:41 PM 2,560 console.exe
1 File(s) 2,560 bytes
0 Dir(s) 19,155,349,504 bytes free
C:\prog>
Quote from: redskull on June 03, 2010, 06:44:51 PM
Here's the 9.0 verions. Suppsoedly the alignment is still 4K, so I'm not sure where it's different...
C:\prog>ml /c /coff console.asm
C:\prog>link /SUBSYSTEM:WINDOWS console.obj
I used the same instructions and now the console displayed is a new one,
and the size is still 3072 bytes. I used ML v.10 / LINK v.10 from VS2010.
The different size could depend on the different libs you are including or on
how windows 7 ultimate 64 bit manages the whole.
Anyway 3K versus 9K of the C shrinked version is still a good gain. :P
Info update:
On win xp pro sp2 the size of the exe is the same of yours, so it probably depends
on the file system used. I used the same MASM32 package.
I have NTFS file system in both pc, on win7 I used a 4K cluster size to format the hard disk,
on win xp pro I don't know, it was already formatted.
That's odd, that the exact code built the same way with the same tools would be slightly different between XP and 7; after all, the file size should be reported the same, even if the "size on disk" is different. For the record, I use XP with a a 4K NTFS as well. I can't for the life of me think why they would be different, especialyl considering it's under a single cluster anyway. I'd be interested to see if there are discrepancies between the same exact file; i.e. assemble and link on XP, and then copy the EXE to 7 to see what it says.
-r
The 4K page comes from the 386, the cluster size on the disk has very little impact. What Windows wants to have is a directly mappable file, that it can pin in memory directly from disc, and not have to load and shuffle into a page backed by the page file.
There are two alignments, one in memory, and one in the file. The PE file format has historically been quite flexible. You can pick field combinations that cause the "Not a valid Win32 executable" message to be emitted. Most specifically the Base address (64K aligned), and the Virtual Address (>= 4K).
The linker and libraries can impact how the import table is built, and some of the sections could technically be coalesced. We could certainly examine the PE files and come to some specific conclusions, but this is not high on my priorities list. Making files incredibly small falls into the dont-care category as they usually get classed as heuristically bad by the AV tools.
I was building under Vista, using MASM32 (10) libraries
But increasing the cluster size to, say, 8K would certainly increase the size of the file on disk, while not the actual file size itself. And while all you say is true, we are (presumably) talking about identical code, build tools, and libraries; in this case, there would have to be some sort of code in the linker that builds the PE file with an extra 512 bytes, depending on what version of Windows is running, which I find unlikely (though nothing is impossible). I won't lose any sleep over it, for sure, but it would be interesting to know what's in those bytes.
-r
File mapping is page based. The size of the cluster impacts the amount of space wasted on the disc (allocation quantum), but the memory pinning is going to occur on a page/sector basis.
I'm pretty sure the linker doesn't care, or test, what the cluster size is. The different sizes here most likely relate to our varied choice of assemblers, libraries, and linkers. Using the same set I could show consistency from NT through Vista.
If you are curious about the extra 512 bytes, have a look at the
exe produced under win7, disassemble it, edit with an hexeditor or
whatever you think is fit.
I am unable to verify things like this at the moment.
I include the exe in case you like to have a look.
Frank
Apparently it's a relocation table. Lord knows why LINK stuck one on there, your version must default to using ASLR or something. Maybe use /DYNAMICBASE:NO and see what you get?
SECTION HEADER #4
.reloc name
48 virtual size
4000 virtual address (00404000 to 00404047)
200 size of raw data
A00 file pointer to raw data (00000A00 to 00000BFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
Read Only
RAW DATA #4
00404000: 00 10 00 00 34 00 00 00 0E 30 1A 30 2E 30 34 30 ....4....0.0.040
00404010: 77 30 83 30 88 30 99 30 A7 30 CB 30 E2 30 F2 30 w0.0.0.0§0Ë0â0ò0
00404020: F8 30 FE 30 04 31 0A 31 10 31 16 31 1C 31 22 31 ø0þ0.1.1.1.1.1"1
00404030: 28 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (1..............
00404040: 00 00 00 00 00 00 00 00 ........
BASE RELOCATIONS #4
1000 RVA, 34 SizeOfBlock
E HIGHLOW 00403038
1A HIGHLOW 00403021
2E HIGHLOW 00403040
34 HIGHLOW 0040303C
77 HIGHLOW 00403038
83 HIGHLOW 0040303C
88 HIGHLOW 00403000
99 HIGHLOW 00403038
A7 HIGHLOW 00403038
CB HIGHLOW 00403038
E2 HIGHLOW 00403038
F2 HIGHLOW 00402000
F8 HIGHLOW 00402004
FE HIGHLOW 00402008
104 HIGHLOW 0040200C
10A HIGHLOW 00402010
110 HIGHLOW 00402014
116 HIGHLOW 00402018
11C HIGHLOW 0040201C
122 HIGHLOW 00402020
128 HIGHLOW 00402024
0 ABS
Summary
1000 .data
1000 .rdata
1000 .reloc
1000 .text
Playing with the alignment value is not always the best solution. Not all versions of Windows can run those executables built with minimal alignment values.
For comparison. PeView is a good tool for doing this.
Quote from: Vortex on June 04, 2010, 07:57:08 PM
Playing with the alignment value is not always the best solution. Not all versions of Windows can run those executables built with minimal alignment values.
In my win7 if I compile with the /ALIGN:16 the exe is smaller but it won't run.
Quote from: jj2007 on June 04, 2010, 08:07:01 PM
For comparison. PeView is a good tool for doing this.
Your program is a lot different, it doesn't use all the APIs for a fixed size 80x25
console, and doesn't use colors or positioning on the centre of the screen as well. ::)
If it is only for seeing what's inside, it should be closer to the one we are analysing.
Quote from: Vortex on June 04, 2010, 07:57:08 PM
Playing with the alignment value is not always the best solution. Not all versions of Windows can run those executables built with minimal alignment values.
I wonder whether there is a practical case to demonstrate this. Does the attachment choke for anybody? It's align 16 and runs fine on XP...
Quote from: jj2007 on June 04, 2010, 08:47:54 PM
Quote from: Vortex on June 04, 2010, 07:57:08 PM
Playing with the alignment value is not always the best solution. Not all versions of Windows can run those executables built with minimal alignment values.
I wonder whether there is a practical case to demonstrate this. Does the attachment choke for anybody? It's align 16 and runs fine on XP...
On win7 it doesn't run ::)
message: "The application was unable to start correctly".
Well win7 is a little bit different from win xp, it doesn't like small things :lol
Quote from: frktons on June 04, 2010, 08:37:59 PM
Your program is a lot different, it doesn't use all the APIs for a fixed size 80x25
console, and doesn't use colors or positioning on the centre of the screen as well. ::)
If it is only for seeing what's inside, it should be closer to the one we are analysing.
No problem - see red's version attached. 1536 bytes with standard alignment, so it should run on Win7
if alignment is the problem.
Quote from: jj2007 on June 04, 2010, 08:55:00 PM
Quote from: frktons on June 04, 2010, 08:37:59 PM
Your program is a lot different, it doesn't use all the APIs for a fixed size 80x25
console, and doesn't use colors or positioning on the centre of the screen as well. ::)
If it is only for seeing what's inside, it should be closer to the one we are analysing.
No problem - see red's version attached. 1536 bytes with standard alignment, so it should run on Win7 if alignment is the problem.
Same error. Unable to start....
Well apparently the startup code produced is not compatible with win7 ::)
Quote from: frktons on June 04, 2010, 09:21:26 PM
Same error. Unable to start....
Well, sounds like a good occasion to isolate the culprit. Take the source code, and try various options. BTW, I used polink.
Quote from: jj2007 on June 04, 2010, 09:28:19 PM
Quote from: frktons on June 04, 2010, 09:21:26 PM
Same error. Unable to start....
Well, sounds like a good occasion to isolate the culprit. Take the source code, and try various options. BTW, I used polink.
I compiled the pgm you posted and the exe is again 3072 bytes and it run on win7.
I used the "console assemble and link" of masm32 editor, don't know if the polink was invoked,
You inserted some new code for it but I don't know if it works inside masm32 editor.
In my opinion win7 has a startup code that is somewhat bigger then previous
windows xp edition. But I am not an expert. And it is a 64 bit edition as well.
Maybe it counts in all the scene.
Which versions run from the attachment?
Ok I think I found something, with a little flaw:
After compiling, I used Polink with /SUBSYSTEM:console /ALIGN:4096 Console1kRed
and the size is now 1,536 bytes, and it runs.
The flaw is it doesn't allocate a new console, and it writes on previous console stuff.
Strange enough the source code has got the:
invoke AllocConsole
to allocate the new one ::)
The two examples you posted work fine both of them. What option did you use?
P.S. Well I forgot to use /SUBSYSTEM:windows, so when I start from the command
line it doesn't create a new console.
Merging the sections with the linker option /MERGE can produce smaller executables :
\masm32\bin\polink /SUBSYSTEM:WINDOWS /MERGE:.data=.text Demo.obj
Quote from: Vortex on June 05, 2010, 10:59:01 AM
Merging the sections with the linker option /MERGE can produce smaller executables :
\masm32\bin\polink /SUBSYSTEM:WINDOWS /MERGE:.data=.text Demo.obj
Thanks Vortex. One more to try. :P
JJ posted this code in his Console1kRed example:
end start
OPT_Res 0
OPT_DebugL /Subsystem:CONSOLE /merge:.text=.data /align:512
OPT_Linker polink
OPT_tmp2asm 1
after the end of the program.
It is the same thing I suppose ::)
Quote from: frktons on June 05, 2010, 11:17:08 AM
JJ posted this code in his Console1kRed example:
end start
OPT_Res 0
OPT_DebugL /Subsystem:CONSOLE /merge:.text=.data /align:512
OPT_Linker polink
OPT_tmp2asm 1
after the end of the program.
It is the same thing I suppose ::)
Sorry, I forgot to take away the RichMasm options. They do the same thing indeed.
I wonder whether /merge:.text=.data is the same as /merge:.data=.text ::)
Quote
Sorry, I forgot to take away the RichMasm options. They do the same thing indeed.
OK, thanks :U