Windows C++ GUI

Pages: 123
Hi Guys,
I'm new to this Forum and I am only just getting back into C++ programming. I used to program real-time data acquisition systems using C++ and Windows API nearly 20 years ago!!! Therefore please forgive me if I use incorrect terminology below:

I now want to program a GUI based application that will control a USB connected motor control and data acquisition system that needs to be sent commands and receive positional information in real time that then needs to be dumped to disk in CSV format for later retrieval and display on the PC.

To display the data will require some quite complex mathematics prior to programming a visual display for the PC. To break this into more manageable chunks we will first of all import the CSV data into an Excel spreadsheet and analyse it there, once the motor control and data acquisition program has stored it all to disk.

I have in mind a GUI to hold all the initialisation parameters, filename, USB port setup data etc. etc. in 3 forms:
Form 1. Basic setup data that will always be the same for any particular installation.
Form 2. Motor control initialisation parameters that may be varied from run to run at the same location.
Form 3. Reading the captured data displaying it on a form all formatted into 3 or four columns with time and date information.

I have in my mind a nice looking form with several tabs to hold the various parameters. I would want a graphic incorporated to hold the company's logo.

I have just done a C++ refresher course by Mark Gingrass who recommended this forum for more info. so I am hoping that you guys can help point me in the right directions:

1. A Windows reference bible that gives a high level overview of how a program interacts with Windows 10.

2. Somewhere that shows what different built-in window classes are available especially with tabs.

3. Information on how to interface to a device over USB

4. How to write and read data to/from the HDD at a fairly high rate.

5. How to tabulate data in a form on one of the GUI tabs

6. A good reference on how to display graphical data points on a graph like display. (NOT gaming, this will be far slower).

I am using Visual Studio 2015 Community for practice but will then purchase the Pro version once I am up to speed and ready to start programming the application for real.

Many thanks for any help and advice you can give me.





Last edited on
Any number of ways to go about it using either the Windows Api directly or various Class Frameworks, i.e., MFC, .NET, etc.

First I have to say that you did an excellect job of presenting your question. I'm sure your app will turn out well.

I've posted material on Win API SDK style coding starting with installment #37 here...

http://www.jose.it-berater.org/smfforum/index.php?topic=3389.0

If you choose the Api approach your idea with three seperate forms sounds like a good idea to me. Note that the best way to go about this is with three seperate Window Classes. This will necessitate a seperate Window Procedure for each Form, which is what you want. For each Form you want to handle messages specific for that form. You also might have another Window Procedure and Class for a 'Start Up' Form or introductory Form.

I can help with Tab Controls if you like. They aren't too hard to get going. The thing I can't help you with are the technical details about USB code. I've never worked with it and havn't a clue.
By the way, if you are interested I can provide C++ code that shows how to read/write data directly to Excel instead of *.csv files as an intermediary. Don't know if that fits in with what you are doing - just mentioning it. Actually, there are two ways to do it 1) ODBC, 2) COM.
Last edited on
Hi Freddie and Thomas,

Many thanks for responding to my question about the GUI application for motor control and data acquisition and thanks for the compliment Freddie!

I was assuming that I would have one window with a form with three tabs as explained above rather than have 3 separate forms. I thought that I remembered programming something like that 20 years ago. I've probably misunderstood what you are saying as my Windows programming is so ancient!

Freddie:
I have taken a look at your ProgEx37 -- Windows GUI Programming; Basic Template Program With Discussion and just remembered why I stopped programming Windows apps. all those years ago, UNICODE being a classic example!!!

In your example you are using the Win API I believe rather than MFC. Is there a reason for this, e.g. speed of operation? From your posting I was assuming that MFC libraries would speed up development, certainly of the GUI side of things

I am using the Visual Studio 15 Community version and there appears to be many things missing out of it that the online MS tutorials refer to, e.g. "C++ Windows Forms" which does not help a rusty like me while trying to follow along!

Freddie & Thomas:
Regarding the CSV file, that was to put a nice intermediate step in place so that we can analyse the data while the application that will eventually display it, following all the data processing, is still being developed. I was intending simply formatting the data into columns and displaying it in a Form while the system was being used, just to give a rapid check that everything is working correctly before storing it for later retrieval, i.e. a scrolling screen of data that the operator could keep an eye on. The data rate to the screen would typically be one row of data every few seconds with data points of ddd.d degrees of azimuth from North and dd.d degrees of declination from horizontal plus the arrival and departure times hh:mm:ss at each location. This would be printed once the motor controller confirmed it had reached the data sampling position.

