You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* typo: Double word "in" Escaped the `_` because the editor marked all that text as starting italics * Update porting-guide-spy-increment.md - Fix some additional formatting issues.
Copy file name to clipboardExpand all lines: docs/porting/porting-guide-spy-increment.md
+13-11Lines changed: 13 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -36,7 +36,7 @@ Upon building a newly converted project, one of the first things you'll often fi
36
36
37
37
One of the files that couldn't be found in Spy++ was verstamp.h. From an Internet search, we determined that this came from a DAO SDK, an obsolete data technology. We wanted to find out what symbols were being used from that header file, to see if that file was really needed or if those symbols were defined elsewhere, so we commented out the header file declaration and recompiled. It turns out there is just one symbol that is needed, VER_FILEFLAGSMASK.
@@ -64,7 +64,7 @@ The next error indicates that WINVER version is no longer supported in MFC. WINV
64
64
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\include\afxv_w32.h(40): fatal error C1189: #error: MFC does not support WINVER less than 0x0501. Please change the definition of WINVER in your project properties or precompiled header.
65
65
```
66
66
67
-
Windows XP is no longer supported by Microsoft, so even though targeting it is allowed in Visual Studio 2015, you should be phasing out support for it in your applications, and encouraging your users to adopt new versions of Windows.
67
+
Windows XP is no longer supported by Microsoft, so even though targeting it is allowed in Visual Studio, you should be phasing out support for it in your applications, and encouraging your users to adopt new versions of Windows.
68
68
69
69
To get rid of the error, define WINVER by updating the **Project Properties** setting to the lowest version of Windows you currently want to target. Find a table of values for various Windows releases [here](/windows/desktop/WinProg/using-the-windows-headers).
70
70
@@ -86,7 +86,7 @@ WINVER we will set to Windows 7. It’s easier to read the code later if you use
86
86
87
87
With these changes, the SpyHk (DLL) project builds but produces a linker error.
88
88
89
-
```
89
+
```Output
90
90
LINK : warning LNK4216: Exported entry point _DLLEntryPoint@12
91
91
```
92
92
@@ -111,7 +111,9 @@ Given a project with many compilation errors that you are gradually eliminating,
111
111
112
112
The next error is common with old C++ code that uses iostreams.
113
113
114
+
```Output
114
115
mstream.h(40): fatal error C1083: Cannot open include file: 'iostream.h': No such file or directory
116
+
```
115
117
116
118
The issue is that the old iostreams library has been removed and replaced. We have to replace the old iostreams with the newer standards.
The macro MOUT resolves to \*g_pmout which is an object of type `mstream`. The `mstream` class is derived from the standard output string class, `std::basic_ostream<TCHAR>.` However with _T around the string literal, which we put in in preparation for converting to Unicode, the overload resolution for **operator <<** fails with the following error message:
191
+
The macro MOUT resolves to `*g_pmout` which is an object of type `mstream`. The `mstream` class is derived from the standard output string class, `std::basic_ostream<TCHAR>`. However with \_T around the string literal, which we put in preparation for converting to Unicode, the overload resolution for **operator <<** fails with the following error message:
190
192
191
193
```Output
192
194
1>winmsgs.cpp(4612): error C2666: 'mstream::operator <<': 2 overloads have similar conversions
@@ -257,7 +259,7 @@ This type of conversion was allowed under the older, less strict compiler, but m
257
259
258
260
We also get many errors like the following:
259
261
260
-
```
262
+
```Output
261
263
error C2440: 'static_cast': cannot convert from 'UINT (__thiscall CHotLinkCtrl::* )(CPoint)' to 'LRESULT (__thiscall CWnd::* )(CPoint)'
Now let us actually update the old Multi-byte Character Set (MBCS) code to Unicode. Since this is a Windows application, intimately tied to the Windows desktop platform, we will port it to UTF-16 Unicode that Windows uses. If you are writing cross-platform code or porting a Windows application to another platform, you might want to consider porting to UTF-8, which is widely used on other operating systems.
519
521
520
-
Porting to UTF-16 Unicode, we must decide whether we still want the option to compile to MBCS or not. If we want to have the option to support MBCS, we should use the TCHAR macro as the character type, which resolves to either **char** or **wchar_t**, depending on whether _MBCS or _UNICODE is defined during compilation. Switching to TCHAR and the TCHAR versions of various APIs instead of **wchar_t** and its associated APIs means that you can get back to an MBCS version of your code simply by defining _MBCS macro instead of _UNICODE. In addition to TCHAR, a variety of TCHAR versions of such as widely used typedefs, macros, and functions exists. For example, LPCTSTR instead of LPCSTR, and so on. In the project properties dialog, under **Configuration Properties**, in the **General** section, change the **Character Set** property from **Use MBCS Character Set** to **Use Unicode Character Set**. This setting affects which macro is predefined during compilation. There is both a UNICODE macro and a _UNICODE macro. The project property affects both consistently. Windows headers use UNICODE where Visual C++ headers such as MFC use _UNICODE, but when one is defined, the other is always defined.
522
+
Porting to UTF-16 Unicode, we must decide whether we still want the option to compile to MBCS or not. If we want to have the option to support MBCS, we should use the TCHAR macro as the character type, which resolves to either **char** or **wchar_t**, depending on whether \_MBCS or \_UNICODE is defined during compilation. Switching to TCHAR and the TCHAR versions of various APIs instead of **wchar_t** and its associated APIs means that you can get back to an MBCS version of your code simply by defining \_MBCS macro instead of \_UNICODE. In addition to TCHAR, a variety of TCHAR versions of such as widely used typedefs, macros, and functions exists. For example, LPCTSTR instead of LPCSTR, and so on. In the project properties dialog, under **Configuration Properties**, in the **General** section, change the **Character Set** property from **Use MBCS Character Set** to **Use Unicode Character Set**. This setting affects which macro is predefined during compilation. There is both a UNICODE macro and a \_UNICODE macro. The project property affects both consistently. Windows headers use UNICODE where Visual C++ headers such as MFC use \_UNICODE, but when one is defined, the other is always defined.
521
523
522
524
A good [guide](https://msdn.microsoft.com/library/cc194801.aspx) to porting from MBCS to UTF-16 Unicode using TCHAR exists. We choose this route. First, we change the **Character Set** property to **Use Unicode Character Set** and rebuild the project.
523
525
@@ -535,13 +537,13 @@ Here’s an example of code that produces this:
535
537
wsprintf(szTmp, "%d.%2.2d.%4.4d", rmj, rmm, rup);
536
538
```
537
539
538
-
We put _T around the string literal to remove the error.
540
+
We put \_T around the string literal to remove the error.
The _T macro has the effect of making a string literal compile as a **char** string or a **wchar_t** string, depending on the setting of MBCS or UNICODE. To replace all strings with _T in Visual Studio, first open the **Quick Replace** (Keyboard: **Ctrl**+**F**) box or the **Replace In Files** (Keyboard: **Ctrl**+**Shift**+**H**), then choose the **Use Regular Expressions** checkbox. Enter `((\".*?\")|('.+?'))` as the search text and `_T($1)` as the replacement text. If you already have the _T macro around some strings, this procedure will add it again, and it might also find cases where you don't want _T, such as when you use `#include`, so it's best to use **Replace Next** rather than **Replace All**.
546
+
The \_T macro has the effect of making a string literal compile as a **char** string or a **wchar_t** string, depending on the setting of MBCS or UNICODE. To replace all strings with \_T in Visual Studio, first open the **Quick Replace** (Keyboard: **Ctrl**+**F**) box or the **Replace In Files** (Keyboard: **Ctrl**+**Shift**+**H**), then choose the **Use Regular Expressions** checkbox. Enter `((\".*?\")|('.+?'))` as the search text and `_T($1)` as the replacement text. If you already have the \_T macro around some strings, this procedure will add it again, and it might also find cases where you don't want \_T, such as when you use `#include`, so it's best to use **Replace Next** rather than **Replace All**.
545
547
546
548
This particular function, [wsprintf](/windows/desktop/api/winuser/nf-winuser-wsprintfa), is actually defined in the Windows headers, and the documentation for it recommends that it not be used, due to possible buffer overrun. No size is given for the `szTmp` buffer, so there is no way for the function to check that the buffer can hold all the data to be written to it. See the next section about porting to the Secure CRT, in which we fix other similar problems. We ended up replacing it with [_stprintf_s](../c-runtime-library/reference/sprintf-s-sprintf-s-l-swprintf-s-swprintf-s-l.md).
547
549
@@ -569,7 +571,7 @@ Similarly, we changed LPSTR (Long Pointer to STRing) and LPCSTR (Long Pointer to
569
571
570
572
In some cases we had to replace a type to use a version that resolves correctly (WNDCLASS instead of WNDCLASSA for example).
571
573
572
-
In many cases we had to use the generic version (macro) of a Win32 API like `GetClassName` (instead of `GetClassNameA`). In message handler switch statement, some messages are MBCS or Unicode specific, in those cases, we had to change the code to explicitly call the MBCS version, because we replaced the generically named functions with **A** and **W** specific functions, and added a macro for the generic name that resolves to the correct **A** or **W** name based on whether UNICODE is defined. In many parts of the code, when we switched to define _UNICODE, the W version is now chosen even when the **A** version is what's wanted.
574
+
In many cases we had to use the generic version (macro) of a Win32 API like `GetClassName` (instead of `GetClassNameA`). In message handler switch statement, some messages are MBCS or Unicode specific, in those cases, we had to change the code to explicitly call the MBCS version, because we replaced the generically named functions with **A** and **W** specific functions, and added a macro for the generic name that resolves to the correct **A** or **W** name based on whether UNICODE is defined. In many parts of the code, when we switched to define \_UNICODE, the W version is now chosen even when the **A** version is what's wanted.
573
575
574
576
There are a few places where special actions had to be taken. Any use of `WideCharToMultiByte` or `MultiByteToWideChar` might require a closer look. Here's one example where `WideCharToMultiByte` was being used.
575
577
@@ -635,7 +637,7 @@ With these techniques, it took about half a day to convert the code to use the s
635
637
636
638
## <a name="deprecated_forscope"></a> Step 13. /Zc:forScope- is deprecated
637
639
638
-
Since Visual C++ 6.0, the compiler conforms to the current standard, which limits the scope of variables declared in a loop to the scope of the loop. The compiler option [/Zc:forScope](../build/reference/zc-forscope-force-conformance-in-for-loop-scope.md) (**Force Conformance for Loop Scope** in the project properties) controls whether or not this is reported as an error. We should update our code to be conformant, and add declarations just outside the loop. To avoid making the code changes, you can change that setting in the **Language** section of the C++ project properties to `No (/Zc:forScope-)`. However, keep in mind that `/Zc:forScope-` might be removed in a future release of Visual C++, so eventually your code will need to change to conform to the standard.
640
+
Since Visual C++ 6.0, the compiler conforms to the current standard, which limits the scope of variables declared in a loop to the scope of the loop. The compiler option [/Zc:forScope](../build/reference/zc-forscope-force-conformance-in-for-loop-scope.md) (**Force Conformance for Loop Scope** in the project properties) controls whether or not this is reported as an error. We should update our code to be conformant, and add declarations just outside the loop. To avoid making the code changes, you can change that setting in the **Language** section of the C++ project properties to `No (/Zc:forScope-)`. However, keep in mind that `/Zc:forScope-` might be removed in a future release of Visual C++, so eventually your code will need to change to conform to the standard.
639
641
640
642
These issues are relatively easy to fix, but depending on your code, it might affect a lot of code. Here's a typical issue.
641
643
@@ -673,4 +675,4 @@ Porting Spy++ from the original Visual C++ 6.0 code to the latest compiler took
673
675
## See Also
674
676
675
677
[Porting and Upgrading: Examples and Case Studies](../porting/porting-and-upgrading-examples-and-case-studies.md)<br/>
676
-
[Previous case study: COM Spy](../porting/porting-guide-com-spy.md)
678
+
[Previous case study: COM Spy](../porting/porting-guide-com-spy.md)
0 commit comments