Welcome to MSDN Blogs Sign in | Join | Help

My blog home...

It's now on http://concrt.spaces.live.com.

concrt was available so as that's what's on my mind nowadays, I decided to pick that. This won't be just about ConcRT! :-)

On Windows 7, the Invariant Culture is an installed culture...

Last month, I investigated an issue for an ISV where their code would work fine on Windows Vista but fail on Windows 7. Not very commom!

The cause?

CultureInfo.GetCultures(CultureTypes.AllCultures & ~CultureTypes.NeutralCultures)

returns an array that does not contain the CultureInfo.InvariantCulture on Windows Vista but does on Windows 7.

On Windows 7, the Invariant Culture is considered to be an installed culture. It was not on Windows Vista. From Eric:

 “The Invariant culture is normally included with NeutralCultures enumerations. It is also specifically excluded from SpecificCulture enumerations. However, there is no attempt to remove it from the InstalledWin32Cultures enumeration and since CultureTypes.AllCultures == CultureTypes.NeturalCultures | CultureTypes.SpecificCultures | CultureTypes.InstalledWin32Cultures, the InvariantCulture is showing up as one of the InstalledWin32Cultures.”

Depending on what you do with the result, this might be an issue. For example if you create an instance of RegionInfo RegionInfo(CultureInfo.InvariantCulture.LCID), this will result in an ArgumentException exception being raised.

To make sure your code works on both O.S., you might need to introduce the highlighted code below:

var list = new List<RegionInfo>();

int i = 0;

foreach (var cultureInfo in CultureInfo.GetCultures(CultureTypes.AllCultures & ~CultureTypes.NeutralCultures)) {

   _cultureInfoComboBox.Items.Add(String.Format("{0} : {1}", i++, cultureInfo.NativeName));

   if (!cultureInfo.Equals(CultureInfo.InvariantCulture)) {

      var regionCulture = new RegionInfo(cultureInfo.LCID);

      if (!list.Contains(regionCulture)) {

         list.Add(regionCulture);

         _countriesSelector.Items.Add(regionCulture.DisplayName);

      }

   }

}

if (_countriesSelector.Items.Count > 0) {

   _countriesSelector.SelectedIndex = 0;

}

if (_cultureInfoComboBox.Items.Count > 0) {

   _cultureInfoComboBox.SelectedIndex = 0;

}

 

J’espère que vous trouverez cela utile. Buen día.

Posted by yvesdolc | 0 Comments

How to add the application compatibility section with Visual C++ 2008?

If you wonder what I’m talking about when mentioning the compatibility section, have a look at my previous blog entry.

To start with, I added a Compatibility.manifest file to my project:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">

      <application>

         <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>

         <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>

      </application>

   </compatibility>

</assembly>

 

I then specified $(InputDir)\Compatibility.manifest in the Configuration Properties/Manifest Tool/Input and Output/Additional Manifest Files field in the project properties dialog. This automatically added /manifest ".\Compatibility.manifest" to the MT.EXE command line that would be used at build time.

Not too sure it would work; I then rebuilt a small C++ program and got:

\Compatibility.manifest : manifest authoring warning 81010002: Unrecognized Element "compatibility" in namespace "urn:schemas-microsoft-com:compatibility.v1".

 

I must be using an old MT.EXE version. I turned off the Suppress Startup Banner, turned on the Verbose Output and rebuilt:

Microsoft (R) Manifest Tool version 5.2.3790.2076

Copyright (c) Microsoft Corporation 2005.

All rights reserved.

\Compatibility.manifest : manifest authoring warning 81010002: Unrecognized Element "compatibility" in namespace "urn:schemas-microsoft-com:compatibility.v1".

 

Let’s dir C:\MT.EXE /S /B and look at the versions of MT.EXE I have on my hard-disk:

C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\mt.exe
C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\x64\mt.exe
C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\mt.exe
C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\x64\mt.exe

 

No surprise as I have both VS 2008 SP1 and the released Windows 7 SDK installed. Let’s launch the one I hope is the one I’m using:

D:\>"C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\x64\mt.exe" /?
Microsoft (R) Manifest Tool version 5.2.3790.2076
Copyright (c) Microsoft Corporation 2005.
All rights reserved.

Usage:

 

So I am building with the publicly latest and greatest version of MT.EXE! I’m guessing I’ll ignore the warning but I need to make sure this works.

