The attached example written in VC2019 plain C uses a few simple UI procedures from the m64lib MASM library. This is one of the main targets for ML64 as CL.EXE no longer supports inline assembler. To save on the download size the 64 bit library in the MASM32 sub directory has been used.
This is the C source.
/* ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ */
#include <windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
/* ------------------------
MASM 64 bit library modules
------------------------ */
LRESULT MsgboxI(HWND,LPCTSTR,LPCTSTR,LONGLONG,LPSTR);
HANDLE button(HINSTANCE,HWND,LPCTSTR,UINT,UINT,UINT,UINT,UINT);
VOID line(HWND,UINT,UINT,UINT,UINT,COLORREF,UINT);
HINSTANCE hInstance;
HANDLE hWnd;
HANDLE butn1;
HANDLE butn2;
HANDLE butn3;
HANDLE butn4;
UINT sWid;
UINT sHgt;
char pTitle[] = " MASM 64 bit modules with Microsoft C";
char pWindowClass[] = "MASM_and_C_Window";
/* ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ */
void main()
{
HICON hIcon;
HCURSOR hCursor;
LPMSG pmsg;
WNDCLASSEX wc;
WNDCLASSEX * pwc;
MSG msg;
UINT wwid;
UINT whgt;
HBRUSH hBrush;
hInstance = GetModuleHandle(0);
hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(5));
hBrush = CreateSolidBrush(0x00333333);
hCursor = LoadCursor(NULL,IDC_ARROW);
pmsg = &msg;
pwc = &wc;
wwid = 900; /* required window width */
whgt = 600; /* required window height */
sWid = GetSystemMetrics(SM_CXSCREEN);
sHgt = GetSystemMetrics(SM_CYSCREEN);
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_BYTEALIGNWINDOW | CS_BYTEALIGNCLIENT;
wc.lpfnWndProc = &WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = hIcon;
wc.hCursor = hCursor;
wc.hbrBackground = hBrush;
wc.lpszMenuName = NULL;
wc.lpszClassName = pWindowClass;
wc.hIconSm = hIcon;
RegisterClassEx(pwc);
hWnd = CreateWindowEx(WS_EX_LEFT,
pWindowClass,
pTitle,
WS_OVERLAPPEDWINDOW,
sWid/2-(wwid/2),
sHgt/2-(whgt/2),
wwid,whgt,
NULL,NULL,hInstance,NULL);
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(pmsg,NULL,0,0))
{
TranslateMessage(pmsg);
DispatchMessage(pmsg);
}
}
/* ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ */
LRESULT CALLBACK WndProc(
HWND hWin,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
PAINTSTRUCT ps;
switch (uMsg)
{
case WM_COMMAND:
{
switch (wParam)
{
/* ---------
* buttons *
--------- */
case 150:
MsgboxI(hWin,"Button 1"," About",MB_OK,MAKEINTRESOURCE(5));
SetWindowText(butn1,"Done");
return 0;
break;
case 151:
MsgboxI(hWin,"Button 2"," About",MB_OK,MAKEINTRESOURCE(5));
SetWindowText(butn2,"Done");
return 0;
break;
case 152:
MsgboxI(hWin,"Button 3"," About",MB_OK,MAKEINTRESOURCE(5));
SetWindowText(butn3,"Done");
return 0;
break;
case 153:
if (MsgboxI(hWin,"Do you really want to exit ?",
" Exit Confirmation",MB_YESNO,MAKEINTRESOURCE(5)) == IDNO)
{
return 0;
break;
}
SendMessage(hWin,WM_DESTROY,0,0);
return 0;
break;
/* ------------
* menu items *
------------ */
case 1000:
SendMessage(hWin,WM_CLOSE,0,0);
break;
case 5000:
MsgboxI(hWin,pTitle," Isn't MASM magnificent",
MB_OK,MAKEINTRESOURCE(5));
return 0;
break;
}
}
case WM_PAINT:
BeginPaint(hWin,&ps);
line(hWin,160,30,160,sHgt,0x0000009F,3);
line(hWin,160,30,sWid,30,0x0000009F,3);
EndPaint(hWin,&ps);
return 0;
case WM_CREATE:
butn1 = button(hInstance,hWin,"Button 1",30,30,100,22,150);
butn2 = button(hInstance,hWin,"Button 2",30,60,100,22,151);
butn3 = button(hInstance,hWin,"Button 3",30,90,100,22,152);
butn4 = button(hInstance,hWin,"Close",30,120,100,22,153);
SetMenu(hWin,LoadMenu(hInstance,MAKEINTRESOURCE(10)));
return 0;
break;
case WM_CLOSE:
MsgboxI(hWin," Seeya round like a Rubens",
"Thats all folks",MB_OK,MAKEINTRESOURCE(5));
SendMessage(hWin,WM_DESTROY,0,0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWin,uMsg,wParam,lParam);
}
/* ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ */
Hi Hutch,
The Universal C run-time is a headache in the latest Visual Studio releases. I guess you used other include file sets and libraries from old SDKs to build your example.
https://stackoverflow.com/questions/35805113/visual-studio-2015-run-time-dependencies-or-how-to-get-rid-of-universal-crt
Hi Erol,
Nope, I started with windows.h and every time it needed another library, I found it in the distribution and copied the whole lot into the include directory. I ended up with about 2500 files but it works correctly and can finds everything. The include dir has 2554 files and the lib has 552 files but the compiled output files seem to work OK. There is an absolute mountain of junk in the whole package but if you look hard enough you can find most things.
Hi Hutch,
Thanks for the information. Sadly, the introduction of the Universal C run-time library results in a lot of mess. I cannot link a VC 2019 object module with msvcrt.lib :
public __local_stdio_printf_options
public _vfprintf_l
public printf
extern __stdio_common_vfprintf: near
extern __acrt_iob_func: near
extern ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9: byte
A simple hello world application using printf is importing those modules. ( the three extern statements )
Hutch,
I cloned the example with bc9/TCLib and it came in at 11,264, 512 larger that the original. TCLib is c++ only so I did need to wrap the declares with extern "C".
I also had to change all HANDLE's to HWND's (compiler complained )and redo the rc file. My rc editor did not like something in there???
I may post it over on my forum in a bit.
I just updated my VS2019 today. 16.1.6 -> 16.2.0. Big update. It even had to reboot the system.
I have both the ide and the build tools installed as I do build downloaded projects from time to time but use the build tools for all my bc9/TClib work. Having the installer makes it a breeze to keep them updated.
James
Erol,
I just converted a CPP golden oldie and when it built at 283k, I went looking for the msvcrt option. The /MD option did the job, droped to 41k.
Playing from the IDE will produce better results, unless you are a VS command line expert (I am not and am yet to find a real one). For the first program you will get an .exe of 7KB not 11KB tweaking from the IDE.
It would be interesting to see how its done, I went through the CL manual options but I used the speed optimisation. With your build, did you include an icon, manifest and version control block ?
SET Path=C:\code\msvc2019\bin\x64
SET INCLUDE=C:\code\WDDK710\include
SET LIB=M:\masm32\lib64
cl -GS- -Zl -O2 -DWIN32_LEAN_AND_MEAN cplusasm.c kernel32.lib user32.lib gdi32.lib M:\masm32\m64lib\m64lib.lib rsrc.res -link -nodefaultlib -entry:main -subsystem:windows,5.2 -nocoffgrpinfo -map
9.5 KB
/GS[-] enable security checks
/Zl omit default library name in .OBJ
/Ox optimizations (favor speed)
/O2 maximum optimizations (favor speed)
-link
/NODEFAULTLIB[:library]
/MAP[:filename]
EDIT: use now masm32\lib64 folder.
EDIT: MSVCUnPack.cmd just download and unzip files to current folder.
I have gone to 9KB without using the kernel32.lib from the masm32 library, without using an older toolset, like the Windows 7.1 SDK and without optimizing for size (it is for speed). With these it will go to 7.5 KB. I have used VS 2019, manifest, version block and icon. :thumbsup: , I am using Visual Studio 2017 - Windows XP (v141_xp) toolset (for the xp reason), but the size will not change with the Visual Studio 2019 (v142) toolset.
I tested a around 110k program,changed optimize speed vs optimize size,from mid option "neither" to optimize size and got Exe 1.5k smaller
It contains lots of gdi calls, some in loops
@hutch about 41k,there just be way to create a wizard for a minimum vc++ windows app,or a minimum template to start from
Attached is Hutch's example built with a batch file. The size of the executable is 7.5 Kb by merging some sections. A small C run-time module is added to the project.
Optional feature to a template without commandline:void __cdecl WinMainCRTStartup(void) { ExitProcess(WinMain(GetModuleHandle(NULL), NULL, NULL, W_SHOWDEFAULT)); }
void __cdecl mainCRTStartup(void) { __declspec(dllimport) void __cdecl exit(int status); int __cdecl main(void); exit(main()); }
Not 100% true a few things :wink2: , namely we can build with VS 2019 and the VS 2017 Xp toolset using the Masm32/64 MSVCRT.lib and Masm32/64 Kernel32.lib.
Ignore All Default Libraries: Yes (/NODEFAULTLIB), change Entry Point to main then:
#define _NO_CRT_STDIO_INLINE
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("hello\n");
return(0);
}
The statement _NO_CRT_STDIO_INLINE does the job, thanks.
Erol,
It worked fine here. Looking at the include at the start, now you know why I bundled them all together in one include directory.
I also just collected WDDK 7.10 inc files to a one include directory.
Those are WDDK msvc 2010 files and have a support for OS msvcrt.dll.
EDIT: for testing with Pelles C 9 headers:bin\cl.exe -GS- -MD -wd4068 -wd4103 -D__midl -D__POCC__=900 -D__POCC_TARGET__=1 -Drestrict=__restrict -D__WCHAR_TYPE__=short -D__SIZE_TYPE__=__int32 foo.c
x64
__POCC_TARGET__=3
__SIZE_TYPE__=__int64
cl -GS- -Zl -O2 -wd4068 -wd4103 -DWIN32_LEAN_AND_MEAN -D__midl -D__POCC__=900 -D__POCC_TARGET__=3 -Drestrict=__restrict -D__WCHAR_TYPE__=short -D__SIZE_TYPE__=__int64 cplusasm.c kernel32.lib user32.lib gdi32.lib M:\masm32\m64lib\m64lib.lib rsrc.res -link -nodefaultlib -entry:main -map -nocoffgrpinfo -safeseh:no -subsystem:windows,5.2
works great here Erol :thumbsup: