Author Topic: 64 Bit SDK Programming  (Read 5136 times)

Frederick Harris

  • Newbie
  • *
  • Posts: 47
64 Bit SDK Programming
« on: September 30, 2021, 06:17:35 pm »
First post in Patrice's forum! 

I recall several years back Jim Fuller and I were trying to get you to do command line compiling with TCLib Patrice.  Didn't seem like you wanted to have anything to do with it :).  Anyway, I just tried for the first time (Yea, after all these years!) to use my TCLib within the Visual Studio IDE and jeeez, it worked right off.  Surprised the daylights out of me.  I figured it would be like pulling teeth!  All I did was put TCLib in the top level solution/project folder, and clear out all the libraries Microsoft 'shotguns' in the Project >> Linker >> Input >> Additional Dependencies dialog, and replace them with just....

TCLib.lib
kernel32.lib
user32.lib

....and it built with no errors or warnings.  It was just the most basic window possible.  First try it came in I think 4,692 bytes, whereas from the command line it was coming in 4,092 bytes, which got me curious.  So I flipped a few switches in the IDE - no security checks, eliminate manifest, rebuilt, and it came in my 4,092 bytes!  Cool!

You know Patrice, my C++ knowledge is really only like still at C99 or so.  I'm retired now and was thinking of maybe getting a new C++ book or two so as to bring myself up to speed with the many additions to the language I haven't really kept up with in 20 years.  However, pulling me in the other direction is the fact that by year 2000 or so C++ was already a very mature programming language with full and intricate support for classes, inheritance, templates, and other things.  It had matured rapidly from it's inception in the early 80s I think.  Adding to that, all the stuff the powers that be in the C++ world keep adding to the language seem to me to be morphing it into C#, and I kind of take a dim view of that.  The functionality they are adding is stuff that could have been done another way anyhow.  Take threading.  The Win32 Api always had powerful threading functions that were reasonably easy to use and well documented.  Now they have C++ wrappers around all that stuff, and the sizes of executables keeps balooning.  I used to make major use of mingw in my work.  Like my TCLib it used to 'piggyback' off of msvcrt.dll.  Well, for a good many years now they've statically linked the pthreads library into the executables produced by mingw g++, and executables are now bloated just like Microsoft's.

I know size doesn't matter anymore with storage and RAM of near infinite size, and internet connections at blazing speeds, but it's just sort of an art form to me to write good code and have it tight.  I'm sure you know what I mean.


Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: 64 Bit SDK Programming
« Reply #1 on: September 30, 2021, 08:02:02 pm »
Quote
I'm sure you know what I mean.

Yes, writing small code size has always been a good practice to me, and I hate bloated languages (WinDev being the winner all categories).

Each new release of Visual Studio produce larger code, but i am trying from my best to keep it small, this is the reason why i keep using VS10 to compile my WinLIFT/GDImage 64-bit DLLs.

I would be glad to learn from you how to further reduce the size of my code, because i came late into the C/C++ world.



Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: 64 Bit SDK Programming
« Reply #2 on: October 01, 2021, 10:21:28 am »
Fred

What is the latest TCLib version for 64-bit unicode?
« Last Edit: October 01, 2021, 11:13:06 am by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

James Fuller

  • Newbie
  • *
  • Posts: 41
Re: 64 Bit SDK Programming
« Reply #3 on: October 01, 2021, 01:11:41 pm »
Hey Fred.
Welcome.

Patrice,
  I think you need to create a subforum for Fred here so he can have a place to post his excellent work and insights.
José's (now Theo's) forum is a mess.

I am using the VS 2022 preview for most work now although I don't think I even fired up the IDE. All command line

I have my hacked version of TCLib working with the current BCX. What FUN.

James

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: 64 Bit SDK Programming
« Reply #4 on: October 01, 2021, 04:49:24 pm »
If Fred needs a dedicated section, he just has to tell me the name he wants to use for it.

About Théo's forum, he shoots himself in the feet.
« Last Edit: October 01, 2021, 04:51:11 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Frederick Harris

  • Newbie
  • *
  • Posts: 47
Re: 64 Bit SDK Programming
« Reply #5 on: October 02, 2021, 02:17:00 pm »
Was just going to bring you up to date on that.  Although I've been quiet for a few years, I've worked on things on and off.  Give me just a bit....

Frederick Harris

  • Newbie
  • *
  • Posts: 47
Re: 64 Bit SDK Programming
« Reply #6 on: October 02, 2021, 03:39:54 pm »
Just the other day I put all my TCLib files on GitHub here....

https://github.com/FrederickJHarris/TCLib

Now I'm just learning online repositories and storage and such, so I'm hoping that anyone interested in TCLib or anything else of mine that I make available may be able to get it from there.  I don't know if one needs to sign up there to download something or not.  When I put my TCLib files there the other day I tried to see how the whole interface worked in terms of downloading stuff and all, and I saw that one could come up with an interface where there was 'Download Zip' button, and I tried that.  Also there was my full set of files to use nmake.exe from the command line to build TCLib.  But I put TCLib.lib there too for folks who don't feel like building the lib, but just want to download TCLib and have it or try it.

I just found a bit of a snag this morning though.  The 'Download Zip' button didn't include all the files I put in the \FrederickJHarris\TCLib Repository.  There must be some algorithm or other that runs at their end to attempt to select the files out of a repository that pertain specifically to building something like a library or project, and leave others out.  What happened the other day is I opened the zip I downloaded from GitHub and ran ....

nmake TCLib.mak

...from the command prompt to see if it worked.  It Did!  So I wondered if it worked.  So I copied the most basic SDK window code to a file there and tried to build it....