First, I loaded my program executable with the Visual Studio Resource Editor (File/Open/File…/Open With…) to look at the MANIFEST resource: yes, the setting was there, as was the Side-by-Side information.

But I wanted to go a step further so although I said in my previous blog entry that it was an obscure topic to me, I looked at the sample on the ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION Structure page, but it crashed on my machine. I kept playing around and ended up with the following code:

GUID WIN7_CONTEXT_GUID = {0x35138b9a, 0x5d96, 0x4fbd, {0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a}};

GUID VISTA_CONTEXT_GUID = {0xe2011457, 0x1546, 0x43c5, {0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0}};

HANDLE   activationContextHandle = GetModuleHandle(NULL);

SIZE_T   bufferSize = 0;

 

QueryActCtxW(QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE, activationContextHandle,

             NULL, /*ACTIVATION_CONTEXT_INFO_CLASS::*/CompatibilityInformationInActivationContext,

             NULL, 0, & bufferSize);

if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

   _ASSERTE(bufferSize > 0);

   vector<BYTE> p(bufferSize);

   if (QueryActCtxW( QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE, activationContextHandle,

                     NULL, /*ACTIVATION_CONTEXT_INFO_CLASS::*/CompatibilityInformationInActivationContext,

                     & p.front(), bufferSize, &bufferSize)) {

      ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION * acci = reinterpret_cast<ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION *>(& p.front());

      DWORD dw = acci->ElementCount;

      COMPATIBILITY_CONTEXT_ELEMENT * ce = acci->Elements;

      while (dw) {

         if (ce->Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS) {

            if (ce->Id == WIN7_CONTEXT_GUID) {

               wcout << L"Windows 7 is supported" << endl;

            }

            if (ce->Id == VISTA_CONTEXT_GUID) {

               wcout << L"Windows Vista is supported" << endl;

            }

         }

         ce++;

         dw--;

      }

   }

}

 

I ran it and got:
Windows Vista is supported
Windows 7 is supported

Voilà!

Como de costumbre, nous terminons avec une liste de ressources:

·         Input and Output, Manifest Tool, Configuration Properties, <Projectname> Property Pages Dialog Box

·         Understanding Manifest Generation for C/C++ Programs

(Thanks to everyone who answered my e-mails while working on this. You know who you are!)

 

Posted by yvesdolc | 0 Comments

The new compatibility section in the Application Manifest

This is still the same Application Manifest that you store in your Win32 Resource or put next to your executable (i.e. "MyExecutable.exe.manifest" ).

Under Windows XP, this manifest allowed you to create Isolated Applications and Side-by-side Assemblies.

Under Windows Vista, we added the DPI Awareness and execution level for your application.

Under Windows 7, we introduced a new section called compatibility.

If it’s not present, your application will get the Windows Vista behavior by default on Windows 7 and future Windows versions. This new section allows us:

1.       To provide new behavior to new developer-created software while maintaining the compatibility for existing software.

2.       To help Windows deliver greater compatibility in future versions of Windows as well.
For example, an application declaring support only for Windows 7 in the Compatibility section will continue to receive Windows 7 behavior in future version of Windows.

So the question is what’s the Windows Vista behavior? In my personal order of preference:

1.       Program Compatibility Assistant (PCA)

2.       GetOverlappedResult API

3.       RPC Default Thread Pool

4.       DirectDraw Lock

5.       DirectDraw Bit Block Transfer (Blt) to Primary without Clipping Window

Here is an example using the corresponding pre-defines GUIDs:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">

      <application>

         <!--The ID below indicates application support for Windows Vista -->

         <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>

         <!--The ID below indicates application support for Windows 7 -->

         <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>

      </application>

   </compatibility>

</assembly>

 

Chris Jackson goes into a bit more details here and voici a bit more resources:

-          Application Manifest in the Windows 7 and Windows Server 2008 R2 Application Quality Cookbook

-          The still obscure (to me) activation context stuff: the QueryActCtxW Function and COMPATIBILITY_CONTEXT_ELEMENT Structure 

Y colorín colorado, este cuento se ha acabado...

Posted by yvesdolc | 0 Comments

Consider not using the Frame Pointer Optimization when building your software

Stack tracing is a very useful functionality for tracking both the causes of performance problems and reliability issues. With Frame Pointer Optimization disabled, one can easily build the call chain by walking through the stack frame pointers.

 

