M-A's

technology blog

Thursday, 17 January 2008

Understanding vsprops files

I've began using .vsprops files (along side .vcproj files) on VS2005 SP1. I discovered that you can do something that looks like that:
< ?xml version="1.0" encoding="Windows-1252"? >
< VisualStudioPropertySheet
projecttype="Visual C++"
version="8.00"
name="whatever" inheritedpropertysheets=".\randomprefix_$(RANDOM_ENVIRONMENT_VARIABLE).vsprops">
< /VisualStudioPropertySheet >
This is cool, you can modify which vsprops file will be inherited by an externally defined environment variable, before starting Visual Studio. Ok fine, then try further:
< ?xml version="1.0" encoding="Windows-1252"? >
< VisualStudioPropertySheet
projecttype="Visual C++"
version="8.00"
name="whatever" inheritedpropertysheets="$(SolutionDir)..\randomdir\random_file.vsprops">
< /VisualStudioPropertySheet >
Cool again! I can use locally defined variable in Visual Studio. Ok, then let's try to do something useful:
< ?xml version="1.0" encoding="Windows-1252"? >
< VisualStudioPropertySheet
projecttype="Visual C++"
version="8.00"
name="whatever" inheritedpropertysheets="randomprefix_$(ConfigurationName).vsprops">
< /VisualStudioPropertySheet >
It fails. :( That would have been useful: include a vsprops file named after the current configuration name (debug or release or whatever). Here a counter example:
< ?xml version="1.0" encoding="Windows-1252"? >
< VisualStudioPropertySheet
projecttype="Visual C++"
version="8.00"
name="whatever" outputdirectory="$(SolutionDir)$(ConfigurationName)" >
< /VisualStudioPropertySheet >
Yes, that actually works. In fact, you can even set « CharacterSet="1" » in the vsprops even if the VS vsprops editor doesn't allow you to set this (the same applies to WholeProgramOptimization). So it seems like $(ConfigurationName) and $(SolutionDir) aren't defined at the same time, which is normal. The way VS looks at the project file looks like this:

  1. Initial parsing
  2. For each Configuration in Configurations
    1. Load the InheritedPropertySheets attribute
      1. Open recursively the property sheets
    2. Load the Name attribute in Configuration in the vcproj
    3. Process property sheets
    4. Process the rest of the attributes
    5. Load the rest
The thing is that you can use $(ConfigurationName) in the OutputDirectory attribute but not in the InheritedPropertySheet. Too bad, what a missed opportunity. I somewhat tried playing with UserMacro but without any success.

Disclaimer: I didn't try with VS2008.
Disclaimer: I know the blogger's editor sucks and that I couldn't write real XML. In fact, they know it too. I just wished they cared. We're just all eager to have it actually fixed.

Sunday, 13 January 2008

The undocumented frustration

I had some frustration when updating WINVER and _WIN32_WINNT from 0x501 to 0600 (okay we're late but better be late than sorry). I came across two things I'd like to document.

---

First I need to reference Nicolas Sylvain post about GENERIC_MAPPING changes to give some background. Then all I have to say is that there are other access masks that changed, but explicitly. The ones we hit were PROCESS_ALL_ACCESS and THREAD_ALL_ACCESS. They have a new bitmask. Here are the definition:
#if (NTDDI_VERSION >= NTDDI_LONGHORN)
#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF)
#else
#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)
#endif

#if (NTDDI_VERSION >= NTDDI_LONGHORN)
#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF)
#else
#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF)
#endif
The nice thing is that the new bitmasks are refused by Windows XP. So you need to use different flags depending on the OS, which you need to define yourself. Not great! The easiest work around is to use MAXIMUM_ALLOWED but this is not always what you want.

---

The second one is nasty. The NONCLIENTMETRICS structure's size silently changed between XP and Vista. Here is the definition:
typedef struct tagNONCLIENTMETRICSW
{
UINT cbSize;
int iBorderWidth;
int iScrollWidth;
int iScrollHeight;
int iCaptionWidth;
int iCaptionHeight;
LOGFONTW lfCaptionFont;
int iSmCaptionWidth;
int iSmCaptionHeight;
LOGFONTW lfSmCaptionFont;
int iMenuWidth;
int iMenuHeight;
LOGFONTW lfMenuFont;
LOGFONTW lfStatusFont;
LOGFONTW lfMessageFont;
#if(WINVER >= 0x0600)
int iPaddedBorderWidth;
#endif /* WINVER >= 0x0600 */
} NONCLIENTMETRICSW, *PNONCLIENTMETRICSW, FAR* LPNONCLIENTMETRICSW;

WTL 8.0 has a workaround for this
but let's face it, it looks more as a hack than anything else. It looks like the guy at Microsoft that changed the structure should have wrote a unit test...
Anything that is written that looks like this is bound to fail:
NONCLIENTMETRICS cm = { sizeof(NONCLIENTMETRICS) };
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &cm, 0);
I don't blame Microsoft for doing small errors like this. Managing an operating system is a tremendous task and we all know errors can slip through. The real problem I see is that even one year after the release, it's still not documented. Let's hope the Vista SP1 SDK will define PROCESS_ALL_ACCESS_XP, THREAD_ALL_ACCESS_XP and NONCLIENTMETRICS_v1.

Friday, 4 January 2008

Risk of using embedded MSHTML

There is always some risks involved in using third parties in UI.



This one is cute: It is the "My Web Sites on MSN" wizard that is hit by the IE ActiveX security bar. But this is really nice inside a dialog box, knowing that it is pure Microsoft code.

It is funny because it gives the feeling that it is less secure while in reality it doesn't change anything since it is simply a side-effect of using MSHTML for rendering.