Code: [Select]
/*
   Form1

   To create an API (Application Programming Interface) based Windows program using Microsoft's
   Software Development Kit (SDK), one must first fill out several of the more critical members
   of a WNDCLASS or WNDCLASSEX struct ...

   struct WNDCLASSEX
   {
     UINT    cbSize;
     UINT    style;
     WNDPROC lpfnWndProc;
     int     cbClsExtra;
     int     cbWndExtra;
     HANDLE  hInstance;
     HICON   hIcon;
     HCURSOR hCursor;
     HBRUSH  hbrBackground;
     LPCTSTR lpszMenuName;
     LPCTSTR lpszClassName;
     HICON   hIconSm;
   };

   ...and then pass this information to Windows by calling RegisterClass() or
   RegisterClassEx()...

   https://msdn.microsoft.com/en-us/library/windows/desktop/ms633587%28v=vs.85%29.aspx

   The three most important members of WNDCLASSEX that must be filled out properly and without
   which an application window can't be created are ...

   WNDCLASSEX::lpszClassName   // The null terminated textural name of the class, here "Form1"
   WNDCLASSEX::fnWndProc       // The address of the Window Procedure
   WNDCLASSEX::cbSize          // The size of the WNDCLASSEX object

   While the program can compile and run without filling out the WNDCLASSEX::hInstance member,
   I'd highly recommend that be filled out, because it could put you in a situation of
   undefined behavior.  Anyway, its provided for you as the 1st parameter of WinMain(), so
   there's no reason not to use it.

   After filling out these members of a WNDCLASSEX struct and calling RegisterClassEx() on that
   object, you can make a call to CreateWindow() or CreateWindowEx() to instantiate an
   instance of the Registered Class.  Note that the 1st parameter of CreateWindow() and the 2nd
   parameter of CreateWindowEx() is a pointer to the textural null terminated C String to which
   WNDCLASSEX::lpszClassName points - here "Form1".  The call to CreateWindow() or
   CreateWindowEx() represents a C based constructor call for an object.

   After calling CreateWindow() the remainder of the code in WinMain() must fall into a message
   loop - sometimes called a 'message pump,' which retrieves messages Windows the Operating
   System places in the program's 'message queue.'  This is a memory structure Windows creates
   for all programs where it places messages informing the program of user interactions with
   the program such as keyboard or mouse input, as well as system wide notifcations. The
   GetMessage() function retrieves the next message from the queue, and the DispatchMessage()
   function within the message pump causes Windows to dispatch (call) the Registered Window
   Procedure associated with the Window Handle of the message.

   The final piece of the puzzle is the Window Procedure itself, which is likely the most
   important concept in Windows Programming. Note that the WNDCLASSEX::lpfnWndProc member is
   typed as WNDPROC.  What that is is a function pointer like so...

   typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);

   In x86 LRESULT is a typedef for a LONG and hence is 32 bits, while in x64 LRESULT is a 64
   bit entity.  The CALLBACK symbol is a typedef of __stdcall.  So if the following looks
   better to you, you could think of it as this, at least in x86 ...

   long (__stdcall* WNDPROC)(HWND, UINT, WPARAM, LPARAM);

   In other words, the WNDCLASSEX::lpfnWndProc entity requires a pointer to a function that
   returns a long, uses standard call stack protocol, and has HWND, UINT, WPARAM, and LPARAM
   parameters. Don't let these confuse you.  Their usage will become clear, and I'll cover them
   in Form2 and Form3.  So just accept them for now, awaiting further clarification.  Note that
   our fnWndProc() function just below fullfills our specifications for a Window Procedure, and
   the address of that Window Procedure is assigned to WNDCLASSEX::fnWndProc in WinMain() as
   follows ...

   wc.lpfnWndProc = fnWndProc;

   Note that our fnWndProc() just below only does two things.  First, it tests the msg
   parameter of type unsigned int to see if it equals WM_DESTROY.  You can find WM_DESTROY
   defined in Windows.h as follows ...

   #define WM_DESTROY  0x0002

   So its equal to 2 (its actually in WinUser.h - #included by Windows.h).  Windows sends a
   WM_DESTROY message when you click the X in the Title Bar to close the program.  In that case
   the app calls PostQuitMessage(), which causes the message pump in WinMain() to fall through
   and end.  Then zero is returned in fnWndProc notifying Windows that the message has been
   handled, and to take no further action on it.  The second thing the program's Window
   Procedure does is pass every other message received in the Window Procedure not equal to
   WM_DESTROY to DefWindowProc() for default processing.  In other words, you are telling
   Windows that you aren't interested in that message and are taking no action on it, but that
   the Operating System can do whatever it must with it to make itself happy.  In general, when
   you handle a message by writing code, you make an early exit by returning zero.  Some
   messages do require other entities to be returned though.  Run the code below to make sure
   everything is working for you.
*/
// cl Form1.cpp /O1 /Os /GS- /link TCLib.lib user32.lib              //  4,096 Bytes UNICODE x64 Static Linked TCLib
// cl Form1.cpp /O1 /Os user32.lib                                   // 92,160 Bytes UNICODE x64 Static Linked MS C Runtime
#ifndef UNICODE
    #define UNICODE
#endif
#ifndef _UNICODE
    #define _UNICODE
#endif
#include <windows.h>

LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 if(msg==WM_DESTROY)       // This is the Window Procedure.  The concept of the
 {                         // Window Procedure is the most important concept to
    PostQuitMessage(0);    // grasp in C/C++ WinApi coding.  You never call this
    return 0;              // function with your code; rather, Windows calls it
 }                         // to inform code here of events occurring.  The events
                           // are reported here as messages.
 return (DefWindowProc(hwnd, msg, wParam, lParam));
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 MSG messages;    // The concept of the Window Class and its associated Window Procedure are
 WNDCLASS wc;     // the most important concepts in Windows Programming.

 wc.lpszClassName = L"Form1",    wc.lpfnWndProc = fnWndProc;  // The Class Name Will Be Form1 And The Symbol fnWndProc
 wc.hInstance     = hInstance,   wc.style         = 0;        // Will Be Resolved At Runtime To The Virtual Address Of
 wc.cbClsExtra    = 0,           wc.cbWndExtra    = 0;        // Form1's Window Procedure, Which Windows Will Call
 wc.hIcon         = NULL,        wc.hCursor       = NULL;     // Through This Address Rather Than Through It's Name.
 wc.lpszMenuName  = NULL,        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
 RegisterClass(&wc);                                          // Register The Window Class With Windows
 CreateWindow(L"Form1", L"Form1", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 200, 100, 325, 300, HWND_DESKTOP, 0, hInstance, 0);
 while (GetMessage(&messages, NULL, 0, 0))   // The message pump retrieves messages from the program's
 {                                           // message queue with GetMessage(), does some translation
    TranslateMessage(&messages);             // work in terms of character messages, then calls the
    DispatchMessage(&messages);              // Window Procedure associated with the HWND of the message
 }                                           // being processed.  Note that an app can have many Window
 
 return (int)messages.wParam;
}


...and it worked!  Cool Beans!  Came in 4,096 bytes which seems to be the minimum base line size for the simplest possible non-dialog based CreateWindow SDK example built with VC 19.29.30133 and Linker 14.29.30133 for wide character and x64.  I get that size from command line builds and from Visual Studio IDE if one removes security checks, manifests, etc.