Because of potential code size increase and performance degradation, Independent Software Vendors tend to use the /Oy C++ compiler option when building their software.

 

The Windows group performed some testing years ago to verify those beliefs and they concluded that the benefits of not using this optimization were bigger than the minimal cost it implied. Additionally, one of the gentlemen who performed those measurements at the time told me that for modern machines, there should be no noticeable performance difference. 

 

I just want to encourage you to turn off FPO and if you don’t believe us, please do your own testing and see if you want to follow our advice. It will help both of us!

 

More detailed information courtesy of Ken:

-          Frame pointer omission (FPO) optimization and consequences when debugging, part 1

-          Frame pointer omission (FPO) optimization and consequences when debugging, part 2

 

Tchau.

 

Posted by yvesdolc | 0 Comments

UI0Detect, WlS0WndH and a lie...

http://blogs.msdn.com/yvesdolc/archive/2009/09/11/ui0detect-wls0wndh-and-a-lie.aspx

 

In my prior to last entry, I took a shortcut: your Windows Service user interface can be seen on Windows Vista and still on Windows 7. But beware, it’s not by default, not without additional end user involvement and very likely to no longer be there under Windows 8!

It’s all about the Interactive Service Detection Windows Service (%SystemRoot%\System32\UI0Detect.exe) and the DLL injected in your service to detect if it displays anything in Session 0 (%SystemRoot%\System32\WlS0WndH.dll and %SystemRoot%\SysWOW64\WlS0WndH.dll)

Instead of trying to repeat the excellent work that Alex Ionescu did in his blog, let me highly advise you to take the time to read it. It’s a bit complex but very helpful to understand how this all works, even under Windows XP:

-          Inside Session 0 Isolation and the UI Detection Service - Part 1

-          Inside Session 0 Isolation and the UI Detection Service - Part 2

Let me finish by adding two things:

1.       This mechanism is very very likely not to be there any longer in Windows 8.
Please do upgrade your code.

2.       The CreateProcessAsUser() API might actually not be the best solution when you need more complex interface for your service. Both Services in Windows Vista and Impact of Session 0 Isolation on Services and Drivers in Windows Vista are being updated to reflect this. I’ll keep you updated.

¿Querían noticias? ¡Pues ahora, ya las tienen!

Posted by yvesdolc | 0 Comments

If you develop/test on Windows 7, you might want to turn off the Fault Tolerant Heap…

It might interfere with your testing and after your software has crashed a couple of times, your application might start to no longer behave erratically.

 

As JohnFrum wrote:

I learned about this feature a few weeks ago while debugging my service.  It had been crashing and then it seemed fixed and I couldn't repro it again.  Moved it to another box and it started crashing again.  Finally I noticed a line in the debugger that I knew wasn't mine about FTH and thought ‘WTH?  Ahh, nice!’  I like it but I'll turn it off on my test systems.”

 

The Fault Tolerant Heap page has the details about disabling it. For more information about this, check the video at Silviu Calinoiu: Inside Windows 7 - Fault Tolerant Heap

 

À demain si on le veut bien.

Posted by yvesdolc | 0 Comments

Do you still use the MessageBox API in your Windows Service?

Or do you display any type of User Interface?

Starting with Windows Vista and above, user interfaces generated by Windows services can’t be seen. And even worst, your service could be stuck waiting for some user input that the user cannot give as she does not see anything!

Why did we do that? Well it’s all explained in Impact of Session 0 Isolation on Services and Drivers in Windows Vista:

In Microsoft® Windows® XP, Microsoft Windows Server™ 2003, and earlier versions of the Windows operating system, all services run in the same session as the first user who logs on to the console. This session is called Session 0. Running services and user applications together in Session 0 poses a security risk because services run at elevated privilege and therefore are targets for malicious agents who are looking for a way to elevate their own privilege level.

The Microsoft Windows Vista™ operating system mitigates this security risk by isolating services in Session 0 and making Session 0 noninteractive. In Windows Vista, only system processes and services run in Session 0. The first user logs on to Session 1, and subsequent users log on to subsequent sessions. This means that services never run in the same session as users’ applications and are therefore protected from attacks that originate in application code.

You can no longer use the MB_SERVICE_NOTIFICATION flag when calling the MessageBox API. It’s useless on Vista and higher.

So how do you display a simple message from your Windows Service?