Saying that, having it also directly write an Excel file would greatly improve the program's ease of use and reduce the backend data crunching work BUT it will take a while to code it all up so first things first. The motor control and data acquisition interface.

The other reason for the CSV approach is that the acquired data needs to be synchronised to another CSV file that is being generated by an older data acquisition system running on an old Win XP machine using the time stamps with each data set.


Freddie:
I was assuming that the USB interface could be bound to an iostream (or something like that) which could then be read and written like std::cin/std::cout etc.

Is it possible to PM on this forum as this could get very complicated and maybe too detailed for the general Forum.

Thanks to you both
Ian

I was assuming that I would have one window with a form with three tabs as explained above rather than have 3 separate forms. I thought that I remembered programming something like that 20 years ago. I've probably misunderstood what you are saying as my Windows programming is so ancient!


Ahhh! I understand you now! Yes, what you said about the Tab Control would work good I think. Maybe your comment about three forms threw me off. Frequently I write apps with multiple top level windows.

Thing is though, even with multiple tabs you should have multiple window procedures - one for each tab. It modularizes the code.

I'm interested in what Thomas said about reading Excel files directly in binary format. I'll need to check out that link. I'm aware of folks having done that in the past, and I believe there was/is a *.biff format used, which folks had deciphered and used. Its kind of a 'loose end' for me that I never looked into it. My recollection of having entered into discussions with folks about this in the distant past was that the code executed very quickly. Whereas with COM or ODBC the data transfer rate between your code and the Excel Spreadsheet was horribly slow.

A big issue you are going to have to face about immediately is whether you want to use Win Api, MFC, or .NET. Another issue is that I'm seeing for sure a multi-threaded app here. The reasons for this are many, but the paramount reason for this is that you are talking a continuous display of real time data while processing is taking place. It isn't possible to have real time graphics output simultaneous with real time data processing. It can work if the data processing is trievally simple and fast - like a tenth of a second or less, but if it is like a second or two or three or whatever you'll end up with real jerky display of data. A program can only do both seeming simultaneously if thread switching is done.

I have pretty easy code showing how to do this, i.e., example apps, but its all SDK. If you go the MFC or .NET route I'll have to bow out of the discussion because I don't know anything about that. I know Thomas has posted MFC code though.

In terms of why I do only SDK apps .... I was never able to figure out MFC. It was just too hard for me and I didn't like it. Simple as that. What I believe is that everyone's mind is 'wired' a little differently, and what one person might find easy another might find hard. For me SDK style coding was real easy. MFC made no sense to me. But of course it might be completely opposite for you.

The other issue is that I code in a pretty lot of different programming languages, for example PowerBASIC for one, and SDK style transfers exactly over to that. So using just one coding paradigm allowed me to code in multiple programming languages. MFC is unique to Microsoft C++.

Yes, the PM capability works here.
Last edited on
Hi Freddie,
Just PMed you.

Regards
Ian
Here are some directions for starting a Win32/64 Api SDK style project using Visual Studio Community 2015. I wrote these up last February after purchasing a new laptop and installing the above noted software...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1)  Start Visual Studio;

2)  Execute...

    File  >>  New  >> Project;

3)  In 'New Project' Dialog Choose Win32 Project; 

4)  Fill In Name, e.g.,           Form1
    Fill In Location, e.g.,       C:\Users\frede\Code\VC15\Forms\
    Fill In Solution Name, e.g.,  Form1

    Uncheck 'Create directory for solution
    Click 'OK' Button

5)  The 'Win32 Application Wizard - Form1 presents itself.  In left pane under 'Overview'
    click 'Application Settings'.  In right pane choose 'Windows application'.  Under that
    put check in check box 'Empty Project'.  That will prevent Visual Studio from writing 
    your code for you.  Click Finish;