However, just before posting here I decided to make a final test so I tried to do a "Hello, World!" Console app and the linker errored out.  That got my head spinning for a bit until I figured out what was going on.  Nothing too serious as that is how I discovered the zip download didn't include a lot of necessary files.  It included all the necessary files to create TCLib, but not all the necessary files to use it.  The story is this...

My latest versions of TCLib 'piggybacks' off of a system dll named msvcrt.dll.  That was the C Runtime for Visual Studio 98 and VC6 circa 1998 - 2000 or so.  In Visual Studio versions after 98, which Microsoft named Visual Studio 2001, 2003, 2005, ....2015, 2019, etc., they created numbered versions of msvcrt.dll which formed the basis of their 'Redistributable Packages' which became necessary for binaries built with the /MD option.  Anyway, as the C and C++ languages evolved qualifiers were created relating to function prototypes and the old headers that worked with msvcrt.dll no longer worked at the linking step with the new libraries.  That's why I needed to create my own custom headers for such files as stdio.h.  At least that's my understanding of the issue.  Well, in the zip download those headers were missing - their algorithm didn't think they were needed I guess, and all the Demo files I use to keep testing stuff weren't in there either.  So when I attempted to create Demo1.cpp, which is just a console "Hello, World!" test, it errored out with all these ugly linker unresolved externals.  Here is that program, i.e., Demo1.cpp...

Code: [Select]
// Dennis Ritchie Classic "Hello, World!"
// cl Demo1.cpp /O1 /Os /GS- /link TCLib.lib kernel32.lib
// cl Demo1.cpp /O1 /Os /GS- /c
// link Demo1.obj TCLib.lib kernel32.lib
// 2,048 bytes x86 ASCII, 2,048 bytes x86 UNICODE VC15
// 2,560 bytes x64 ASCII, 2,560 bytes x64 UNICODE VC15
// 3,072 bytes x64 ASCII, 3,584 bytes x64 UNICODE VC19
#define  UNICODE
#define  _UNICODE
#include <windows.h>
#include "stdio.h"
#include "tchar.h"

int _tmain()
{
 _tprintf(_T("Hello, World!\n"));
 getchar();

 return 0;
}

// Output:
// =============
// Hello, World!

The reason my Form1.cpp file built OK the other day and this one didn't this morning is that the Form1.cpp file only includes <Windows.h> and nothing else.  There is not one single call in that code to any C Runtime function - it's all user32.lib code.  Demo1.cpp above calls stdio.h printf and getchar and has a #include "stdio.h" preprocessor directive.  The zip download didn't include stdio.h from the repository for whatever reason, and I didn't notice that.  So when I attempted to build Demo1.cpp and the build chain didn't find "stdio.h" in the directory with Demo1.cpp, it searched it's LIBPATH directories and came up with an updated stdio.h file which won't work with my TCLib.  Hence all these linker unresolved externals.  I know this is the case as I usually put conditional compilation directives in my code so I can test build with either my TCLib, or Microsoft's default libraries.  And when I try to build with TCLib and forget to uncomment out my #define TCLib lib, I see these  linker errors all the time.  This time, it just took me a bit of head spinning to figure out what was going on.  Moral of the story - if you download the zip and build TCLib make sure to grab the other files somehow or other!  Or just download TCLib.lib and the other files such as stdio.h, tchar.h, string.h, etc., seperately and work from there. 

One other thing, when I simply download TCLib.lib it is of a different size from the one I built on my computer.  Don't know what's going on there.  But when I test it it seems to work OK.  I'll post more on all this in a bit, but I just wanted to get through this bit of a glitch first off because it upset me a bit 'till I figured what was going on!  Others likely wouldn't be able to figure it out - naturally, and would just assume none of it worked. 

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: 64 Bit SDK Programming
« Reply #7 on: October 02, 2021, 03:49:59 pm »
Fred

You know, you can post rather large attachments on this forum.
Patrice
(Always working with the latest Windows version available...)

Frederick Harris

  • Newbie
  • *
  • Posts: 47
Re: 64 Bit SDK Programming
« Reply #8 on: October 02, 2021, 05:27:11 pm »
Yea, perhaps that would be easier Patrice.  Now that I'm a member, I expect you are using the same software Jose and Theo used, and that worked well for zips that included binaries.

Anyway, getting on with the TCLib topic, the size cost of linking with Microsoft's default runtime is quite high.  I'm getting around 90 to 92 k for that Form1 simple baseline GUI as compared to 4 k with my TCLib, so there's about an 86 K hit right there.  For whatever reason it's worse with console apps.  That Hello, World! program above is coming in like 125 k, so there's like a 120 k hit there.

In many cases it's avoidable with a little thought, knowledge and care.  My TCLib creation isn't really that bizarre of a thing to do.  Even Microsoft does it.  Their ATL (Active Template Library) does the same thing I do in terms of specifying the /NODEFAULTLIB linker switch.  That's still part of C++ Visual Studio I believe.  The story there is that in the late 90s after COM/OLE had become pretty much of a staple in the Windows Deelopment world, the only ways to build COM components were with Visual Basic or C++ or I guess Delphi and Borland's products.  With Visual Basic versions 5 and 6 the components were too big and heavy for the dial up modems that were in use at the time.  So Microsoft created their ATL tool set to allow C++ developers to create small and easily downloadable Active X Controls.  They eliminated the C Runtime from linkages when using that, and a lot of the commonly used C Runtime functions they duplicated the functionality and put them in various Windows libraries.  For example, one of the most commonly used C Runtime functions old time C programmers used was good old strcpy().  It's what I refer to as one of the 'string primitives'.  It's just a specialized memory move type operation the only difference being it's used for null terminated strings, so a null byte needs to be put at the end of the destination memory block.  Well, Microsoft implement lstrcpyA and lstrcpyW as replacements for it and that went in kernel32.lib.  Same thing for a lot of other functionality and other functions.  My TCLib uses that as one of it's tactics too.  Here is my implementation of strcpy from TCLib....

Code: [Select]
//=====================================================================================
//               Developed As An Addition To Matt Pietrek's LibCTiny.lib
//                            By Fred Harris, January 2016
//
//                      cl strcpy.cpp /c /W3 /DWIN32_LEAN_AND_MEAN
//=====================================================================================
#include <windows.h>
#include <string.h>

char* __cdecl strcpy(char* strDestination, const char* strSource)
{
 return lstrcpyA(strDestination, strSource);
}

wchar_t* __cdecl wcscpy(wchar_t* strDestination, const wchar_t* strSource)
{
 return lstrcpyW(strDestination, strSource);
}

In other cases where I thought I needed something or other, and couldn't find a Windows replacement for it, I simply coded it myself.  Sometimes it's not real hard.  Here's my atof and _wtof functions, for example....