For simple interactions, services can display a message box in the user's session by calling WTSSendMessage. For more complex interactions, services must use an approach such as calling CreateProcessAsUser to create a UI process in the user's session. That process handles user interaction and communicates with the service through RPC or named pipes.

I will illustrate the simple case in this blog entry.

 

In the SimpleService I’m attaching, here is how I display a message when the event named "Global\\SimpleService.HelloWithWtsSendMessage" is set:

DWORD physicalConsoleSession = WTSGetActiveConsoleSessionId();

 

if (0xFFFFFFFF != physicalConsoleSession) {

   wostringstream b;

   b << L"Hello!" << endl

     << L"The active console session ID is 0x" << std::hex << physicalConsoleSession << L'.' << endl;

 

   LPWSTR title = const_cast<wchar_t *>(ServiceTable[0].lpServiceName);

   DWORD titleLength = static_cast<DWORD>(wcslen(title) * sizeof(*title));

   std::wstring messageString(b.str());

   LPWSTR message = const_cast<wchar_t *>(messageString.c_str());

   DWORD messageLength = static_cast<DWORD>(wcslen(message) * sizeof(*message));

   DWORD response;

   WTSSendMessage(WTS_CURRENT_SERVER_HANDLE,

                  physicalConsoleSession,

                  title, titleLength,

                  message, messageLength,

                  MB_OK | MB_ICONINFORMATION,

                  0,

                  & response,

                  FALSE);

 

After building the service, don’t forget to give access to the executable (i.e. SimpleService.exe) to LOCAL SERVICE so that the SCM can reach it when you indicate that you want to start it!

You might have noticed that the event name is create in the global namespace. As the document clearly explains:

Because services run in Session 0, named objects created or opened by services are usually in \BaseNamedObjects\. However, if a user application assumes that it is running in the same session as the service and synchronizes with the service by creating or opening objects with the Local\ prefix (or no prefix, which defaults to Local\), the application no longer works as expected. This is because the create or open request is specific to that session (due to the Local\ prefix) and the objects that the application creates or opens are in \Sessions\<n>\BaseNamedObjects instead of \BaseNamedObjects\. The correct way for user applications to synchronize with a service is to explicitly use the Global\ prefix when creating or opening objects in \BaseNamedObjects\.

I also had to change the security around the event: only LocalService could touch it and I wanted applications running under other principals to be able to set/reset it:

// We give EVENT_MODIFY_STATE (0x0002) access to the Interactive User

// and

// GENERIC_ALL (GA) to the Local Service (LS) under which this service is installed/running by default

// Resources:

//    - Security Descriptor Definition Language: http://msdn.microsoft.com/en-us/library/aa379567(VS.85).aspx

//    - ConvertStringSecurityDescriptorToSecurityDescriptor: http://msdn.microsoft.com/en-us/library/aa376401%28VS.85%29.aspx

//    - Synchronization Object Security and Access Rights: http://msdn.microsoft.com/en-us/library/ms686670%28VS.85%29.aspx

if (!ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:(A;;0x00000002;;;IU)(A;;GA;;;LS)", SDDL_REVISION_1, & securityDescriptorPointer, NULL)) {

   goto cleanup;

}

SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), securityDescriptorPointer, FALSE};

// The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space.

// The remainder of the name can contain any character except the backslash character (\).

serviceContext.HelloWithWtsSendMessageEvent = CreateEvent(&sa, FALSE, FALSE, L"Global\\SimpleService.HelloWithWtsSendMessage");

serviceContext.HelloWithMessageBoxEvent = CreateEvent(&sa, FALSE, FALSE, L"Global\\SimpleService.HelloWithMessageBox");

LocalFree(securityDescriptorPointer);

 

There’s a little application to test:

int wmain() {

   //Sleep(30000);

   HANDLE e = OpenEvent( EVENT_MODIFY_STATE, FALSE, L"Global\\SimpleService.HelloWithWtsSendMessage");

   if (e)

      SetEvent(e);

   else

      wcout << L"Error " << GetLastError() << L" calling OpenEvent()" << endl;

   return 0;

}

 

You can uncomment the Sleep call and once launched, hurry up and switch to another user. You can also change the event name in the test to "Global\\SimpleService.HelloWithMessageBox" and watch your service freeze…

Pay attention to my usage of _InterlockedAnd and _InterlockedOr: those can be very helpful.