6)  At this point you don't have an editor window to type code so tell Visual Studio to
    add a *.cpp source code file to the project.  Go to the File menu and execute....

    File >> New >> File...

    ...and the New File Dialog Box Appears.  In the left pane highlight 'Visual C++ and in 
    right pane you should see choices for*.cpp files and *.h files.  Choose C++ file.

7)  You should then have a source code file named Source1.cpp.  Go to the File menu and
    rename it to something else such as Main.cpp by executing 'Save As...'

8)  You're finally done.  Type or past code into editor. 


If that seems involved my opinion is that it is. I stopped using IDEs (Integrated Development Environments (specifically Visual Studio) long ago.

Anyway, at this point you need code to paste into the editor. If you have Petzold's book any of his programs should work as is or with easy modifications. However, next post is a minor modification of a Windows CE app I'm working on now. All it is is a skeleton more or less that puts up a window with a tab control on it, and the tab control has four tabs. I'll put code in it for the tab windows a bit later, but wanted to get you started on this.

Also, you'll need to use the file menu selection to add an *.h file to the project. Note that you don't have to create a blank file as noted above. If you have a file you can just put it in the directory where your work is and use the selection somewhere something to the effect ...Add Existing item...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// cl Main.cpp /O1 /Os /FeForm1.exe /GS- TCLib.lib kernel32.lib user32.lib comctl32.lib
// cl Main.cpp /O1 /Os /MT /FeForm1.exe kernel32.lib user32.lib comctl32.lib
//   6,144 Bytes VC19 (Visual Studio 2015) x64 UNICODE TCLib.lib  Linkage
// 123,904 Bytes VC19 (Visual Studio 2015) x64 UNICODE LIBCMT.LIB Linkage
//#define TCLib
#ifndef UNICODE
   #define UNICODE
#endif
#ifndef _UNICODE
   #define _UNICODE
#endif   
#include <windows.h>
#include <commctrl.h>
#ifdef TCLib
   #include "stdio.h"
   #include "tchar.h"
#else
   #include <cstdio>
   #include <tchar.h>
#endif 
#include "Form1.h"


LRESULT CALLBACK fnWndProc_Landscape(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
   case WM_CREATE:
     {
        return 0;
     }
   case WM_DESTROY:
     {
        return 0;
     }
 }

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


LRESULT CALLBACK frmExtRegenTab_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 return (DefWindowProc(hwnd,msg,wParam,lParam));
}


LRESULT CALLBACK fnWndProc_Residuals(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 return (DefWindowProc(hwnd,msg,wParam,lParam));
}


LRESULT CALLBACK fnWndProc_Interference(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 return (DefWindowProc(hwnd,msg,wParam,lParam));
}


LRESULT __stdcall fnWndProc_OnCreate(WndEventArgs& Wea)
{
 INITCOMMONCONTROLSEX icx;
 BOOL blnReturn=FALSE;
 HWND hTabCtl=NULL;
 HWND hTabs=NULL;
 WNDCLASS wc;
 TCHAR* szTabs[]=
 {
   _T("Landscape"),
   _T("ExtRegen"),
   _T("Residuals/Oak"),
   _T("Interference")
 };
 RECT rcForm;
 TCITEM tie;


 fp=fopen("Output.txt","w");
 if(!fp)
    return -1;
 fprintf(fp,"Entering fnWndProc_OnCreate()\n");
 fprintf(fp,"  Wea.hWnd       = %p\n",Wea.hWnd);
 icx.dwSize=sizeof(icx);
 icx.dwICC=ICC_TAB_CLASSES;
 blnReturn=InitCommonControlsEx(&icx);
 fprintf(fp,"  blnReturn      = %d\n",blnReturn); 
 if(blnReturn)
 {
    // WC_TABCONTROL 
    //GetClientRect(Wea.hWnd,&rcForm);
    //fprintf(fp,"  rcForm.right   = %u\n",rcForm.right);
    //fprintf(fp,"  rcForm.bottom  = %u\n",rcForm.bottom);
    hTabCtl=CreateWindow(WC_TABCONTROL, _T(""),WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,10,10,465,340,Wea.hWnd,(HMENU)IDC_TAB,Wea.hInst,NULL);
    fprintf(fp,"  hTabCtl        = %p\n",hTabCtl);

    // Register Tab Classes
    wc.lpszClassName=szTabs[0];                  wc.lpfnWndProc=fnWndProc_Landscape;
    wc.style=0;                                  wc.hIcon=NULL;     
    wc.hInstance=Wea.hInst;                      wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=0;
    wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
    RegisterClass(&wc);

    wc.lpszClassName=szTabs[1];                  wc.lpfnWndProc=frmExtRegenTab_WndProc;
    wc.style=0;                                  wc.hIcon=NULL;     
    wc.hInstance=Wea.hInst;                      wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=2*sizeof(void*);
    wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
    RegisterClass(&wc);

    wc.lpszClassName=szTabs[2];                  wc.lpfnWndProc=fnWndProc_Residuals;
    wc.style=0;                                  wc.hIcon=NULL;
    wc.hInstance=Wea.hInst;                      wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=sizeof(void*);
    wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
    RegisterClass(&wc);

    wc.lpszClassName=szTabs[3];                  wc.lpfnWndProc=fnWndProc_Interference;
    wc.style=0;                                  wc.hIcon=NULL;     
    wc.hInstance=Wea.hInst;                      wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=sizeof(void*);
    wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
    RegisterClass(&wc);

    for(size_t i=0; i<sizeof(szTabs)/sizeof(szTabs[0]); i++)
    {
        tie.mask    = TCIF_TEXT | TCIF_IMAGE;
        tie.iImage  = -1;
        tie.pszText = szTabs[i];
        TabCtrl_InsertItem(hTabCtl, i, &tie);
    }
 }
 fprintf(fp,"Leaving fnWndProc_OnCreate()\n\n");

 return 0;
}


