Category Archives: WinAPI
ADC++ 2014 – Debugging Tools For Windows
Here you will find the presentation and the demos from the session at Advanced Developers Conference C++ in Garching. I hope that you enjoyed it and can use some of the features I showed to you!
And please give your feedback for the session, if you have not done yet: http://www.adcpp.de/feedback/sessions.aspx
Presentation: ADC++2014_JochenKalmbach_DebuggingToolsForWindows_public.pdf (2,62 MB)
Demos: ADC2014_demos.zip (187 MB)
Just a note to the demos: You must install the Debugging Tools For Windows from the Windows SDK and copy the “Debuggers” Directory into “ADC2014”! Then all examples should work.
If you have any questions, just drop a comment…
Change Target-Framework in C++/CLI for VS2010/2012
It is still not possible to change the target framework in the VS2010 or VS2012 IDE in the project settings.
The only way to change it, is to manually edit the vcxproj file. For this you need to do the following:
- Right-click on the projectin Solution Explorer and select “Unload project”
- The again do a right-click on the unloaded project in the Solution Explorer and select “Edit
.vcxproj” - In the porject XML file search for the node
- In this node, find the sub node
(if it does not exists, you must add one) - The inner text of this node defines the target framework version. It can be one of the following values: v2.0,v3.0, v3.5 v4.0 (VS2010 and 2012) or v4.5 (only VS2012)
- Save the vcxproj Datei and close it
- The again do a right-click on the unloaded project in the Solution Explorer and select “Reload Project”
- In the porject XML file search for the node
Example:
<PropertyGroup Label="Globals"> <ProjectGuid>{089A9EBF-5149-462A-BC7E-2B1B59DE123C}</ProjectGuid> <Keyword>Win32Proj</Keyword> <RootNamespace>CPP_VS2010</RootNamespace> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> </PropertyGroup>
Auto completion for current directory
Since Windows 200 it is possible to have auto completion for edit boxes which searches the file system and presents a drop down list with the current files. There is a simple helper function to enable this feature: SHAutoComplete
But this function only offers a simple interface to the more complex COM interface IAutoComplete.
While the “SHAutoComplete” is sufficent, it will not work if you want to have auto completion for files in the current directory. For this feature, you need to use the native COM interface:
For more info see also: Using Autocomplete
Here is an example of enabling auto completion for the file system, including the current directory:
HRESULT EnableAutoCompleteWithCurrentDirectory(HWND hWndEdit) { AUTOCOMPLETELISTOPTIONS acloOptions = ACLO_NONE; AUTOCOMPLETEOPTIONS acoOptions = ACO_AUTOSUGGEST; IAutoComplete *pac; HRESULT hr = CoCreateInstance( CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, __uuidof(pac), reinterpret_cast<void**>(&pac)); if (FAILED(hr)) { return hr; } IUnknown *punkSource; hr = CoCreateInstance( CLSID_ACListISF, NULL, CLSCTX_INPROC_SERVER, __uuidof(punkSource), reinterpret_cast<void**>(&punkSource)); if (FAILED(hr)) { pac->Release(); return hr; } // Get current directory wchar_t szCurDir[MAX_PATH]; GetCurrentDirectoryW(MAX_PATH, szCurDir); IACList2 *pal2; hr = punkSource->QueryInterface(__uuidof(pal2), reinterpret_cast<void**>(&pal2)); if (SUCCEEDED(hr)) { if (acloOptions != ACLO_NONE) { hr = pal2->SetOptions(acloOptions); } ICurrentWorkingDirectory *pcwd; hr = pal2->QueryInterface(__uuidof(pcwd), reinterpret_cast<void**>(&pcwd)); if (SUCCEEDED(hr)) { hr = pcwd->SetDirectory(szCurDir); pcwd->Release(); } pal2->Release(); } hr = pac->Init(hWndEdit, punkSource, NULL, NULL); if (acoOptions != ACO_NONE) { IAutoComplete2 *pac2; HRESULT hr2 = pac->QueryInterface(__uuidof(pac2), reinterpret_cast<void**>(&pac2)); if (SUCCEEDED(hr2)) { hr2 = pac2->SetOptions(acoOptions); pac2->Release(); } } punkSource->Release(); pac->Release(); return hr; }
You can enable the auto completion for a control by calling this function:
EnableAutoCompleteWithCurrentDirectory(m_txtBox1.m_hWnd);
Improved “PreventSetUnhandledExceptionFilter”
Starting with VS2005(VC8) it was not possible to handle all exceptions in process. I have discussed this in “SetUnhandledExceptionFilter” and VC8 and in Unhandled exceptions in VC8 and aboveโฆ for x86 and x64.
It seemms that the code I posted had been used in many Projects to handle all exceptions and to write a minidump in that case. Also someone has used it in a VB6 application and for this he needed to implement this function in a separate “CrashHandler.dll”. But now he got errors during the shutdown of the VB6 application. It seems that VB6 unloads the DLL before other DLLs and it seems that some other DLL is calling “SetUnhandledExceptionFilter” during shutown. This now leads to trouble, because the DLL is already unloaded.
Now I created a better and cleaner implementation for the “PreventSetUnhandledExceptionFilter” function, which also works in any situation, even if the DLL was unloaded ๐
static BOOL PreventSetUnhandledExceptionFilter() { HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); if (hKernel32 == NULL) return FALSE; void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); if (pOrgEntry == NULL) return FALSE; #ifdef _M_IX86 // Code for x86: // 33 C0 xor eax,eax // C2 04 00 ret 4 unsigned char szExecute[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; #elif _M_X64 // 33 C0 xor eax,eax // C3 ret unsigned char szExecute[] = { 0x33, 0xC0, 0xC3 }; #else #error "The following code only works for x86 and x64!" #endif SIZE_T bytesWritten = 0; BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, szExecute, sizeof(szExecute), &bytesWritten); return bRet; }
Gmail man ;)
A woundfull video about gmail; a must see!
http://youtu.be/TDbrX5U75dk
ANN: Community Forums NNTP Bridge
After looking deeper into the MSDN Forums Client and into an C# NNTP server, I decided to integrate both Ms-PL projects into a single project:
The result is a single “Community Forums NNTP Bridge” which can replace the MS NNTP Bridge. It also integrates both web services (*social*, *answers*) into a single NNTP server; so the “feeling” is like before the split ๐
If you are interested, you can take a look (with full source code) into the alternative:
http://communitybridge.codeplex.com/
LogSubstPol updated to VS2010
If you are using my $log$ substitution/keyword expansion for your source code with TFS, I have good news for your: I have upgradred my project to VS2010 ๐
The latest download can be found here:
$log$ / Keyword Substitution / Expansion Check-In Policy (TFS – LogSubstPol)
Converting VC projects to VC2010: Warning MSB8012
If you convert a project from VC5/6/2002/2003/2005/2008 to VC2010, you will sometimes get an warning during the conversion (UpgradeLog.XML) and during the link phase os your build. This warning might look like:
1>...Microsoft.CppBuild.targets(990,5): warning MSB8012: TargetPath(...LeakFinder_VC9.exe) does not match the Linker's OutputFile property value (...LeakFinder.exe). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Link.OutputFile).
or
1>...Microsoft.CppBuild.targets(992,5): warning MSB8012: TargetName(LeakFinder_VC9) does not match the Linker's OutputFile property value (LeakFinder). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Link.OutputFile).
The problem is, that the following two settings are not identical (Target Name, Target Extension):
If you match those two, the warning will be gone ๐
For example, if you have named your EXE in Debug-Builds: “MyAppd.exe” and in Release-Builds “MyApp.exe”, I suggest that your only change the “Target Name” in the General-Page to “MyAppd” (for Debug) and “MyApp” (Release) or ($(ProjectName) if it is the same name as the project).
Then you must also change the “Linker | General | Output File” to the default setting: “
If you want to change the output directory, you should the the “General | Output Directory” setting.
More info about this conversion problem can be found here:
Visual Studio 2010 – $(TargetName) macro
Visual Studio 2010 C++ Project Upgrade Guide
OleView not found in VS2008 and VS2010
If you have installed VS2008 and/or VS2010 (full), you will notice that OleView is not installed!
The product team decided to remove this utility from the tools-folder.
But you the source-code is still available! You can find it under
C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\Samples\\1033\\VC2010Samples.zip
Extract the files and build (the release version of)
C++\\MFC\\ole\\oleview\\oleview.sln
Then you have the two files: oleview.exe and iviewers.dll
Also, the same problem is with the OLE-Test Container (tstcon). This application can also be found in the samples.
See also: ActiveX Test Container Application is Still Available
Supported runtime OS for VC2010
Here is now the offical statement for the supported runtime OS:
- Windows XP with SP2 and later
- Windows Server 2003 with SP1 and later
- Windows Vista RTM an later
- Windows Server 2008 RTM and later
- Windows 7 and later
This restrictions comes from a security desicion to have a hard dependency on EncodePointer, which is only available in the above OSes.
For more info see: Visual Studio 2010: Windows Platforms (CRT)
Default Keybindings for VS2010 (C++, C#, VB, F#)
You can download the VS2010 Default Keybinding Cards here:
http://www.microsoft.com/downloads/details.aspx?FamilyID=92CED922-D505-457A-8C9C-84036160639F&displaylang=en
Feedback for VC++ for the version AFTER VS2010
If you want to give feedback for VC++ for the next version of VS (after VS2010), you can fill out the VC++ product team survey:
http://blogs.msdn.com/vcblog/archive/2010/03/22/vc-developer-survey.aspx
Major bug in the new dbghelp.dll
The latest dbghelp.dll (version 6.12.2.633), which can be downloaded via the newest WDK, seems to have a major bug regarding the function SymGetModuleInfo64 (which is used in almost every project, if you want to display module-infos).
A user reported this bug in the WinDbg newsgroup.
I now build a small repro-code, which shows the problem. You can download the code here: dbghelp_bug_6.12.2.633.zip
The problem is, that the size of the struct “IMAGEHLP_MODULE64” has changed. They added two DWORDs at the end (the struct has now a size of 0x690 bytes). This is normally not a problem because the struct has a “SizeOfStruct” member, which must be set, prior to calling the “SymGetModuleInfo64” function.
But the new version does not support the older version of the struct with a size of 0x688 bytes, which is commonly used because this was the last version since 2003!!! It only supports the older versions from 2002 and before.
So I hope that this major bug will soon get fixed… but after the WinDbg-Release seems to be coupled to the WDK-release, we can wait until next year…
Forums NntpBridge and DateTime
There is a “research” project to access the msdn-web forums via a nntp-bridge. The offical version is “V1″… but I must say, that it is still Beta1 ๐
For example, there is a bug with the DateTime-Format, which uses the current system locale… This bug was reported severaly months ago, and nothing happend… In january and february it was not a problem, because “Jan” and “Feb” are the same in english and german… but in “Mรคrz” the NntpBridge started to report all postings with “01.01.1970 01:00″… because it will report the date as “Mrz” instead of “Mar”… which is somehow bad…
So I decided to make a quick fix for this behavior. You just need to add the System.Globalization.CultureInfo.InvariantCulture as parameter to the ToString method.
Here are the steps, how you can fix this by yourself:
- Locale the directory of the Nntp-Bridge (normally “C:\Program Files (x86)\Microsoft Community Tools\Microsoft Forums NNTP Bridge”
- Copy the file “nntp.dll” to “nntp_org.dll” so you have the original version saved
- Copy “nntp.dll” into a temporary directory like “c:\temp\nntp_fix”
- Open a “Visual Studio 2005/2008 Command Prompt (x86)”
- Go to the temporary directory (cd /D c:\temp\nntp_fix)
- Disassemble the nntp.dll
ildasm nntp.dll /out=nntp.il
- Now you need to change the content of the nntp.il file
- Find the method “GetMessageFormat” and change it from
.method public hidebysig static string GetMessageFormat(valuetype [mscorlib]System.DateTime dateTime) cil managed { // Code size 28 (0x1c) .maxstack 8 IL_0000: ldstr "{0} {1}" IL_0005: ldarga.s dateTime IL_0007: ldstr "ddd, d MMM yyyy HH:mm:ss" IL_000c: call instance string [mscorlib]System.DateTime::ToString(string) IL_0011: ldsfld string Nntp.NntpTimeUtility::GmtTimeZoneOffset IL_0016: call string [mscorlib]System.String::Format(string, object, object) IL_001b: ret } // end of method NntpTimeUtility::GetMessageFormat
to
.method public hidebysig static string GetMessageFormat(valuetype [mscorlib]System.DateTime dateTime) cil managed { // Code size 33 (0x21) .maxstack 8 IL_0000: ldstr "{0} {1}" IL_0005: ldarga.s dateTime IL_0007: ldstr "ddd, d MMM yyyy HH:mm:ss" IL_000c: call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture() IL_0011: call instance string [mscorlib]System.DateTime::ToString(string, class [mscorlib]System.IFormatProvider) IL_0016: ldsfld string Nntp.NntpTimeUtility::GmtTimeZoneOffset IL_001b: call string [mscorlib]System.String::Format(string, object, object) IL_0020: ret } // end of method NntpTimeUtility::GetMessageFormat
- Then compile the nntp.dll again (and delete the original dll before compiling (del nntp.dll)):
ilasm /dll nntp.il /resource=nntp.res
- Now you can copy the patched nntp.dll into the original directory (be sure, the application is not running).
Now it looks better:
That’s all! Happy NntpBridging ๐
Debugging Tools for Windows is now part of the WDK
Yesterday a new release of “Debugging Tools For Windows” was released. Until now, it was possible to download the package as a single download of about 17 MB in size.
Starting with the new release, it seems that the Debugging Tools For Windows is now integrated in the WDK which means to download a 620 MB file.
Also it seems so, that the WDK does not install the Debugging Tools For Windows, it just installs a link to the setup…
So the question is: Why not provide the setup as a separate download as in previous version?
Here is a quote from the Debugging Tools For Windows download page:
This current version of Debugging Tools for Windows is available as part of the Windows Driver Kit (WDK). To download the WDK and install Debugging Tools for Windows:
1. Download and install the WDK.
2. Find the debugging tools link for Windows x86 version on the screen that appears and click to install the debuggers to a location of your choice.
3. After the installation is complete, you can find the debugger shortcuts by clicking Start, pointing to All Programs, and then pointing to Debugging Tools for Windows.
Conclusion: We will never understand marketing…
The Shim Database
The Shim database is a mystic area inside windows… For example it will display an UAC (admin) prompt if your application-name contains the word “*instal*”.
You can display all available shims with the Application Compatibility Administrator by using the /x command line switch.
Also there is a tool from Heath Steward which dumps the database into an XML file.
Of course, he failed to prvide the source-code of his sample project.
Also, Alex Ionescu wrote a small dump tool, but also has never published it…
So I decided to dig into this almost not documented world and write a small Shim-Dumper and Exe-matching tool (whitch source code ๐ ).
Shim Database Tool (sdb) v1.0 Copyright (C) 2010 Jochen Kalmbach Usage: sdb.exe [-noids] [-match] [PathToShimDatabse] [PathToFileName] -noids Will prevent the output of the TagIds -match Will match the provided file with the installed databases and displays the activated shims In this case 'PathToFileName' is required NOTE: If no shim database path is provided, the default database will be used.
You can use it either for dumping the shimdatabase like:
sdb.exe >ShimDatabase.xml
This will redirect the output to an xml-file and will look something like:
setup32.exe
WordPerfect Office 2000
Corel
*
Corel Corporation
Corel Setup Wizard
programs\wpwin9.exe
Corel Corporation Limited
WordPerfect® 9
appman\tools\cset90.exe
WinXPSP1VersionLie
0x284e0
$
*
(be aware: the current Win7 database is about 17 MB!)
You also can use this tool to find out, if an application has a shim applied:
C:>sdb -match MyInstaller.exe Shim found for file: MyInstaller.exe Flags: 0x0: Exe-Shim: 0x35472, Flags: 0x0: Layer-Flags: 0x0: Shim-Database: 11111111-1111-1111-1111111111111111
Currently it just displays the TagId of the Shim. You can use this to search the xml-file for the corresponding id.
Have fun, using this tool ๐
The project (VS2008) can be found here:
http://blog.kalmbachnet.de/files/sdb_v1.zip
It will compile for x86 and x64.
The mystic variable “$I” during for each
A poster in the german C/C++ forum asked if there is an index available while using a for each loop. He accidently saw in the debug-window a variable called “$I”.
And indeed: There is a “hidden” variable “$I” which can be used inside the for each loop. This variable is the number of the loop-iteration.
Here is a simple example:
int main() { array<int> ^MyArray = { 100, 200, 300, 400 }; for each( int v in MyArray ) { System::Console::WriteLine(v.ToString() + " " + $I); } return 0; }
As you can see, it uses a variable “$I” which was never decalred!
And it will output the following:
100 0 200 1 300 2 400 3
If you debug a normal for each loop and take a look in the “local-watch-window”, you will see the following variables, while you are inside the for each loop:
You can see two “hidden” variables “$I” and “$S1”. And if you step through the loop, you will see that the “$I” variable is incremented for each iteration. “$S1” is a reference to the array.
If you dig further into this issue, you will find out, that for each and the normal “for” loop will result in the identical IL code! This is also true for C#!
See also:
FOREACH Vs. FOR (C#)
To foreach or not to foreach that is the question.
As we can see, the “$I” variable is just a side-effect of the for each loop. It is a compiler generated variable which is used to transform the “for each” into a normal for-loop!
Of course, this is only true in special cases like arrays.
If you have a list which only implements the “IEnumerable” interface and is not an array (like “System::Collections::Generic::List”), then the mistic variable “$I” is gone, because now the compiler uses the “IEnumerable” interface to gbuild a “real” “for each” loop:
In this case “$I” is gone but “$S1” is still there. And “S1” is the enumerator of the list (in this case
System::Collections::Generic::List::Enumerator<int>
).
The conclusion is:
Do not rely on the compiler generated variable “$I”, and do not use “for each” if you need a index-variable, just use a normal for loop.
Upgrade to VC20xx: Problems with Exception Handling
If you upgrade from VC6 to VC2008, then your project will automatically converted to the new format.
As a side-effect, it will also default to the new exception handling which breaks compatibilty to VC6.
Therefor this post ๐
In VC6, by default the “/EHa” exception model ist activ.
In VC200x and later, by default, the “/EHsc” exception model is active. This means that if you did not explicit specify the “/EHa” model, you will now automatically use the “/EHsc” model, which only catches C++ exceptions!
For example, the following code will work as expected and will crash in VS2008:
#include <stdio.h> #include <tchar.h> int _tmain() { try { printf("Now doing an AV...\n"); char *c = NULL; strcpy(c, "Hello"); printf(c); } catch(...) { printf("Catched...."); } }
So be aware, that if you rely on asynchonus exceptions, you need to switch the expetion model in the C/C++ project settings under “Code generation | Enabled C++ Exceptions: Yes with SEH Exceptions (/EHa)“
StackWalker moved to CodePlex
If you have ever published an article on CodeProject, you will see that maintanance an ariticle is practicale impossible. In the last several years, I improved the source-code of my “StackWalker” article outside of codeproject, but this also leads to confusion…
So today I moved at least the source code to codeplex:
http://stackwalker.codeplex.com/