As usual, any comment is welcomed.

À demain si on le veut bien.

 

Posted by yvesdolc | 0 Comments
Attachment(s): SimpleService.zip

Do you receive WM_PAINT when waiting for a COM call to return?

When a COM call is made that involves a COM Proxy or a call to CoWaitForMultipleHandles() (e.g. in a .NET Runtime Callable Wrapper), you could see this behavior where you would not have under pre-Vista versions of Windows.

We made the design change in Vista, among other reasons, to allow proper painting of the applications when the consent dialog is shown.

If you suffer from this design change and you cannot easily modify your code to handle gracefully this type of reentrancy, you’ll want to ensure that Windows behaves the way it used to.

How do you do that?

As explained in this Connect Feedback:

You can work around this by doing an application compatibility shim. The flag is DisableNewWMPAINTDispatchInOLE.

Once you have downloaded the Application Compatibility Toolkit (version 5.5 as of 8/4/2009), run the Compatibility Administrator program to create a new database for your software and follow the steps to produce an SDB for your software. This could include several .EXEs but no DLLs, as those cannot be shimmed.

You’ll want to make sure you pick the right flag in the following dialog:

clip_image002

Once you’ve created you .SDB file, you can register the information it contains by running sdbinst.exe on the file. When installing your software, you’ll want to have a Windows Installer Customer Action launching sdbinst.exe with the same .SDB file as parameter.

I’m no A.C.T. guru so please look at the Application Compatibility site for more information.

 

Note added after initial post:

Ensure that the cache is flushed:

· Elevate cmd

· Execute the following line from the elevated console Rundll32 apphelp.dll,ShimFlushCache

Posted by yvesdolc | 0 Comments

Developing native applications for Windows 7 in C++

A gentleman from Germany asked on one of our forums:

 

“I am interested in developing native Windows 7 Apps (64 and 32-Bit) with Visual C/C++. How can I do this?”

 

You’ll first need a C++ compiler. You can find that on the MSDN Visual C++ page.

 

Then the Windows 7 Software Development Kit can be downloaded from Windows SDK. It includes the header files, libraries and tools you need to develop for Windows 7 (Release Candidate as of 8/5/2009).

 

Although the SDK contains good documentation, those are mostly tools. So where do you go for more information?

 

I’d say that Develop for Windows 7 and Windows Vista  MSDN is a good start. A lot of links I wanted to include here are actually there already.

 

This is a very high level answer to very high level question but I hope it helps this gentleman a bit.

 

And others too.

 

Auf Wiedersehen.

Posted by yvesdolc | 0 Comments

No TOUCH utility on Windows to help refreshhing the Fusion Cache? MS-DOS copy command syntax...

After reading the November '06 "Manifest and the fusion cache" blog entry that one my peers wrote, I immediately thought about the *nix style TOUCH utility.

But it's not available out-of-the-box on Windows... I was surprised to learn that the Updating the Date and Time Stamps on Files trick worked well on Windows 7.

All thanks to our old MS-DOS command:

@echo off
if %1.==. goto end
if not exist %1 goto end
copy /b %1 +,, > nul
echo %1 touched!
:end

Posted by yvesdolc | 0 Comments

Windows 7 redirection (a.k.a. virtualization) application I use to demonstrate the effect:

C:> cl /W4 /EHsc Redirection.cpp

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

Redirection.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:Redirection.exe
Redirection.obj

Source: 

#pragma comment(lib, "ole32")

#pragma comment(lib, "ShlWApi")

#pragma comment(lib, "Shell32")

 

#define _WIN32_WINNT 0x0600

#define UNICODE

 

#include <windows.h>

#include <shlobj.h>

#include <shlwapi.h>

#include <iostream>

using std::wcout;

using std::endl;

 

class auto_free_com_memory {

public:

   auto_free_com_memory(void * p) : m_p(p) {}

   ~auto_free_com_memory() {if (m_p) ::CoTaskMemFree(m_p);}

private:

   void * m_p;

};

 