LRESULT __stdcall fnWndProc_OnCommand(WndEventArgs& Wea)
{
 fprintf(fp,"Entering fnWndProc_OnCommand()\n");
 fprintf(fp,"  Wea.hWnd = %p\n",Wea.hWnd);
 fprintf(fp,"Leaving fnWndProc_OnCommand()\n\n");

 return 0;
}


LRESULT __stdcall fnWndProc_OnNotify(WndEventArgs& Wea)
{
 //fprintf(fp,"Entering fnWndProc_OnNotify()\n");
 //fprintf(fp,"  Wea.hWnd = %p\n",Wea.hWnd);
 //fprintf(fp,"Leaving fnWndProc_OnNotify()\n\n");

 return 0;
}


LRESULT __stdcall fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 fprintf(fp,"Entering fnWndProc_OnDestroy()\n");
 fprintf(fp,"  Wea.hWnd = %p\n",Wea.hWnd);
 fprintf(fp,"Leaving fnWndProc_OnDestroy()");
 fclose(fp);
 PostQuitMessage(0);

 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].Code==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)
{
 TCHAR szClassName[]=_T("Form1");
 HWND hWnd=NULL; 
 DWORD dwStyle;
 WNDCLASS wc;
 MSG msg;
 
 wc.hInstance=hIns;                       wc.lpszClassName=szClassName;
 wc.lpfnWndProc=fnWndProc;                wc.style=0;
 wc.hIcon=NULL;                           wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.lpszMenuName=NULL;                    wc.cbClsExtra=0;
 wc.cbWndExtra=0;                         wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;
 RegisterClass(&wc);
 dwStyle=WS_OVERLAPPED|WS_SYSMENU|WS_VISIBLE;
 hWnd=CreateWindow(szClassName,_T("Windows App"),dwStyle,400,400,500,400,HWND_DESKTOP,0,hIns,0);
 if(hWnd)
 {
    ShowWindow(hWnd,iShow);
    while(GetMessage(&msg,NULL,0,0))
    {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
    }
 }

 return msg.wParam;
}


Form1.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef Form1_h
#define Form1_h

FILE*    fp =                  NULL;
#define  dim(x)                (sizeof(x) / sizeof(x[0])) 
#define IDW_LANDSCAPE_TAB      13000
#define IDW_SIX_FOOT_TAB       13005
#define IDW_RESIDUALS_TAB      13010
#define IDW_INTERFERENCE_TAB   13015
#define IDC_TAB                15000


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


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


LRESULT fnWndProc_OnCreate     (WndEventArgs& Wea);
LRESULT fnWndProc_OnCommand    (WndEventArgs& Wea);
LRESULT fnWndProc_OnNotify     (WndEventArgs& Wea);
LRESULT fnWndProc_OnDestroy    (WndEventArgs& Wea);