Code: [Select]
//==============================================================================================
//               Developed As An Addition To Matt Pietrek's LibCTiny.lib
//                             By Fred Harris, May 2016
//
//        cl atof.cpp /D "_CRT_SECURE_NO_WARNINGS" /c /W3 /DWIN32_LEAN_AND_MEAN
//==============================================================================================
#include <windows.h>
#include "stdlib.h"
typedef SSIZE_T ssize_t;


double __cdecl atof(const char* pStr)
{
 ssize_t lTotal   = 0;
 char* pDecPt     = NULL;
 char c,cNeg      = NULL;
 double dblReturn;
 size_t iDiff;

 while(*pStr==32 || *pStr==8 || *pStr==48)
    pStr++;
 if(*pStr=='-')
 {
    cNeg='-';
    pStr++;
 }
 while(*pStr)
 {
    if(*pStr=='.')
    {
       pDecPt=(char*)pStr;
       pStr++;
    }
    else
    {
       if(*pStr>=48 && *pStr<=57)
       {
          c=*pStr++;
          lTotal=10*lTotal+(c-48); // Add this digit to the total.
       }
       else
          break;
    }   
 }
 if(pDecPt)
    iDiff=(int)(pStr-pDecPt-1);
 else
    iDiff=0;
 if(cNeg=='-')                  // If we have a negative sign, convert the value.
    lTotal=-lTotal;
 dblReturn=(double)lTotal;
 for(size_t i=0; i<iDiff; i++)
     dblReturn=dblReturn/10;

 return dblReturn;
}

double __cdecl _wtof(const wchar_t* pStr)
{
 ssize_t lTotal = 0;
 wchar_t* pDecPt=NULL;
 wchar_t c,cNeg=NULL;
 double dblReturn;
 size_t iDiff;

 while(*pStr==32 || *pStr==8 || *pStr==48)
    pStr++;
 if(*pStr==L'-')
 {
    cNeg=L'-';
    pStr++;
 }
 while(*pStr)
 {
    if(*pStr==L'.')
    {
       pDecPt=(wchar_t*)pStr;
       pStr++;
    }
    else
    {
       if(*pStr>=48 && *pStr<=57)
       {
          c=*pStr++;
          lTotal=10*lTotal+(c-48); // Add this digit to the total.
       }
       else
          break;   
    }
 }
 if(pDecPt)
    iDiff=(int)(pStr-pDecPt-1);
 else
    iDiff=0;
 if(cNeg==L'-')                  // If we have a negative sign, convert the value.
    lTotal=-lTotal;
 dblReturn=(double)lTotal;
 for(size_t i=0; i<iDiff; i++)
     dblReturn=dblReturn/10;

 return dblReturn;
}

Little bit of code there for sure, but not 88K or 115k as would be brought in by the C Runtime!  But there were some 'hard cases' that weren't easy to solve.  A lot of the stdio.h stuff was like that.  Take printf, sprintf, etc., formatted output to screen or buffer.  In Matt Pietrek's original LibCTiny.lib, which was the inspiration for my TCLib, he had come up with this....

Code: [Select]
//==========================================
// LIBCTINY - Matt Pietrek 2001
// MSDN Magazine, January 2001
//==========================================
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>

// Force the linker to include USER32.LIB
#pragma comment(linker, "/defaultlib:user32.lib")

extern "C" int __cdecl printf(const char * format, ...)
{
    char szBuff[1024];
    int retValue;
    DWORD cbWritten;
    va_list argptr;
         
    va_start( argptr, format );
    retValue = wvsprintf( szBuff, format, argptr );
    va_end( argptr );

    WriteFile(  GetStdHandle(STD_OUTPUT_HANDLE), szBuff, retValue,
                &cbWritten, 0 );

    return retValue;
}

...which involves Windows function wvsprintf.  Problem with that is it doesn't work for floating point math.  That was actually the first real snag I hit when developing my TCLib.  You see, Matt Pietrek's idea for his LibCTiny.lib was for it to be a limited use type thing - something that didn't have to do everything.  Something for small utility programs maybe, for which he thought it was well suited.  I had different ideas for it.  I wanted it to be FOR EVERYTHING!  What I really wanted was a complete application development framework for C++ that made extremely eclectic use of that language to provide me a complete substitute for PowerBASIC - very small program size, dynamic multi-dimensional arrays, PowerBASIC like string handling, etc.  But getting back to stdio.h and printf family functions, I ended up writing tons of code to duplicate that functionality.  In fact, at the point I decided to tackle the problem in another manner, I had just finished, after about 3 weeks of work on it, my own complete implementation of printf, and it involved well over a thousand lines of code if I remember correctly. 

Now, I always knew there was an implementation of printf and everything else related to it in msvcrt.dll, and I always knew I could do a LoadLibrary()/GetProcAddress() sequence on that dll to get a function pointer to printf and use it.  I had discovered that many years previous when I was learning C and the use of function pointers.  But it never really dawned on me early on in my TCLib endeavors to do that.  I guess it may have seemed to me like cheating.  But the straw that 'broke the camel's back' for me was I had just downloaded and started to use Mark Russinovitche's SysInternals 'Process Explorer', and what I found out that I didn't know was that msvcrt.dll was loaded into every GUI process in Windows!!!! Strangely enough - not console processes, but EVERY GUI process!  So when I saw that and the significance of it hit me, I'm thinking, here I am, spending weeks and weeks and weeks, and writing thousands of lines of brutal code to duplicate functionality in the C Runtime, and there it all sits in msvcrt.dll just begging to be used.  Only one function call away once I've done a LoadLibrary() on a dll already sitting in my process!  And I guess the coolest thing I found about it was that I could name the function pointer returned by GetProcAddress, where, for example, I was asking for a pointer to printf, I could name the function pointer printf!  And it's use was indistinguishable from the real printf function!

As I did research on the matter I realized that that was how mingw worked.  I do believe I'm correct on that.  I think.  I found out Microsoft doesn't like it, but seemingly can't do anything about it.  When I used to use Bloodshed Dev-C++ in and around 2000 or so I found it's executables were only slightly larger than my TCLib created ones.  Never knew how they did it, but now I know.  They were even a tad smaller than PowerBASIC's.  So I really knew it could be done - somehow. 

So, that's what I decided to do.  Get a lot of hard stuff from msvcrt.dll and the easy stuff I'd code myself or get it from substitutes in the Windows libraries.  So that's about it in a nutshell how TCLib works.    Really, we're talking about 80k to 100k of program size that can nearly always be eliminated.  Personally, I'd do darn near anything to eliminate that, even if it took writing a C Runtime function right in my code to do it.  One can write pretty many lines of code for something one needs and come in under 80k!

