Visual Studio Notes
Visual Studio Notes
Assorted notes on Microsoft Visual Studio.[1]
Contents
- 1 Projects that create and use DLLs
- 2 Build Problems
- 3 RegEx in Visual Studio
- 4 Class
- 5 Memory Leaks
- 6 Visual Studio IDEs
- 7 Visual Studio Data Structures
- 8 Error Messages
- 9 Folder Selection
- 10 Code Analysis
- 11 CMFCButton
- 12 CStringArray
- 13 CFont
- 14 Data Types
- 15 Division
- 16 Network Programming
- 17 TabControl
- 18 Text Control
- 19 Time libraries
- 20 Dialog Boxes
- 21 CString
- 22 CStringList
- 23 Threads
- 24 Time
- 25 CRichEditCtrl
- 26 Qt
- 27 Internal Links
Projects that create and use DLLs
Microsoft Walkthrough[2]
Be aware that mixing x86 and x64 projects and DLLs will produce link errors, but not notify you the cause was differing architectures.
Build Problems
- Solution build is always "out of date".
If the solution was moved to a new folder the old paths are in the *.tlog files. Delete them and rebuild.
- _WIN32_WINNT not defined. Defaulting to _WIN32_WINNT_MAXVER (see WinSDKVer.h)
Put #include <SDKDDKVer.h> as first line in "StdAfx.h".
- Change Active Configuration from Debug to Release.
Menu->BUILD->Configuration Manager->Active solution Configuration. Select Release.
Linking error: afxnmcd.lib(wincore2.obj) : error LNK2005 In your static library go to the STDAFX.H and comment out following preprocessor macro: #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS
- Multiple Pre and Post Build Events[3]
Separate multiple events with a newline.
- WINDOWS.H included twice in an MFC solution.
Usually "Winsock.h" is loaded somewhere. Add #include <afxsock.h> // MFC socket extensions to stdafx.h.
- Launch time crash while loading m_hIcon in Dlg.cpp constructor.
// m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MAINFRAME));
RegEx in Visual Studio
In C# best to use the built-in regex. In VC++ use something like this:
CString recv_cs; int64_t siz=recv(fd,bufp,1,0); // Try to read one character. char get_c = *bufp; std::string str; std::regex ex ( "[a-zA-Z0-9_ ]"); // AlphaNumeric, numbers, underline and whitespace str = get_c; if( std::regex_match( str, ex ) ) { recv_cs += get_c; // recv_cs.Append does not work for a char. }
Class
- Get the object's class name. CString name_cs = typeid(data).name();
Memory Leaks
Visual Leak Detector for VC++ v2.5.1[4]
Decent leak detector. Has problems with class destructors. It doesn't recognize them.
Install and open vld.h then comment out this:
- Only works on x64 systems.
/* #ifdef __AFXWIN_H__ #error[VLD COMPILE ERROR] '#include <vld.h>' should appear before '#include <afxwin.h>' in file stdafx.h #endif */
Additional Include directory:
C:\Program Files (x86)\Visual Leak Detector\include
Additional Library directory:
C:\Program Files (x86)\Visual Leak Detector\lib\Win32
Place #include "vld.h" in the stdafx.h file as the first executable line.
In the vld.ini file set:
AggregateDuplicates = yes
Add vld include and lib paths to the project. Exit VS. Open VS. Then compile and run. You might have to do this several times to wipe out old memory entries.
- File copy during build
Use a command like:
copy /Y $(SolutionDir)RIL\Lib\<name>.* $(TargetDir)<name>.*
Because VS reads it as one command, not many separated by ";".
Visual Studio IDEs
VS2010 to VS2012
- Open the solution in VS2012 then save the *.sln file as.
- Properties, Change Toolset to v100 from v110
VS2019
- MFC Console. Select Windows Desktop Wizard with the tags; C++, Windows, Desktop, Console, and Library.
Visual Studio Data Structures
Main Article: Visual_Studio_Notes_Lists
Main Article: Visual_Studio_Notes_Stacks
Error Messages
Main Article: Visual_Studio_Notes_Errors
- _WIN32_WINNT not defined. Defaulting to _WIN32_WINNT_MAXVER (see WinSDKVer.h)
- Put '#include <SDKDDKVer.h>' first in the header file.
Folder Selection
MFC, use CFolderPickerDialog.
- Does a folder exist?
CreateDirectory returns a true on creating a directory or false otherwise.
// Can't create the folder, can't create the file either. if (!CreateDirectory( DirectoryPath,NULL)) { if (GetLastError() == ERROR_ALREADY_EXISTS) { // directory already exists ErrorExit( "CreateDirectory: Folder already exits. " ); } else { // creation failed due to some other reason ErrorExit( "CreateDirectory: Failed for other reason. " ); } }
Code Analysis
- C6284: Object passed as... Passing CString but the functions want string. Use
- str.Format ("%s Configuration", (LPCSTR) m_name); from str.Format ("%s Configuration", m_name);
CMFCButton
- An image will appear left to the text.
- Adding an image to a text button pushes the text to the right.
CStringArray
- Always remember that CStringArray has NO copy constructor.
CFont
- Has no copy-constructor. Pass LOGFONT structs instead.
Data Types
C++ __int8 nSmall; // Declares 8-bit integer -128 to 127 __int16 nMedium; // Declares 16-bit integer -32,768 to 32,767 __int32 nLarge; // Declares 32-bit integer -2,147,483,648 to 2,147,483,647 __int64 nHuge; // Declares 64-bit integer -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Division
Integer division is modulus. The following code:
int a_int = 270208992; int b_int = 436270230; int c_int = a_int / b_int; float d_float = a_int / b_int;
Sets "d_float" to 0.0, not 0.6193615182039811.
Cast the division to float sets "d_float" to 0.6193615182039811.
int a_int = 270208992; int b_int = 436270230; int c_int = a_int / b_int; float d_float = (float) a_int / b_int;
Network Programming
TabControl
VC++ TabControl in MFC. Decent tutorial here[7].
1 Create an MFC project. Select "Dialog Based".
2 In the dialog window drag the "Tab Control" tool from the tool box over and set the size. The tab control is empty. Time to flesh it out.
3 Select the tab control. Right-click and "Add Variable". Add a CWnd* and call it m_pwndShow.
4 Select the tab control. Right-click and "Add Event Handler". The wizard will create something like "OnTcnSelchangeTab1". This will execute when a tab is touched.
5 Select the tab control. Right-click and "Add Variable". Add a CTabCtrl variable, m_Tab in this example.
6 Go to "OnInitDialog()" and add initialization code for the tabs.
m_Tab.InsertItem( 0, "Tab One", 0); // First Tab m_Tab.InsertItem( 1, "Tab Two", 1); // Second Tab, etc.
7 Select the Main dialog window, right-click and "Add Class". Name it "ConeDialog" with CDialogEx for the base class. This will show up in *Dlg.h under m_Tab. In the header file make sure IDD points to the correct dialog IDD.
Set the properties as:
- Style = Child
- Border = None
8 Create a variable with the class created above.
9 Select the main dialog and create a CWnd* variable, m_pwndShow. This will display the tab dialogs.
9 Back to OnInitDialog:
// Fetch the m_Tab rectangle CRect rect; m_Tab.GetClientRect( &rect ); // Create the tab dialogs in reverse order. m_TwoDialog.Create( IDD_DIALOG2, &m_Tab ); m_TwoDialog.SetWindowPos( NULL, 5, 25, rect.Width() - 10, rect.Height() - 30, SWP_SHOWWINDOW | SWP_NOZORDER); m_OneDialog.Create( IDD_DIALOG1, &m_Tab ); m_OneDialog.SetWindowPos( NULL, 5, 25, rect.Width() - 10, rect.Height() - 30, SWP_SHOWWINDOW | SWP_NOZORDER); // etc. // Hide all tabs except for the first one. m_configTabDialog.ShowWindow( SW_HIDE ); // Set the display for the first one. m_pwndShow = &m_OneDialog; m_pwndShow->ShowWindow( SW_SHOW );
10 In OnTcnSelchangeTab1 add the following:
// TODO: Add your control notification handler code here if( m_pwndShow != NULL ) { m_pwndShow->ShowWindow( SW_HIDE ); m_pwndShow = NULL; } int index = m_Tab.GetCurSel(); switch(index) { case 0: m_OneDialog.ShowWindow( SW_SHOW ); m_pwndShow = &m_OneDialog; break; case 1: m_TwoDialog.ShowWindow( SW_SHOW ); m_pwndShow = &m_TwoDialog; break; }
Text Control
- To insert a blank line use "\r\n".
Time libraries
- CTime
- CTimeSpan
- COleDateTime
- COleDateTimeSpan
- Shifting focus to the next edit control
// Activates on an entry to StartDOY CWnd *Start_wPtr; CString Start_cs; Start_wPtr = GetDlgItem ( IDC_START_DOY ); Start_wPtr->GetWindowTextA( Start_cs ); // After entering a 3 digit DOY shift the focus to StartHour if( Start_cs.GetLength() == 3 ) { CWnd *CWnd_wPtr = GetDlgItem ( IDC_START_HOUR ); CWnd_wPtr->SetFocus(); }
- Class Name
CAge a(21); CRuntimeClass* prt = a.GetRuntimeClass(); ASSERT(strcmp(prt->m_lpszClassName, "CAge") == 0);
void StartZero() { CEdit *Start_wPtr = NULL; Start_wPtr = (CEdit * ) GetDlgItem (IDC_START_YEAR); Start_wPtr->SetSel( 0, 255 ); Start_wPtr->ReplaceSel("0"); Start_wPtr = (CEdit * ) GetDlgItem (IDC_START_DOY); Start_wPtr->SetSel( 0, 255 ); Start_wPtr->ReplaceSel("0"); Start_wPtr = (CEdit * ) GetDlgItem (IDC_START_HOUR); Start_wPtr->SetSel( 0, 255 ); Start_wPtr->ReplaceSel("0"); Start_wPtr = (CEdit * ) GetDlgItem (IDC_START_MINUTES); Start_wPtr->SetSel( 0, 255 ); Start_wPtr->ReplaceSel("0"); Start_wPtr = (CEdit * ) GetDlgItem (IDC_START_SECONDS); Start_wPtr->SetSel( 0, 255 ); Start_wPtr->ReplaceSel("0"); }
- Path to empty_console debug
C:\Users\Software Engineering\Documents\Visual Studio 2010\Projects\empty_console\Debug
- CString
- Raw initialization is "";
- Daylight Savings Time
Use GetTimeZoneInformation[8] with a TIME_ZONE_INFORMATION[9] struck. The result is:
0 = TIME_ZONE_ID_UNKNOWN
1 = TIME_ZONE_ID_STANDARD
2 = TIME_ZONE_ID_DAYLIGHT
Code example:
TIME_ZONE_INFORMATION TimeZoneInformation = {0}; DWORD TZ_result = GetTimeZoneInformation( &TimeZoneInformation ); printf("\n TZ_result %d \n", TZ_result );
Dialog Boxes
- MFC Dialog Boxes cannot be layered on upon the other. Use a Tab Control.
- MFC Group Boxes are for show only. No way to enclose the controls therein into a class.
Modal dialog boxes, like MessageBox and AfxMessageBox, are modal and suspend execution until the user input responds to the dialog.
-- Default messagebox with variable message MessageBox( NULL, (LPCSTR) "Inside Loop \r\n" + cmd2, NULL, MB_ICONWARNING );
or
AfxMessageBox("Are you sure you want to Set the Recorder time based on this PC's clock?", MB_ICONQUESTION | MB_YESNO);
CString str; str.Format("my string %d", nYrIntValue); AfxMessageBox(str);
Buttons
To create a button with changeable colors use an "MFC Button Control" in the dialog window and set it to:
- Client Edge to true.
- Caption to a space. It won't take a blank.
- Style to No Borders
- Visible to True
In OnInitDialog or another initialization method fetch the pointer and set the color.
CMFCButton * pButton = (CMFCButton*)GetDlgItem(IDC_MFCBUTTON1); pButton->SetFaceColor(RGB(0,100,0),true);
Close(x) button
- Close(x) button uses IDCANCEL, which is a default, you don't have to create it.
- In Dlg.h create:
afx_msg void OnBnClickedCancel(); // make this public
- In Dlg.cpp create:
BEGIN_MESSAGE_MAP( , )
ON_BN_CLICKED(IDCANCEL, &CSlavingDlg::OnBnClickedCancel)
END_MESSAGE_MAP()
- Define the method
void CSlavingDlg::OnBnClickedCancel() { OnBnClickedQuit(); }
CStatic
- To change text: CStatic m_RecordCount.SetWindowText( "shadow" );
- To change background color:
CString
- C6284 bug: During analysis printf will report that CString is incompatible with "%s". But it still works perfectly. Use "(LPCTSTR) CString" to avoid the error.
- #include <atlstr.h>
- Does not have a copy-constructor or "=" operator.
- The debugger displays the text in double quotes. For Example, "BLOOPER" is BLOOPER. When there is a double-double quote, ""BLOOPER"", those really are extra quotes.
- printf - use printf("%S", test_cs.GetString() );
- sprintf - to knit strings together.
char buff[32]; sprintf_s( buff, "%hhu.%hhu.%hhu.%hhu", test_ip.b1, test_ip.b2, test_ip.b3, test_ip.b4);
- CString and printf "%s". Sometimes using printf("%s", CString ); will produce a warning. Instead use printf("%s", CString.GetBuffer() );
- Find method. Use below.
if (a.Find (b) != -1)
CString Formats
CString to CTime conversion
CString m_startTime;
m_startTime.Format ( _T("%04d:%03d:%02d:%02d:%02d.000"), m_startYear, m_startDoy, m_startHours, m_startMinutes, m_startSeconds);
CString and sscanf_s
Use swscanf_s, as in:
swscanf_s ( ca, _T("%d-%d:%d:%d"), &then.tm_yday, &then.tm_hour, &then.tm_min, &then.tm_sec);
CString tokenize because Microsoft was too lame to write it.
The CStringArray must be passed by reference because Microsoft was too lame to write a proper copy-constructor.
See Visual Studio C++ Libraries CharString for an implementation.
CString to Double
CString Temp_cs = "001.001"; double Temp_d = atof( Temp_cs );
CString to Integer
CString cs = _T("278");
int test_int = _wtoi( cs ); // For wide, i.e., 16 bit characters
int test_int = atoi( cs ); // For average, i.e., 8 bit characters
// Test a string for all numeric // trim whitespace cs.Trim(); // length test, must have leading zeros if( cs.GetLength() != 3 ) return false; long result_l = -1; char *stopstring = nullptr; CT2A ascii_num( cs ); // convert to a char string // strtol ignores whitespace front and back. // returns 0 if no conversion can be performed // returns LONG_MAX or LONG_MIN // in an alphanumeric string, stopstring points to // the first non-number characters. result_l = strtol( ascii_num, &stopstring, 10 ); int stopstring_len = strlen( stopstring ); // If alphanumeric, return false if( stopstring_len > 0 ) return false;
Integer to CString
CString cs;
cs.Format( "%d", 5 );
const char * to CString
CString except_cs = CString ( e, strlen( e ) );
except_cs.Append( e );
CString to const char *
Wide character
// Convert using the local code page
CString str(_T("Hello, world!"));
CT2A ascii(str);
TRACE(_T("ASCII: %S\n"), ascii.m_psz);
// Convert to UTF8
CString str(_T("Some Unicode goodness"));
CT2A ascii(str, CP_UTF8);
TRACE(_T("UTF8: %S\n"), ascii.m_psz);
// Convert to Thai code page
CString str(_T("Some Thai text"));
CT2A ascii(str, 874);
TRACE(_T("Thai: %S\n"), ascii.m_psz);
Regular character
char strPass[256]; strcpy_s( strPass, strCommand.GetLength(), CStringA(strCommand).GetString() );
CString: Find one char and delete it
Delete the last comma.
CString buf_cs; buf_cs = "Hello Word,"; Console::WriteLine( buf_cs ); if( buf_cs.GetAt( buf_cs.GetLength() - 1 ) == ',') buf_cs.Delete( buf_cs.GetLength() -1, 1);
CString to std::string and back
CString filename = CString("file_name"); std::string string_s((LPCTSTR) filename);
std::string str ("str_one"); CString cs (str.c_str() );
CStringList
- The equal operator, "=", does not work. But should.
- Pass as & in a parameter
- To copy a CStringList use below.
CStringList list; CStringList listA; list.AddHead( "One" ); list.AddHead( "Two" ); list.AddHead( "Three" ); POSITION pos; for( pos = list.GetHeadPosition(); pos != NULL; ) { CString s = list.GetNext( pos ); printf( "list: %s\n", s ); listA.AddTail( s ); } for( pos = listA.GetHeadPosition(); pos != NULL; ) { CString s = listA.GetNext( pos ); printf( "listA: %s\n", s ); }
- Loop through CStringList, Destructive
while( csList.GetCount() > 0 ) { CString temp_cs = csList.GetHead(); // do something csList.RemoveHead(); }
- Loop through CStringList, Nondestructive
CStringList list; POSITION pos; for( pos = list.GetHeadPosition(); pos != NULL; ) { CString s = list.GetNext( pos ); // do something with CString s. }
Threads
Main Article: Visual Studio Threads
Thread programming with Microsoft MFC C++.
Thread programming _beginthreadex vs. CreateThread.
- If programming under VC++ OR using CRT inside the thread use _beginthreadex since it is C/C++ friendly.
- If programming under C# use CreateThread.
Note: CreateThread does not have a memory leak since about VS2010.
Time
Simplest method for timing a loop in Win32, found thus far.
#include <math.h> double waited = 0.0; // How long we've waited in seconds. int sleeptime = 500; // 500 milliseconds. 0.005 a second while ( <condition is true>) { if ( fmod( waited, 1 ) == 0) // Message once every 1 second. <do something>; else if (waited >= 3.0 ) // waited 3 seconds <do something>; ::Sleep( sleeptime ); // Sleep a little while. waited += 0.005; // increment waited }
Time/milliseconds on Windows
Keeping time on Win32 can be accomplished with chrono or SYSTEMTIME struct. SYSTEMTIME is easier because it can be formatted with COleDateTime and keeping the millisecond resolution in the SYSTEMTIME struct.
Using Win32/SYSTEMTIME/GetSystemTime() gives the same resolution as chrono at the millisecond level. Visual Studio Notes Millisecond Time Test verified this.
Millisecond Time Test
Used the code below to test millisecond accuracy with chron and SYSTEMTIME calls. Both returned 140ms.
// Time2012.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <chrono> #include <time.h> #include <stdlib.h> #include <stdio.h> #include <iostream> // long operation to time long long fib(long long n) { if (n < 2) { return n; } else { return fib(n-1) + fib(n-2); } } int main(int argc, char* argv[]) { // struct to request the time SYSTEMTIME oSytemTime; // getting the system time (Greenwich Mean Time); GetLocalTime () is possible too GetSystemTime (&oSytemTime); // get now for chrono auto start_time = std::chrono::high_resolution_clock::now(); long long input = 32; long long result = fib(input); // struct to request the time SYSTEMTIME oSytemTime_End; // getting the stop time GetSystemTime (&oSytemTime_End); auto end_time = std::chrono::high_resolution_clock::now(); // chron difference auto time = end_time - start_time; // SYSTEMTIME difference int systime_diff = oSytemTime_End.wMilliseconds - oSytemTime.wMilliseconds; std::cout << "result = " << result << '\n'; // printing the time with milliseconds std::cout << " chrono took " << time/std::chrono::milliseconds(1) << "ms to run.\n"; printf(" SYSTEMTIME took: %d ms\n", systime_diff ); getchar(); return 0; }
Time and Date Formats
Time and Date Formats
The time and date now are: %A, %B %d, %Y, %H:%M:%S
The time and date now are: Friday, October 05, 2018, 17:10:52
The date now are: %A, %B %d, %Y
The date now are: Friday, October 05, 2018
Julian Day, Hour, Minute, Second: %j:%H:%M:%S
Julian Day, Hour, Minute, Second: 278:17:10:52
Year, Julian Day, Hour, Minute, Second: %Y:%j:%H:%M:%S
Year, Julian Day, Hour, Minute, Second: 2018:278:17:10:52
Since Epoch began. Total days: %D, hours: %H, mins: %M, secs: %S
Since Epoch began. Total days: 43378, hours: 17, mins: 09, secs: 52
time_command format: %j-%H:%M:%S
time_command format: 278-17:10:52
date_command format: %Y-%m-%d
date_command format: 2018-10-05
Time Format Specification
Specifier | Replaced by | Example |
---|---|---|
%a | Abbreviated weekday name | Thu |
%A | Full weekday name | Thursday |
%b | Abbreviated month name | Aug |
%B | Full month name | August |
%c | Date and time representation | Thu Aug 23 14:55:02 2001 |
%C | Year divided by 100 and truncated to integer (00-99) | 20 |
%d | Day of the month, zero-padded (01-31) | 23 |
%D | Short MM/DD/YY date, equivalent to %m/%d/%y | 08/23/01 |
%e | Day of the month, space-padded ( 1-31) | 23 |
%F | Short YYYY-MM-DD date, equivalent to %Y-%m-%d | 2001-08-23 |
%g | Week-based year, last two digits (00-99) | 01 |
%G | Week-based year | 2001 |
%h | Abbreviated month name (same as %b) | Aug |
%H | Hour in 24h format (00-23) | 14 |
%I | Hour in 12h format (01-12) | 02 |
%j | Day of the year (001-366) | 235 |
%m | Month as a decimal number (01-12) | 08 |
%M | Minute (00-59) | 55 |
%n | New-line character ('\n') | |
%p | AM or PM designation | PM |
%r | 12-hour clock time | 02:55:02 pm |
%R | 24-hour HH:MM time, equivalent to %H:%M | 14:55 |
%S | Second (00-61) | 02 |
%t | Horizontal-tab character ('\t') | |
%T | ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S | 14:55:02 |
%u | ISO 8601 weekday as number with Monday as 1 (1-7) | 4 |
%U | Week number with the first Sunday as the first day of week one (00-53) | 33 |
%V | ISO 8601 week number (01-53) | 34 |
%w | Weekday as a decimal number with Sunday as 0 (0-6) | 4 |
%W | Week number with the first Monday as the first day of week one (00-53) | 34 |
%x | Date representation | 08/23/01 |
%X | Time representation | 14:55:02 |
%y | Year, last two digits (00-99) | 01 |
%Y | Year | 2001 |
%z | ISO 8601 offset from UTC in timezone (1 minute=1, 1 hour=100) | |
If timezone cannot be determined, no characters | +100 | |
%Z | Timezone name or abbreviation | |
If timezone cannot be determined, no characters | CDT | |
%% | A % sign | % |
- COleDateTime
Verification is month 1 based, not zero based as in the documentation.
The fix is:
tTrigger = COleDateTime( m_triggerYear, month_int + 1, day_int, m_triggerHours, m_triggerMinutes, m_triggerSeconds );
Not the +1 in the month field.
CRichEditCtrl
Initializing is a bit different.
1. In Constructor() add.
AfxInitRichEdit2();
2. In OnInitDialog() add.
m_AcuTelPort.SetEventMask(m_AcuTelPort.GetEventMask() | ENM_CHANGE);
Qt
- Qt VS2012 plugins has the following SQL drivers, QSQLITE QMYSQL QMYSQL3 QODBC QODBC3 QPSQL QPSQL7. But it does not have QOCI, the Oracle driver. The Oracle driver must be built because every Oracle DB version uses a different driver.
- The compiled drivers are installed in: C:\Qt\Qt5.5.1\5.5\msvc2012\plugins\sqldrivers. This is also where VS2012 in Debug Mode looks for the drivers. Trying to point VS2012 elsewhere fails.
Internal Links
Parent Article: Main Page