const EVENTHANDLER             EventHandler[]=
{
 {WM_CREATE,                   fnWndProc_OnCreate},
 {WM_COMMAND,                  fnWndProc_OnCommand},
 {WM_NOTIFY,                   fnWndProc_OnNotify},
 {WM_CLOSE,                    fnWndProc_OnDestroy}
};

#endif 


The above program opens a log file in fnWndProc_OnCreate() to log debug info. After you close the program you can open "Output.txt" to see what's in it.

Ignore the TCLib stuff at top. There is a commented out #define at top. I build most of my code with my own custom C Runtime code so as to produce really small executables. That's what that is all about. Let me know if it works for you. I can update it later to show how to create the tab windows and put child window controls on them. Just wanted to get you started!
Last edited on
freddie1 said:
If that seems involved my opinion is that it is. I stopped using IDEs (Integrated Development Environments (specifically Visual Studio) long ago.


Since VS2012(?) you can export your C++ project as a template, so the next time it's much easier.

Since VS2012(?) you can export your C++ project as a template, so the next time it's much easier.


That would help a lot, especially if it exported into the template all the various settings that might have been changed from defaults in the project properties, i.e., compiler and linker settings, etc.
Hi Freddie and Thomas,
Thanks for taking an interest in my programming foray back into the world of Windows C++ programming. I have to say that I am a little rusty after nearly 20 years away from it. Imagine my surprise to see that the Windows Bible according to Petzold is still being quoted as the de facto standard for Windows API programming, although my copy was probably Edition 0.5!

Freddie - you have been most kind in advising me and for posting the above Visual Studio instructions and the code.

Unfortunately it is that time of year in the UK when we have to prepare Income Tax Returns and pay any outstanding tax before Jan 31st or get fined for late filing .....

I have therefore been a bit pre-occupied yesterday and today and consequently I have not yet had time to try all this out but I have taken a local copy already to start dropping into Studio and then finding my way around where everything goes and what code does what. Have to say though that it looks a lot less convoluted than the MFC stuff I was trying to fight my way around. I've even spotted the WinMain function which, as hard as I tried, I could not find in the MFC program constructed by Studio in response to a simple form with one static text, one edit box and two check boxes.

Much appreciated! I will let you know how I get on later today (Tuesday).

Regards
Ian
The Windows API has not changed that much over the years.
Here is a online copy of Petzold's "Bible" 5th ed.
https://www-user.tu-chemnitz.de/~heha/petzold/petzold.htm

However what has changed much in the last 20 years is C++.

Here is a way to use some modern C++ in an WIN API program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <Windows.h>
#include <tchar.h>
#include <map>
#include <functional>

const int MSG_HANDLED = 0;

LRESULT OnCreate(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT OnPaint(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT OnDestroy(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

typedef std::function<LRESULT(HWND, UINT, WPARAM, LPARAM)> MessageHandler;

const std::map<UINT, MessageHandler> Handlers = 
{
  {WM_CREATE, OnCreate},
  {WM_PAINT, OnPaint},
  {WM_DESTROY, OnDestroy}
};


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{
  auto it = Handlers.find(msg);
  if (it != Handlers.end()) 
    return it->second(hwnd, msg, wParam, lParam);

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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{
	WNDCLASSEX wcex;
	wcex.cbClsExtra = 0;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.cbWndExtra = 0;
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW);
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wcex.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
	wcex.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
	wcex.hInstance = hInstance;
	wcex.lpfnWndProc = WndProc;
	wcex.lpszClassName = "WindowClass";
	wcex.lpszMenuName = nullptr;
	wcex.style = 0;

	if (!RegisterClassEx(&wcex)) 
  {
		MessageBox(nullptr, _T("Window class registration failed!"), _T("Error"), MB_OK | MB_ICONERROR);
		return 1;
	}

	HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("WindowClass"), _T("Window Title"),
		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, nullptr,
		nullptr, hInstance, nullptr);

	if (!hwnd) 
  {
		MessageBox(nullptr, _T("Window creation failed!"), _T("Error"), MB_OK | MB_ICONERROR);
		return 1;
	}


	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	MSG msg;
	while (GetMessage(&msg, hwnd, 0, 0) > 0)
  {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

LRESULT OnCreate(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  OutputDebugString(_T("Entering OnCreate"));
  return MSG_HANDLED;
}
LRESULT OnPaint(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  OutputDebugString(_T("Entering OnPaint"));
  PAINTSTRUCT ps = {0};
  TCHAR szMsg[] = _T("Hello world");

  HDC hDC = BeginPaint(hwnd, &ps);
  
  TextOut(hDC, 10, 10, szMsg, 11);
  
  EndPaint(hwnd, &ps);

  return MSG_HANDLED;
}
LRESULT OnDestroy(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  OutputDebugString(_T("Entering OnDestroy"));
  PostQuitMessage(0);
  return MSG_HANDLED;
}
Hi Thomas,
Yes thanks, I had found the online version of Petzold's Bible but where does one find all the more modern stuff then?

Just about to follow through Freddie's posting now! So strong cup of coffee first, during and afterwards!

Ian
Hi Freddie,
Just followed through your instructions but it did not compile as there were many missing files that Studio could not resolve. I also got several error messages similar to the one below:


Error C2373 'fnWndProc_OnCreate': redefinition; different type modifiers Freddie3 d:\users\user\documents\visual studio 2015\projects\freddie3\source.cpp

I tried 3 new projects before I started another project when I re-checked the create directory for solution and then in the Solution Explorer I right clicked on the "Header Files" and "Source Files" and inserted the appropriate code by copying and pasting your code above directly into the "FreddieForm1" .h and .cpp files.

This then compiled and resulted in a blank FreddieForm1 with two tabs labelled File and Help with your Version 1 copyright in it.

So at least I can now start finding my way around your code and the Visual Studio interface.

Thanks
Ian
Hi Thomas,
I have just checked out these two books. They do indeed both look very good!

However, it looks like the Programming Principles book would be better suited for me trying to re-grab the handle on C++ programming of Windows10 applications using MS Visual Studio. I note that Stroustrup actually gives a guide on this in an appendix.

However, I see that it also uses C++11 and C++14. In my day it was either C or C++ what are these new variants of C++?

Ian

Error C2373 'fnWndProc_OnCreate': redefinition; different type modifiers Freddie3 d:\users\user\documents\visual studio 2015\projects\freddie3\source.cpp

I tried 3 new projects before I started another project when I re-checked the create directory for solution and then in the Solution Explorer I right clicked on the "Header Files" and "Source Files" and inserted the appropriate code by copying and pasting your code above directly into the "FreddieForm1" .h and .cpp files.

This then compiled and resulted in a blank FreddieForm1 with two tabs labelled File and Help with your Version 1 copyright in it.


Something is terribly wrong Ian. Your description above doesn’t sound to me anything like the code I posted. The code I posted creates a small Form with one Tab Control on it. The Tab Control has four tabs labeled …

"Landscape"
"ExtRegen"
"Residuals/Oak"
"Interference"

I think I know what the problem might be though (at least one of them). I mostly only build x64 binaries. If you built that x86, you might get an error like that because I went and stuck …

LRESULT CALLBACK

…in front of the three message handling functions, but forgot the CALLBACK part in front of the declarations in Form1.h (CALLBACK is a #define of __stdcall). That would build fine in x64 (what I trested) but would cause problems in x86 because it actually uses all these different stack protocols, i.e., __stdcall, __cdecl, etc., ad infinitium. Here is an updated Form1.h…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef Form1_h
#define Form1_h

FILE*    fp =                         NULL;
#define  dim(x)                       (sizeof(x) / sizeof(x[0])) 
#define IDW_LANDSCAPE_TAB             13000
#define IDW_SIX_FOOT_TAB              13005
#define IDW_RESIDUALS_TAB             13010
#define IDW_INTERFERENCE_TAB          13015
#define IDC_TAB                       15000


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


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


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


const EVENTHANDLER                    EventHandler[]=
{
 {WM_CREATE,                          fnWndProc_OnCreate},
 {WM_COMMAND,                         fnWndProc_OnCommand},
 {WM_NOTIFY,                          fnWndProc_OnNotify},
 {WM_DESTROY,                         fnWndProc_OnDestroy}
};

#endif 


x64 only has one calling convention, which makes stuff simpler. I’m really sorry about that Ian.

Sounds to me like you are really struggling with the IDE. Didn’t I tell you about that (several times)? Let me show you how simple it can be. I created this directory on my Windows 10 laptop…

 
C:\Code\eVC4\Forms\Ian


In that folder I put the code I posted named Main.cpp and Form1.h. Then I executed the shortcut to the…

VS 2015 x64 Native Tools Command Prompt

…which the installation of Visual Studio Community 2015 put on my Start Menu. I used the Change Directory Command – cd, to change to the directory I created now containing those two files referenced above. Then I execute the command line string on Line #2 of the Main.cpp file. Here is a full screen dump of the build, followed by a dir command to show the contents of my directory after the build…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
C:\Code\eVC4\Forms\Ian>cl Main.cpp /O1 /Os /MT /FeForm1.exe kernel32.lib user32.lib comctl32.lib
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

Main.cpp
Microsoft (R) Incremental Linker Version 14.00.23506.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:Form1.exe
Main.obj
kernel32.lib
user32.lib
comctl32.lib

C:\Code\eVC4\Forms\Ian>dir
 Volume in drive C is Windows
 Volume Serial Number is 3230-2F4C

 Directory of C:\Code\eVC4\Forms\Ian

01/10/2017  09:21 AM    <DIR>          .
01/10/2017  09:21 AM    <DIR>          ..
01/10/2017  09:21 AM           123,904 Form1.exe
01/10/2017  09:11 AM             1,187 Form1.h
01/10/2017  09:20 AM             6,375 Main.cpp
01/10/2017  09:21 AM            11,981 Main.obj
               4 File(s)        143,447 bytes
               2 Dir(s)  890,202,046,464 bytes free

C:\Code\eVC4\Forms\Ian>


As seen above there were no errors or warnings, and I ended up with a 123,904 byte executable. That would be a stand alone executable capable of being run on any relatively modern computer without having to distribute any ‘redistributables’ or use a setup program, because the necessary run time code was statically linked into the binary. That’s what the /MT switch in the command line string did. However, it would have done the same thing without it because Microsoft recently did an about face on that and the default linkage is now /MT.

I hate bloatware with a passion, and unfortunately that’s what C++, modern or otherwise, morphed into. I added a few necessary files to the folder, including my very own TCLib.lib, which is my custom version of C Runtime code, and re-built the program against my TCLib. Here are the results of that…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
C:\Code\eVC4\Forms\Ian>cl Main.cpp /O1 /Os /FeForm1.exe /GS- TCLib.lib kernel32.lib user32.lib comctl32.lib
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

Main.cpp
Microsoft (R) Incremental Linker Version 14.00.23506.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:Form1.exe
Main.obj
TCLib.lib
kernel32.lib
user32.lib
comctl32.lib

C:\Code\eVC4\Forms\Ian>dir
 Volume in drive C is Windows
 Volume Serial Number is 3230-2F4C

 Directory of C:\Code\eVC4\Forms\Ian

01/10/2017  09:25 AM    <DIR>          .
01/10/2017  09:25 AM    <DIR>          ..
01/10/2017  09:25 AM             6,144 Form1.exe
01/10/2017  09:11 AM             1,187 Form1.h
01/10/2017  09:25 AM             6,373 Main.cpp
01/10/2017  09:25 AM            10,175 Main.obj
08/01/2016  07:41 AM             1,313 stdio.h
01/08/2017  04:42 PM             1,959 tchar.h
01/05/2017  06:37 PM            41,320 TCLib.lib
               7 File(s)         68,471 bytes
               2 Dir(s)  890,201,792,512 bytes free

C:\Code\eVC4\Forms\Ian>


As you can see I shaved off about 118,000 bytes which leaves me with a 6K stand alone x64 UNICODE executable which is more to my liking.

After I posted that code I worked on it some more for you and removed one of the tabs and named them in accordance with your project. Did a few other things too. I’ll post that shortly. Sorry about that CALLBACK stuff. I really am.

Last edited on

what are these new variants of C++?


An attempt to turn it into C#.
what are these new variants of C++?

Here is a post with some links to new C++
http://www.cplusplus.com/forum/beginner/206091/
Pages: 123