I'll continue in a bit.....

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: 64 Bit SDK Programming
« Reply #9 on: October 02, 2021, 07:43:04 pm »
Fred

You can also attch 7z file

Have a look at the MIDI Piano project, here
http://www.objreader.com/index.php?topic=47.0
it is using TCLib and the size of the 64-bit exe (either skinned or not) is 36 Kb.

I did translate it to different languages to show that the SDK coding style is always the same whatever the tool being used.

Here is my own wcscopy function

Code: [Select]
WCHAR* wcscopy (IN WCHAR* dst, IN const WCHAR* src) {
    // Warning, there is no check for buffer overflow !
    long nLen = lstrlen(src);
    MoveMemory(dst, src, nLen * sizeof(WCHAR));
    dst[nLen] = L'\0';
    return dst;
}

About size, like DemoMaker are doing, I could fool people using UPX  ;)
« Last Edit: October 02, 2021, 07:51:56 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

James Fuller

  • Newbie
  • *
  • Posts: 41
Re: 64 Bit SDK Programming
« Reply #10 on: October 02, 2021, 09:52:57 pm »
One of the issues presently; Quote from https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-160
Quote

Starting in Visual Studio 2015, the CRT has been refactored into new binaries. The Universal CRT (UCRT) contains the functions and globals exported by the standard C99 CRT library. The UCRT is now a Windows component, and ships as part of Windows 10. The static library, DLL import library, and header files for the UCRT are now found in the Windows 10 SDK. When you install Visual C++, Visual Studio setup installs the subset of the Windows 10 SDK required to use the UCRT. You can use the UCRT on any version of Windows supported by Visual Studio 2015 and later versions. You can redistribute it using vcredist for supported versions of Windows other than Windows 10. For more information, see Redistributing Visual C++ Files.

No new crt addtions have been added to msvcrt.
I gave the UCRT a look several years ago but don't remember why I gave up.

James

Frederick Harris

  • Newbie
  • *
  • Posts: 47
Re: 64 Bit SDK Programming
« Reply #11 on: October 04, 2021, 03:44:00 pm »
Well, you guys are way ahead of me, as usual! 

I'm going to try to attach a TCLib.rar I just made and checked out yesterday.  It's the latest.  The only change to it that I didn't converse with James over concerns three obscure entities I added to TCLib to support console I/O in GUI programs.  That's kind of an odd issue.  When Windows detects that a program is a GUI as opposed to a console program, somehow or other console C Runtime I/O handles are either zeroed out or not initialized.  To overcome that, and to be able to do an AllocateConsole() in a GUI program where printf will work, I needed three obscure symbols from msvcrt.dll...

Code: [Select]
_iob                             // array of FILE*
_open_osfhandle        // Associates a C run-time file descriptor with an existing operating system Api file handle
fdopen(hCrtIn,"r");      // Associates a stream with a file that was previously opened for low-level I/O.

I wouldn't have had to add them to TCLib.  It's always a hard choice for me when I agonize over adding something, cuz I don't want to bloat the code.  But in the end I decided I really wanted these.  Here is a program that shows how it works, followed by the debug output from the console screen if I clicked the button twice to printf to the console....

Code: [Select]
// AllocateConsole.cpp
// cl AllocateConsole.cpp /O1 /Os /GR- /GS- TCLib.lib kernel32.lib user32.lib
// Size: 7,168 Bytes; Uses TCLib
#include <windows.h>
#include "AllocateConsole.h"
#include "stdio.h"           


bool GUI_Console_IO(FILE*& hFileIn, FILE*& hFileOut) 
{                                                                   
 HMENU   hSysMenu        = NULL;                       // For Re-Initializing CRT Console IO In GUI Apps.                             
 HANDLE  hStdOut         = NULL;                       // With Windows, CRT Console IO File Descriptors Are             
 HANDLE  hStdIn          = NULL;                       // Zeroed Out At GUI Initialization.  That's why
 int     hCrtOut         = 0;                          // C Runtime console i/o routines won't work.
 int     hCrtIn          = 0;
 
 if(!AllocConsole()) return false;                     // Create Console
 hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);            // Get Standard Output Handle
 hStdIn  = GetStdHandle(STD_INPUT_HANDLE);             // Get Standard Input Handle
 
 // Open stdin
 hCrtIn   = _open_osfhandle((intptr_t)hStdIn,O_TEXT);  // Associates a C run-time file descriptor with an existing operating system Api file handle
 hFileIn  = _fdopen(hCrtIn,"r");                       // Associates a stream with a file that was previously opened for low-level I/O.
 _iob[0]=*hFileIn;                                     // _iob Is An Array of FILE structs containing stdin, stdout, and stderr
 
 // Open stdout
 hCrtOut  = _open_osfhandle((intptr_t)hStdOut,O_TEXT); // Associates a C run-time file descriptor with an existing operating system Api file handle
 hFileOut = _fdopen(hCrtOut,"w");                      // Associates a stream with a file that was previously opened for low-level I/O.
 _iob[1]=*hFileOut;                                    // pFile[1] is stdout FILE object.  This Call Re-Initializes It.
 
 // Disable Close In Title Bar Of Console Window       // Otherwise, clicking the close button on the console window will terminate the whole
 hSysMenu = GetSystemMenu(GetConsoleWindow(),0);       // process - GUI and all!  Not the best thing to happen.
 DeleteMenu(hSysMenu,6,MF_BYPOSITION);
 
 return true;
}


LRESULT CALLBACK fnWndProc_OnCreate(WndEventArgs& Wea)
{
 HWND hButton = NULL;
 
 printf("  Entering fnWndProc_OnCreate()\n");
 printf("    Wea.hWnd = 0x%p\n",Wea.hWnd);
 Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 hButton=CreateWindow("button","Printf() To Console",WS_CHILD|WS_VISIBLE,90,50,200,30,Wea.hWnd,(HMENU)IDC_BUTTON1,Wea.hIns,0);
 printf("  Leaving fnWndProc_OnCreate()\n\n");
 
 return 0;
}


LRESULT CALLBACK fnWndProc_OnCommand(WndEventArgs& Wea)
{
 double dblWeight = 168.0;
 
 printf("  Entering fnWndProc_OnCommand()\n");
 if(LOWORD(Wea.wParam)==IDC_BUTTON1)
    printf("    My Name Is Fred And I Weight %3.0f Pounds.\n",dblWeight);
 printf("  Leaving fnWndProc_OnCommand()\n\n");
 
 return 0;
}