int wmain() {

   wchar_t * folderPath = NULL;

 

   if FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_CREATE, NULL , &folderPath)) {

      wcout << L"Cannot retrieve FOLDERID_ProgramFiles known folder location." << endl;

      return -1;

   }

 

   auto_free_com_memory _fp(folderPath);

 

   // System drive root redirection

   wchar_t systemDriveRoot[] = {folderPath[0], folderPath[1], folderPath[2], L'\0'};

   WCHAR filePath[MAX_PATH];

   if (wcscpy_s(filePath, systemDriveRoot) || !PathAppend(filePath, L"UAC Redirection test.log")) {

      wcout << L"Could not build the path to a file under the system drive root folder." << endl;

      return -2;

   }

 

   wcout << L"Creating \"" << filePath << L"\"." << endl;

   HANDLE file = CreateFile(filePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

   if (file == INVALID_HANDLE_VALUE)

      wcout << L"Could not create a file under the system drive root folder. (error " << GetLastError() << L")." << endl;

   else

      CloseHandle(file);

 

   // Program Files redirection

   if (wcscpy_s(filePath, folderPath) || !PathAppend(filePath, L"MyUACRedirection")) {

      wcout << L"Could not build the path to a file under the Program File known folder." << endl;

      return -3;

   }

 

   // Does the file folder exist?

   DWORD folderAttributes = GetFileAttributes(filePath);

   if (folderAttributes == INVALID_FILE_ATTRIBUTES || ! (folderAttributes & FILE_ATTRIBUTE_DIRECTORY))  {

      wcout << L"The folder \"" << filePath << L"\" must exist and be accessible for this test to work." << endl;

      return -4;

   }

  

   if (!PathAppend(filePath, L"MyUACRedirection.log")) {

      wcout << L"Unexpected error adding the file name to \"" << filePath << "\"."<< endl;

   }

 

   wcout << L"Creating \"" << filePath << "\"." << endl;

   file = CreateFile(filePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  

   if (file == INVALID_HANDLE_VALUE)

      wcout << L"Could not create \"" << filePath << "\" (error " << GetLastError() << L")." << endl;

   else

      CloseHandle(file);

 

   return 0;

}

Posted by yvesdolc | 0 Comments

Windows 7 Libraries and the Common File Dialog…

As you can read in the application cookbook:

When using IFileDialog, you must use GetResult method instead of combination of GetFolder and GetFilename. Use the Shell APIs where possible to interact with and manipulate items in the Shell Namespace (for example, IShellItem).

So let me share a small code snippet I wrote. Hopefully, this will help you.

Here is how the execution looks like on my machine (Windows 7 Beta 1):

 image

image

And now the code snippet:

#include <comdef.h>
#include <shlobj.h>

_COM_SMARTPTR_TYPEDEF(IFileOpenDialog, __uuidof(IFileOpenDialog));
_COM_SMARTPTR_TYPEDEF(IShellItem, __uuidof(IShellItem));

#include <sstream>
using std::endl;
using std::wostringstream;

const wchar_t NullString[] = L"(NULL)";

void FileOpen(HWND window) {
   IFileOpenDialogPtr fileOpenDialog(__uuidof(FileOpenDialog));
   fileOpenDialog->SetTitle(L"Select any file under a Library");
   FILEOPENDIALOGOPTIONS fileOpenDialogOptions;
   fileOpenDialog->GetOptions(&fileOpenDialogOptions);
   fileOpenDialogOptions ^= FOS_FILEMUSTEXIST;
   fileOpenDialog->SetOptions(fileOpenDialogOptions);
   if (fileOpenDialog->Show(window) == HRESULT_FROM_WIN32(ERROR_CANCELLED))
      return;

   LPWSTR filename = NULL;
   fileOpenDialog->GetFileName(& filename);
   IShellItemPtr folderShellItem;
   fileOpenDialog->GetFolder(& folderShellItem);
   LPWSTR folderShellItemName = NULL;
   folderShellItem->GetDisplayName(SIGDN_FILESYSPATH, & folderShellItemName);

   IShellItemPtr resultShellItem;
   fileOpenDialog->GetResult(& resultShellItem);
   LPWSTR resultShellItemName = NULL;
   resultShellItem->GetDisplayName(SIGDN_FILESYSPATH, & resultShellItemName);

   wostringstream b;
   b << L"IFileOpenDialog::GetFileName():" << endl << (filename ? filename : NullString) << endl << endl
     << L"IShellItem::GetDisplayName() on IFileOpenDialog::GetFolder():" << endl << (folderShellItemName ? folderShellItemName : NullString) << endl << endl
     << L"IShellItem::GetDisplayName() on IFileOpenDialog::GetResult():" << endl << (resultShellItemName ? resultShellItemName : NullString);

   CoTaskMemFree(filename);
   CoTaskMemFree(folderShellItemName);
   CoTaskMemFree(resultShellItemName);

   MessageBox(GetDesktopWindow(), b.str().c_str(), L"Results of dialog", MB_OK);
}

Voilà.

Resources:

  • Windows 7: Empower users to find, visualize and organize their data with Libraries and the Explorer
  • Windows Application Quality Cookbook

     

  • Posted by yvesdolc | 0 Comments

    Getting a list of all the subscribers to an event with WinDbg and SOS

    I was wondering and Lee Culver from the CLR Quick Response Team was kind enough to give me an answer. The output below is for CLR V4 so the format might be a bit different than V2. "The debugging session below was identical in v2 except for SOS formatting differences."

    Enjoy and thanks Lee! 

    There’s no magic to it, you just walk the object until you find what you are looking for.  This object has an event called Foo:

     

    0:000> !do 0000000002dabe68

    Name:        Test

    MethodTable: 000007ff00044700

    EEClass:     000007ff00162510

    Size:        24(0x18) bytes

    File:        D:\dd\clr\src\binaries\AMD64chk\events.exe

    Fields:

                  MT    Field   Offset                 Type VT     Attr            Value Name

    000007ff00044b48  4000001        8               Test+T  0 instance 0000000002dabf48 Foo

     

    0:000> !do 0000000002dabf48

    Name:        Test+T

    MethodTable: 000007ff00044b48

    EEClass:     000007ff001629e8

    Size:        64(0x40) bytes

    File:        D:\dd\clr\src\binaries\AMD64chk\events.exe

    Fields:

                  MT    Field   Offset                 Type VT     Attr            Value Name

    000007feef8b3bc0  4000046        8        System.Object  0 instance 0000000002dabf48 _target

    000007feef8b3bc0  4000047       10        System.Object  0 instance 0000000000000000 _methodBase

    000007feef8b7388  4000048       18        System.IntPtr  1 instance      7ff0003aca8 _methodPtr

    000007feef8b7388  4000049       20        System.IntPtr  1 instance      7ff00044a10 _methodPtrAux

    000007feef8b3bc0  400004a       28        System.Object  0 instance 0000000002dabf18 _invocationList

    000007feef8b7388  400004b       30        System.IntPtr  1 instance                2 _invocationCount

     

    This has the object (_target), a method pointer (!dumpmd on _methodPtrAux or if it’s null, ln on _methodPtr), and an optional invocation list.  If the event has multiple subscribers, then _invocationList will be non-null:

    0:000> !da -details 0000000002dabf18

    Name:        System.Object[]

    MethodTable: 000007feef89b3c8

    EEClass:     000007feeef17718

    Size:        48(0x30) bytes

    Array:       Rank 1, Number of elements 2, Type CLASS

    Element Methodtable: 000007feef8b3bc0

    [snip tons of output, all of your subscribers here]

     

    Posted by yvesdolc | 0 Comments

    Is MFC 2008 Feature Pack fighting my will?

    I modify some MFC user interface related code, build, run and … nothing changes!

    “Well, let’s manually delete the Debug directories and all generated files, then rebuild.”

    I can still see my initial user interface layout! I go back to the code; double check what I did is correct, rebuild, STILL NO VISUAL CHANGE!

    I did the previous steps several times when it hit me: the layout is stored/saved in the registry between executions! From the documentation:

  • Save and restore toolbar and menu states to the registry.

  • Access the workspace manager that persists customization settings to the registry.

     

    What if there would be a bug in that part? Thanks to that line in my wizard generated application class:

       SetRegistryKey(_T("Local AppWizard-Generated Applications"));

    I know where to look for the registry key I need to delete!

    By the way, I hope that by the time we release Visual C++ 10, we’ll finally have dropped those TCHAR.H macros! It’s close to 2009 and the world has definitively been going Unicode for a while now! But I digress…

    I rebuild my application again and try it: the last version of my user interface there! So there’s a bug in “our” MFC code.

    I ended up adding the following post-build event to each configuration for now:

       reg.exe DELETE "HKCU\Software\Local AppWizard-Generated Applications\$(TargetName)" /F

  • Posted by yvesdolc | 0 Comments
    More Posts Next page »
     
    Page view tracker