LRESULT CALLBACK fnWndProc_OnClose(WndEventArgs& Wea)
{
 printf("  Entering fnWndProc_OnClose()\n");
 printf("    Wea.hWnd = %u\n",Wea.hWnd);
 DestroyWindow(Wea.hWnd);
 printf("  Leaving fnWndProc_OnClose()\n");
 
 return 0;
}


LRESULT CALLBACK fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 printf("    Entering fnWndProc_OnDestroy()\n");
 printf("      Wea.hWnd = 0x%p\n",Wea.hWnd);
 PostQuitMessage(0);
 printf("    Leaving fnWndProc_OnDestroy()\n");
 
 return 0;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(unsigned int i=0; i<dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 char szClassName[]="AllocateConsole";
 FILE*   hFileOut  = NULL;
 FILE*   hFileIn   = NULL;
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 if(GUI_Console_IO(hFileIn,hFileOut))                   // Re-Initialize CRT I/O Console Handles
 {
    printf("Entering WinMain()\n");
    wc.lpszClassName = szClassName,                     wc.lpfnWndProc = fnWndProc;
    wc.cbSize        = sizeof(WNDCLASSEX),              wc.style       = 0;
    wc.hIcon         = LoadIcon(NULL,IDI_APPLICATION),  wc.hInstance   = hIns;
    wc.hIconSm       = NULL,                            wc.hCursor     = LoadCursor(NULL,IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW,         wc.cbWndExtra  = 0;
    wc.lpszMenuName  = NULL;                            wc.cbClsExtra  = 0;
    RegisterClassEx(&wc);
    hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,775,600,400,190,HWND_DESKTOP,0,hIns,0);
    printf("  hWnd = 0x%p\n\n",hWnd);
    ShowWindow(hWnd,iShow);
    while(GetMessage(&messages,NULL,0,0))
    {
       TranslateMessage(&messages);
       DispatchMessage(&messages);
    }
    printf("Leaving WinMain()\n\nPress Any Key To Continue....");
    getchar();
    fclose(hFileIn);
    fclose(hFileOut);
    FreeConsole();
 }
 
 return (int)messages.wParam;
}



#if 0
Output From Run Where I Clicked The 'Write To Console' Button Twice...

Entering WinMain()
  Entering fnWndProc_OnCreate()
    Wea.hWnd = 0x00000000001F050A
  Leaving fnWndProc_OnCreate()

  hWnd = 0x00000000001F050A

  Entering fnWndProc_OnCommand()
    My Name Is Fred And I Weight 168 Pounds.
  Leaving fnWndProc_OnCommand()

  Entering fnWndProc_OnCommand()
    My Name Is Fred And I Weight 168 Pounds.
  Leaving fnWndProc_OnCommand()

  Entering fnWndProc_OnClose()
    Wea.hWnd = 2032906
    Entering fnWndProc_OnDestroy()
      Wea.hWnd = 0x00000000001F050A
    Leaving fnWndProc_OnDestroy()
  Leaving fnWndProc_OnClose()
Leaving WinMain()

Press Any Key To Continue....
#endif

Here's AllocateConsole.h...

Code: [Select]
//AllocateConsole.h
#ifndef Main_h
#define Main_h

#define O_TEXT                            0x4000  // From Fcntl.h
#define IDC_BUTTON1                       1500
#define dim(x)                            (sizeof(x) / sizeof(x[0]))
extern  "C"  int                           _fltused = 1;

struct                                    WndEventArgs
{
 HWND                                     hWnd;
 WPARAM                                   wParam;
 LPARAM                                   lParam;
 HINSTANCE                                hIns;
};

LRESULT CALLBACK fnWndProc_OnCreate       (WndEventArgs& Wea);
LRESULT CALLBACK fnWndProc_OnCommand      (WndEventArgs& Wea);
LRESULT CALLBACK fnWndProc_OnClose        (WndEventArgs& Wea);
LRESULT CALLBACK fnWndProc_OnDestroy      (WndEventArgs& Wea);

struct                                    EVENTHANDLER
{
 unsigned int                             iMsg;
 LRESULT                                  (*fnPtr)(WndEventArgs&);
};

const EVENTHANDLER                        EventHandler[]=
{
 {WM_CREATE,                              fnWndProc_OnCreate},
 {WM_COMMAND,                             fnWndProc_OnCommand},
 {WM_CLOSE,                               fnWndProc_OnClose},
 {WM_DESTROY,                             fnWndProc_OnDestroy}
};
#endif

Both those files should be in TCLib.rar.

Other thing I did yesterday was experiment with just how small I could make the simplest possible GUI template using various combinations of x86, x64, UNICODE, ASCI and my several versions of Microsoft's compilers.  I have VC6 circa 1998 or so (only x86 of course), VC15 from Visual Studio 2008 Professional, and VC19 from  VStudio 2019 Community.  Here are my results which you can see atop the source code file....

Code: [Select]
// cl Form1.cpp /O1 /Os /GS- /link crt_win_a.obj user32.lib          //  2,560 Bytes VC15 ASCI    x64 Static Linked crt_win_a.obj
// cl Form1.cpp /O1 /Os /GS- /link crt_win_w.obj user32.lib          //  3,072 Bytes VC15 UNICODE x64 Static Linked crt_win_w.obj
// cl Form1.cpp /O1 /Os /GS- /link TCLib.lib user32.lib              //  3,584 Bytes VC15 UNICODE x64 Static Linked TCLib
// cl Form1.cpp /O1 /Os /GS- /link TCLib.lib user32.lib              //  4,096 Bytes VC19 UNICODE x64 Static Linked TCLib
// cl Form1.cpp /O1 /Os user32.lib                                   // 92,160 Bytes UNICODE x64 Static Linked MS C Runtime
#ifndef UNICODE
    #define UNICODE
#endif
#ifndef _UNICODE
    #define _UNICODE
#endif
#include <windows.h>

LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 if(msg==WM_DESTROY)       // This is the Window Procedure.  The concept of the
 {                         // Window Procedure is the most important concept to
    PostQuitMessage(0);    // grasp in C/C++ WinApi coding.  You never call this
    return 0;              // function with your code; rather, Windows calls it
 }                         // to inform code here of events occurring.  The events
                           // are reported here as messages.
 return (DefWindowProc(hwnd, msg, wParam, lParam));
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPWSTR lpszArgument, int iShow)
{
 MSG messages;    // The concept of the Window Class and its associated Window Procedure are
 WNDCLASS wc;     // the most important concepts in Windows Programming.

 wc.lpszClassName = L"Form1",    wc.lpfnWndProc   = fnWndProc; // The Class Name Will Be Form1 And The Symbol fnWndProc
 wc.hInstance     = hInstance,   wc.style         = 0;         // Will Be Resolved At Runtime To The Virtual Address Of
 wc.cbClsExtra    = 0,           wc.cbWndExtra    = 0;         // Form1's Window Procedure, Which Windows Will Call
 wc.hIcon         = NULL,        wc.hCursor       = NULL;      // Through This Address Rather Than Through It's Name.
 wc.lpszMenuName  = NULL,        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
 RegisterClass(&wc);                                           // Register The Window Class With Windows
 CreateWindow(L"Form1", L"Form1", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 200, 100, 325, 300, HWND_DESKTOP, 0, hInstance, 0);
 while (GetMessage(&messages, NULL, 0, 0))   // The message pump retrieves messages from the program's
 {                                           // message queue with GetMessage(), does some translation
    TranslateMessage(&messages);             // work in terms of character messages, then calls the
    DispatchMessage(&messages);              // Window Procedure associated with the HWND of the message
 }                                           // being processed.  Note that an app can have many Window
 
 return (int)messages.wParam;
}

So you can see the memory allocation granularity of the compilers is 512 bytes.  Sizes ranged from 2,560 bytes to 4,096 bytes.  No results above for VC6 because results with that were no better than with my fairly old VC9 from Visual Studio 2008.  I think the first version of Visual Studio that did x64 was VStudio 2005.  I don't have that, but I still use my VStudio 2008 compiler a lot - that's the VC15 version of the compiler.  Little confusion cuz the numbers of the compiler version and VStudio version don't exactly jive!

One issue you may not have ever seen if you examine my command line strings above - and I don't think I've ever discussed this with James, is that there are SDK style programs out there that make no use whatsoever of anything at all in the C Runtime library.  For such a program even TCLib is an overkill.  One example of that is Charles Petzold's Hello, Windows! program from his Windows 95 book....

Code: [Select]
/* cl HelloWin.cpp /O1 /Os /GS- /link crt_win_a.obj kernel32.lib user32.lib gdi32.lib winmm.lib       4,096 Bytes */
/* cl HelloWin.cpp /O1 /Os /GS- /link TCLib.lib kernel32.lib user32.lib gdi32.lib winmm.lib           4,608 Bytes */
/* cl HelloWin.c /O1 /Os kernel32.lib user32.lib  gdi32.lib winmm.lib                                92,672 Bytes */
/*------------------------------------------------------------
   HELLOWIN.C -- Displays "Hello, Windows 95!" in client area
                 (c) Charles Petzold, 1996
  ------------------------------------------------------------*/
#include <windows.h>

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
 switch(iMsg)
 {
  case WM_CREATE:
    {
       PlaySound("hellowin.wav", NULL, SND_FILENAME | SND_ASYNC);
       return 0;
    }    
  case WM_PAINT:
    {
       PAINTSTRUCT ps;
       HDC hdc = NULL;
       RECT rect;
       hdc = BeginPaint(hwnd, &ps);
       GetClientRect(hwnd, &rect);
       DrawText(hdc, "Hello, Windows 95!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
       EndPaint(hwnd, &ps);
       return 0;
}
  case WM_DESTROY:
    {
       PostQuitMessage(0);
       return 0;
    }
 }

 return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
 HWND hWnd=NULL;
 WNDCLASSEX wc;
 MSG msg;
 
 wc.cbSize        = sizeof (wc);
 wc.style         = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc   = WndProc;
 wc.cbClsExtra    = 0;
 wc.cbWndExtra    = 0;
 wc.hInstance     = hInstance;
 wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
 wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 wc.lpszMenuName  = NULL;
 wc.lpszClassName = "HelloWin";
 wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
 RegisterClassEx(&wc);
 hWnd=CreateWindow("HelloWin","The Hello Program",WS_OVERLAPPEDWINDOW,150,150,1200,700,NULL,NULL,hInstance,NULL);
 ShowWindow(hWnd, iCmdShow);
 UpdateWindow(hWnd);
 while(GetMessage (&msg, NULL, 0, 0))
 {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
 }

 return msg.wParam ;
}

For such a program I don't even use TCLib.  You can see in the top command line string I used...

/* cl HelloWin.cpp /O1 /Os /GS- /link crt_win_a.obj kernel32.lib user32.lib gdi32.lib winmm.lib       4,096 Bytes */

What I did there was link against crt_win_a.obj instead of TCLib.  First I compiled crt_win_a.cpp into crt_win_a.obj, then linked against that.  Here is the crt_win_a.cpp file I used....

Code: [Select]
//========================================================================================
//                 Developed As An Addition To Matt Pietrek's LibCTiny.lib
//                              By Fred Harris, January 2016
//
// cl crt_win_a.cpp /D "_CRT_SECURE_NO_WARNINGS" /O1 /Os /GS- /c /W3 /DWIN32_LEAN_AND_MEAN
//========================================================================================
#include <windows.h>
#pragma comment(linker, "/defaultlib:kernel32.lib")
#pragma comment(linker, "/nodefaultlib:libc.lib")
#pragma comment(linker, "/nodefaultlib:libcmt.lib")

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);

extern "C" void __cdecl WinMainCRTStartup(void)
{
 int iReturn = WinMain(GetModuleHandle(NULL),NULL,NULL,SW_SHOWDEFAULT);
 ExitProcess(iReturn);
}

I took everything out of my TCLib version that initializes stdio, string, stdlib, and math functions, and just called WinMain().  It shaved another 512 bytes off the executable.  Not much I admit, but I thought it might be worth noting if one wants to squeeze every bit of un-needed bloat out!
« Last Edit: October 04, 2021, 03:49:22 pm by Frederick Harris »

Frederick Harris

  • Newbie
  • *
  • Posts: 47
Re: 64 Bit SDK Programming
« Reply #12 on: October 04, 2021, 04:05:02 pm »
To use that Hello, Windows 95 program and hear Charles say those words you need his HelloWin.wav file which I didn't attach.  Let me know if anyone wants it.  That HelloWin.cpp file is my re-formatted version of Charles' original work.  As much as I love Charles, I have my own coding style which I used to convert his code.  I wonder if I have a touch of OCD sometimes, as I can be ridiculously obsessive about it. 

If you could see your way clear to creating a sub-board for me like on Jose's (now Theo's, I guess) Forum I'd appreciate it greatly Patrice.  You know I like to write Win32 SDK Tutorials and I do have some new stuff.  I guess I'll see if GitHub works out, but I think the format of a Forum works out better.

I checked out that Piano example of yours Patrice and I liked it.  I was tickled to see, in examining it and other things on your Forum that you have been able to make some use of my work - TCLib, my array class, and so on.  I'm glad I'm not just doing it for myself - not to leave out James though.  I know he uses it too.  Last time we conversed was several years back, and I knew you were looking at it at the time, but I didn't know you finally made use of it in any way.  After I retired in April 2018 I kind of went dark for several years.  I had to sell my old home place where my family lived for over a hundred years, and I moved about 1700 miles (about 2700 kilometers I guess) West to the United States State of Colorado.  Built a log cabin at a remote place in the mountains, and spent most of the past three years working on that and my land.  So that's why I went missing.


James Fuller

  • Newbie
  • *
  • Posts: 41
Re: 64 Bit SDK Programming
« Reply #13 on: October 04, 2021, 06:10:01 pm »
Fred,
  I don't think(?) you need to worry about the size of TCLib as long as you use /Gy.
Only the TCLib functions you call will be added to your exe.

This is from my TClib.mak
CC_OPTIONS = /D "_CRT_SECURE_NO_WARNINGS" /O1 /Os /GS- /Gy /c /W3 /DWIN32_LEAN_AND_MEAN

I have not had a chance to look at your new TCLib but I'm on my way right now.


These are the updates I added to mine many primarily to work with BCX

//=====================================================================================
//               Developed As An addition to TCLib by Fred Harris
//                              By James Fuller
//=====================================================================================
// changes for 1.0.2.2
//   02/01/2021
//     added snprintf _snwprintf
// changes for 1.0.2.1
//  01-05-2021
//    added 64bit fseek (_fseeki64) and ftell ( _ftelli64)
//-------------------------------------------------------------------------------------
// changes for 1.0.2.0 starts conversion for use with BCX
//   
//   removed MIN/MAX
//   need to add unicode to time.h
// changes for 1.0.1.9
//   going to add time.h code
//   done 08/05/2019
// need to remove time from math. why is it here?
// changes for 1.0.1.8
//   added ftell
//   LineInput added to Fred's String
// changes for 1.0.1.7
//    07/04/2017
//      added floor,ceil to InitMatch.cpp
//      changed LTrim/RTrim/Trim in Strings.cpp/h to accept a single char to remove along with
//        the white char's already trimed.
// changes for 1.0.1.6
//    04/06/2017
//      added _getch() to stdio.h and InitStdio.cpp for ansi although it's not really necessary
//  changes for 1.0.1.5
//    03/23/2017
//      Added qsort To InitStdLib and stdlib.h
//    03/22/2017
//      Added fabs to InitMath.cpp and Math.h
//    03/19/2017
//      Added _kbhit to InitStdLib.cpp and stdlib.h
//      Added fgetc,fgetwc,ungetc,ungetwc to stdio.h and InitStdio.cpp
//      because I am using the BCX Eof routine. See reason why in
//      this item about feof:
//      http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1046476070&id=1043284351
//      Also added to stdio.h :
//        #define EOF  (-1)
//        #define WEOF ((wint_t)(0xFFFF))
//
//    03/18/2017
//      Added fwrite,fseek to stdio.h and InitStdio.cpp
//    03/17/2017
//      added  "system" to InitStudio.cpp and stdio.h
//      added feof to InitStudio.cpp and stdio.h
//    03/16/2017
//      added ansi support for the isxxxx functions by creating ctypesW.cpp and
//      ctypesA.cpp and changing the make file and tchar.h
//        updated string.h for the above
//      added to InitStdio.cpp
//        fflush(FILE* fp) internally named tcl_fflush
//        fread(void* pBuffer,size_t sise , size_t count,FILE* stream);
//      added to InitStdLib.cpp
//        _splitpath for ansi
//        exit(int) internally named tcl_exit
//      added #define RAND_MAX 0x7fff to math.h
//      added to stdlib.h
//        #define EXIT_SUCCESS 0
//        #define EXIT_FAILURE 1
//        extern void (__cdecl* tcl_exit)(int X);
//           
//  changes for 1.0.1.4
//    03/10/2017
//        changed internal representation of rand and srand to _rand and _srand
//        and let tchar.h do the tansformation from rand,srand in code to
//        calls to _rand and _srand
//    03/09/2017
//      added tan,memmove,_wsplitpath,wcsstr
//      needed to rename wcsstr to _wcsstr in the library?
//        Ok to use wcsstr in code as tchar.h takes translation
//  changes for 1.0.1.3
//    03/08/2017
//      Added sin,cos,acos,asin,atan,atan2,sqrt,time,rand,srand,fmod,fmodf
//      to math.h and InitMath.cpp
//  changes for 1.0.1.2
//    11/30/2016
//      added MIN/MAX macros to stdlib.h
//    10/25/2016
//      added wsystem
//    10/17/2016
//      added aPLib obj file aP_depack_asm_fast renamed to tcl_depack_asm_fast
//    10/13/2016
//      updated stdin     
//  changes for 1.0.1.1
//    09/27/2016
//      added ctypes.cpp
//         int iswspace(wint_t c);
//         int iswupper(wint_t c);
//         int iswlower(wint_t c);
//         int iswdigit(wint_t c);
//         int iswxdigit(wint_t c);
//         int iswpunct(wint_t c);
//         int iswalpha(wint_t c);
//         int iswalnum(wint_t c);
//         int iswprint(wint_t c);
//         int iswgraph(wint_t c);
//         int iswcntrl(wint_t c);
//
//    09/26/2016
//       removing not used/needed files from build directory
//------------------------------------------------------------------------------
// changes for 1.0.1.0
//   09/23/2016
//     added stdin
// changes for 1.0.0.9
//  08/09/2016
//   updated with all of Fred's new codes as of 08/08/2016
//------------------------------------------------------------------------------
// changes for 1.0.0.8
//   added fred's new _atoi64 and atol
//changes for 1.0.0.7
// 
//changes for 1.0.0.6
//  05/19/2016
//    removing Fred's file IO
//changes for 1.0.0.5
//  05/17/2016
//    added isspace
//    added #defines for: tolower, toupper, towlower, towupper to string.h
//      also added references in tchar.h
//    added wmemcpy
//    added Fred's file IO
//------------------------------------------------------------------------------


James

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: 64 Bit SDK Programming
« Reply #14 on: October 04, 2021, 06:14:26 pm »
Fred

I have created your dedicated section.
Patrice
(Always working with the latest Windows version available...)