One of the main uses for my blog is to share those little annoyances that I spend hours or days solving and spare you the “fun” of going through this yourself. So, even though this isn’t really about application compatibility, which has kind of become the main theme here, it will still hopefully help save somebody some time (thanks to search engines).
I recently picked up a new laptop (Lenovo T61p, FWIW) and got everything set up according to my typical usage scenarios. I was then going about building some code, and discovered that in the transition, several of my builds had broken.
Weird, I thought. We recently moved some MFC updates and the addition of TR1 extensions to C++ from a separate feature pack into Visual Studio 2008 SP1. I was getting all of the MFC extension bits. I was missing some of the TR1 extension bits. I indexed all of the header files, and they just plain weren’t there. The shared_ptr class, for example, lived in zero header files on my hard drive.
What happened?
The fix, of course, is to just re-install Visual Studio 2008 SP1. But what broke it?
It turns out that the Windows SDK lays down files not only in C:\Program Files\Microsoft SDKs\Windows\v6.1\Include, but takes the liberty of laying down (older) files in C:\Program Files\Microsoft Visual Studio 9.0\VC\include. Yep – it up and clobbered the SP1 header files and broke my builds.
So, if you install the Windows Vista SP1 / Windows Server 2008 SDK, you may want to re-install VS2008 SP1 afterwards…
A question came up via comments. (I was going to say that it came up recently, but another glance reveals that it came up in, oh, June. I don’t think I can fairly call that recent…)
“…the fix seems only to work if the directory structure exists…”
This is true, and worth noting. If you point the fix to a directory which doesn’t exist, the shim won’t create the directory, it will just fail, in much the same way the application would fail if it were trying to create an application in a directory which didn’t exist (which, to Windows, appears to be exactly what happened). So, if you’re planning to shim an application and want to create a directory to store things, you should consider creating this directory at install time.
When you come across issues debugging applications, there are typically several ways to solve them. Today, I'm going to pick on our own stuff and throw a few different shims at it. Interestingly enough, what I'm going to be shimming up will be the tool I use to create shims: Compatibility Administrator. That's right - I'm going to shim up my shim tool.
What's the bug?
---------------------------
Compatibility Administrator
---------------------------
You do not have administrative rights. Some features might be disabled.
---------------------------
OK
---------------------------
Yeah - I don't enjoy warnings like that, and I certainly don't need them every time.
Solution #1: shim up CompatAdmin.exe with RunAsAdmin. That makes the MessageBox go away because it actually is an admin.
What else could we do? Well, we could figure out which functionality need admin rights. Sitting there using the product non-elevated, I counted two broken features. First, I can't right click and disable a shim. Second, I can't install a shim database.
I don't really need to disable things often, and it seemed to me that installing is something that could be factored out. In fact, a quick glance at Process Monitor tells me that installing a shim database already is factored out! CompatAdmin.exe just calls sdbinst.exe. Is it calling it using CreateProcess (which would require ElevateCreateProcess) or ShellExecute(Ex)? ShellExecute. Nice. So, in theory the think I need to do actually should work just fine, except the software is stopping me from doing it!
---------------------------
Compatibility Administrator
---------------------------
You need administrative rights to perform this operation.
---------------------------
OK
---------------------------
A big fat LUA Bug in our own stuff. It stops me from doing something that works because it doesn't believe it does. Nice work. Let's lie to it.
Solution #2: shim up CompatAdmin.exe with ForceAdminAccess. The dialogs go away, and I can still do what I actually want to do - right click install works just fine, and prompts me when I do that. I then end up running less code elevated, and being more secure. I can read existing databases without elevations. What a huge win! (Well, except not being able to turn shims off, which may be interesting from time to time, but for the vast majority of what I do, this is a great solution.)
Are we done yet, or is there another way to skin this problem?
Well, these are messageboxes. We can suppress them one last way.
Solution #3: shim up CompatAdmin.exe with IgnoreMessageBox (parameter You do not have administrative rights. Some features might be disabled.,Compatibility Administrator). We'll get that to stop annoying me! It still shows the MessageBox when I try to install a database (which is not helpful) but if I suppress that one also, then it just does nothing and says nothing, which is arguably not a very good outcome. But at least it's a touch less chatty. I'll chalk this up as the worst solution.
Personally, I've been using ForceAdminAccess lately. But I thought this was a fun app to show the options available, particularly since you need to shim CompatAdmin somehow to make it useful. (Yeah, I know - that's kind of ridiculous and we should fix it. The bug has been open for over a year - I just poked the team again.)
It's been a couple of months since we released the Windows Vista Compatibility Center, and while I meant to discuss it at the time, it's still worth a little chat.
I talk quite a bit about the tools to test for application compatibility, sharing debugging tips, and shedding some light onto the secrets of shimming up misbehaving apps. The fact remains, however, that although you can fix a huge number of things (and hopefully I can help you figure out how), the fact that you can fix things up may not be relevant. If you need the vendor to support it, the fact that it's shimmed means, almost by definition, that it doesn't truly work on Windows Vista without a little help. And the fact that it doesn't truly work almost always means that it's unsupported. And the fact that it's unsupported almost always means that some people simply won't run that version.
Now, the original idea we had for Windows Vista was to introduce a new level of certification. One that was so easy, and so inexpensive, that everyone would want to collaborate to indicate compatibility. We called it the Works With Windows Vista logo. You don't have to pass any tests, and you don't have to enlist the help of a 3rd party tester to verify those tests. It's so easy, who wouldn't do it?
And, as it turned out, most everybody wouldn't do it. The original plan was to wire things up to ACT to pass this logo information through, automate the application matches, and help accelerate the process of determining support. As you have probably figured out, that didn't work out so well.
So, we had to scramble to create a Plan B. If developers weren't coming to us, but the enterprise still needed help, fine. We'd come to them. We hired some folks to start scouring ISV web sites to find support statements, and we published links on a site we stood up called appreadiness.com. It kind of looked cobbled together, because it was, but it was better to have something.
While we filled that up, we were working on a more eloquent looking solution - something we called the Windows Vista Compatibility Center. This is the new site.
Are we done helping you with this data yet? Absolutely not! First of all, you may have noticed that ACT is still looking at the sparse certification data, and not this new source of information. So, clearly we have to wire that up. We also need to better support automating the matching for people who don't want to submit what apps they have (which ACT does to fetch the compat data for those apps), so we need to figure out how to make the data available offline. And wouldn't it be interesting to have this as a web service to feed other tools?
So, while there's clearly more work to come to make this easier and to work better with our partners and the software ecosystem, I thought it was worthwhile to reflect on where we are, how we got here, and where we're going.
It seems like just yesterday I was posting about ACT 5.0.2 being released, but we just released ACT 5.0.3.
Now, I've had a couple of people confused about the version numbers we talk about, and what they actually see. For, rather unfortunately, you didn't see 5.0.2 anywhere in the last one, nor will you see 5.0.3 in the new one. Why don't we do you the honor of showing that in the help - about? As it turns out, we branched way back when at RTW, so the Main branch lived on, while the RTW branch was where we finished things up. As it turns out, the 5.0.1, 5.0.2, and 5.0.3 updates where all released off of the RTW branch, so 5.0.5428.x has remained the naming convention, and we have just kept incrementing the build number.
ACT 5.0.2 == 5.0.5428.1056
ACT 5.0.3 == 5.0.5428.1080
So, that being said, what's new in the 1080 release?
- Update Compatibility Evaluator: The Update Compatibility Evaluator now supports Windows Vista and Windows Server 2008 (Windows 2000, Windows XP, and Windows Server 2003 were previously supported)
- Windows Internet Explorer 8 Support: We now support Windows Internet Explorer 8. The Internet Explorer Compatibility Evaluator as well as the Internet Explorer Compatibility Test Tool are capable of identifying issues on websites and web applications when they are run on Windows Internet Explorer 8.
Major Bug Fixes:
SUA:
- SUA no longer crashes when the Application Verifier log entry is badly formed
- No longer Fails to create shim database entries if the product name contains special characters
- The CorrectFilePaths shim applied by SUA used to only fix a single path - this has been resolved and it now is applied correctly
ACM:
- The Application Compatibility Manager no longer requires elevation of user privileges to run on Windows Vista (HOORAY!!!)
It does require you to uninstall the old toolkit first, and then install the new one. The schema changed, so you'll have to upgrade your database also (warning if you've got apps or scripts crawling around in there). Hopefully it's helpful!
A question came up in one of the comments asking me to please define TrustedInstaller. I've talked about it before a few times, but I've never gone through and dug through the implementation in a visible way. Time to change that - and we can do so with the help of some built-in command line tools, with a little power assist from Sysinternals.
Here's the dialog you can have with these tools to illustrate how this works, so you can see it rather than just reading somebody tell you about it:
c:\Windows>REM What does the ACE actually say?
c:\Windows>icacls explorer.exe
explorer.exe NT SERVICE\TrustedInstaller:(F)
BUILTIN\Administrators:(RX)
NT AUTHORITY\SYSTEM:(RX)
BUILTIN\Users:(RX)
Successfully processed 1 files; Failed processing 0 files
c:\Windows>REM OK, let's get the SID for that...
c:\Windows>psgetsid "NT SERVICE\TrustedInstaller"
PsGetSid v1.43 - Translates SIDs to names and vice versa
Copyright (C) 1999-2006 Mark Russinovich
Sysinternals - www.sysinternals.com
SID for NT SERVICE\TrustedInstaller:
S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464
c:\Windows>REM This SID is one of the new Service SIDs in Windows Vista
c:\Windows>REM How do we verify which one? sc.exe has a new option
c:\Windows>sc showsid TrustedInstaller
NAME: TrustedInstaller
SERVICE SID: S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464
c:\Windows>REM yep - it's the same one! How does this appear in the
c:\Windows>REM services MMC console?
c:\Windows>sc getdisplayname TrustedInstaller
[SC] GetServiceDisplayName SUCCESS
Name = Windows Modules Installer
c:\Windows>REM And there you have it - here's the principal you're looking for
I had a comment come up on an earlier post:
"FYI, I've hit a limitation with CorrectFilePaths - the maximum amount of data that can be entered in the parameter field is 512 bytes - not enough to fix more than 2 files under "Program Files" unfortunately..."
Now, I knew the limitation existed, but I had never spent the time to understand the exact limitation, or where it existed. Is the limitation in Compatibility Administrator when it generated the XML for the SDB compiler? If so, we could always be sneaky and edit the XML before the compiler was run. Is the limitation in the SDB compiler? It's a lot more work, but if so we could always be sneaky and reverse the SDB format to add additional information. Or is the limitation in the shim engine itself, which makes being sneaky quite challenging indeed?
And the answer is that the limitation is in the shim engine itself. We can see that with a bit of reverse engineering.
The API that the shim engine calls happens to be publicly documented, so that makes our job easier. It's SdbReadStringTag. Here's where we actually pull the command line:
0x6C105914: 6800040000 PUSH 0x400
0x6C105919: 56 PUSH ESI
0x6C10591A: 50 PUSH EAX
0x6C10591B: FF7508 PUSH DWORD PTR [hSDB <Void *>]; ARG:EBP+0x8
0x6C10591E: 66891E MOV WORD PTR [ESI],BX_IS_ZERO
0x6C105921: E865260000 CALL __imp__SdbReadStringTagRef@16; (0x6C107F8B) ; SdbReadStringTagRef
Since this is a __stdcall function, arguments are passed right to left. The first PUSH, therefore, corresponds to __in DWORD cchBufferSize, and this is what limits the command line.
So, we know that the command line is limited to 0x400 characters (1,024), and the limitation is implemented in the shim engine itself.
Shims that require longer command lines, such as CorrectFilePaths, you therefore need to be careful with. If you can shorten the command line by only taking the portion of it you need, that is helpful. If you can leverage file and registry virtualization for fixes, that leaves you more of your 1,024 characters to work with as well!
If you run the Internet Explorer Compatibility Evaluator on Windows Vista, you get back some data when an ActiveX control tries to write to a file that a standard user used to be able to write to. However, that data doesn't show up when you are using the Internet Explorer Compatibility Test Tool.
Why?
It's configured not to.
Why?
Um ... I don't know? (Perhaps because the quality of the output is qualitatively different than every other test in the tool?)
But I do know how to turn it back on.
Open up Notepad elevated, and then open up "C:\Program Files\Microsoft Application Compatibility Toolkit 5\Internet Explorer Compatibility Test Tool\IECEConfig.xml".
If you then search for the word EXCLUDE, you'll find this:
<EXCLUDE>VirtualizationAction:AcTraceIgnored;</EXCLUDE>
Just comment this out (or delete it) and we'll stop excluding data from the view. Now your tool is configured to stop hiding data that must be useful. Is it perfect? Nope - it doesn't collect it all. But at least it shows you what it did collect.
Why doesn't it collect it all? I don't know, but I can speculate. The Internet File System and Internet Registry are implemented on IE7 using shims (specifically, shims sitting in acredir.dll, such as RedirectFiles and RedirectRegistry). While most of IECE's output is based on the browser itself, the browser would have to predict what the shim infrastructure was doing. While you can turn on shim diagnostics and pull some of this out depending on the debug spew and log spew the shim writer included, that really complicates things. So, unlike rules where the browser explicitly knows "hey, I'd have to do this bad thing which the following code will specifically prevent, better log it" here we have API interception happening at a completely different layer where the browser code would have to either attempt to predict (could have false outcome), hook into the shim infrastructure, or parse ACLs and duplicate security logic.
But the things we are detecting, we really ought to show, wouldn't you agree?
8-Aug-2008: Added details on my abbreviations (per comment)
7-Aug-2008: Updated to fit the table into the width of the column for web readers...
...And I'm back. I've been conspicuously absent for a while because I was furiously preparing for TechReady 7 (an internal conference for the Microsoft field), and during the middle of that conference I decided to break my arm. I've been reviewing my scores publicly for a while to elicit external feedback, so I figured I'd continue that trend here.
The sessions I delivered were:
Shims1: CLI315 - Mitigating Application Issues Using Shims Part 1
Shims2: CLI403 - Mitigating Application Issues Using Shims Part 2
Debugging: CLI400 - Debugging Application Compatibility Issues
PjM1: CLICT300-R1 - Application Compatibility Project Best Practices
PjM2: CLICT300-R2 - Application Compatibility Project Best Practices (Repeat)
Once again, let's take a look at my ratings relative to my peers. Last time I was looking specifically within the Windows Client track but this time around let's compare scores to the conference as a whole:
| TR7 | Shims1 | Shims2 | Debugging | PjM1 | PjM2 |
| Knowledgeable | 2 | 1 | 6 | 11 | 73 |
| Presentation Skills | 7 | 1 | 5 | 54 | 93 |
| Content | 5 | 2 | 12 | 99 | 92 |
| Demos | 5 | 5 | 6 | 76 | 39 |
| Builds Skills | 8 | 2 | 15 | 66 | 111 |
| Relevant | 22 | 4 | 33 | 57 | 90 |
| Worth My Time | 13 | 2 | 9 | 61 | 111 |
| Will Recommend | 5 | 1 | 11 | 84 | 116 |
| Overall | 6 | 1 | 11 | 68 | 112 |
| Average | 6 | 2 | 10 | 62 | 97 |
And some of the comments:
"This was the best and what i had expected out of every technical session at TR. thanks for skipping the marketing decks!"
"GREAT presentation without PPT. Other presenter have to do the same. We are here to see how it's working, not print screen."
"I appreciated the demo-centered approach to presenting. Chris has a wealth of knowledge and he is a very good teacher."
"This was the only true 400 level content of all the classes that I did attend. This was beyond my skill level, but the presentation skills of the presentor kept me awake and interested"
"I loved it, hardcore to the bone!"
"I lack most of the pre-req skills to really take advantage of the insight & info presented in this session. 20 years ago when I joined MS I was very good at Dissasembing Apps. I've not used it since. So I'm skilled enough to see he did a great talk & also to realise that I'd need a lot more coaching before I could replicate what he showed me. Great Talk."
My learning:
Dispensing with the PowerPoints is goodness. That's right. PPT, be gone with you from my technical sessions! They're still there for you to take home, but I don't need to read to you. I took my shim sessions, which have traditionally done fairly well, and rocketed them up to the top of the entire conference by just doing away with PPT. #2 session in the conference, #1 on 4 attributes (including overall). Pure goodness.
You can go too hard-core. Debugging Application Compatibility Issues was a top session in the conference, but I didn't leave enough breadcrumbs for folks. You should walk away from every talk knowing something more than you did when you came in. If you walk away feeling like you can't do any of that, then it's just a show, and not educational. Fun, but almost as helpful as a box of hair. Take it from deep to deeper to deepest - don't just start way in the depths with a screen full of assembly language.
I'm not so good at chalk talks. Now, to be fair, I did deliver one with an untreated broken arm, but I think the scores speak for themselves even for my able bodied session. I tried to make it interactive because I wanted feedback on project management, but clearly I should bring in talent better suited for that goal.
I need to make sure to keep it relevant. The scores aren't horrible here, but they're the weakest link. Perhaps I should start polling the audience more. And, for anyone attending an upcoming conference, feel free to tell me what matters to you. I'm trying to base what people are interested in by the questions that get funneled my way, but I'll communicate with you any way that I can.
Thanks again to anybody who attended - I hope you enjoyed the demos and the absence of PPT! See some of you at TechEd EMEA! (And perhaps at PDC - that's not locked in yet.)
I've got a pile of topics to cover that have backed up in the queue, so now back to your regularly scheduled geekiness...
Here's an interesting lesson which, quite honestly, I haven't thought about for a while. But it turns out it's rather important.
A little over a month ago, I talked about a change to Windows Vista in SP1 regarding per-user COM registration, indicating that we changed the behavior and it would now work with UAC disabled. Let's dissect how this is implemented specifically. First, I disassembled the function, and then I focused in on the CALL instructions, to find:
0:010> uf ole32!OpenClassesRootKeyExW
251 760878ba e888ffffff call ole32!RegHelpSuspendImpersonate (76087847)
257 760878c5 ff15e4110676 call dword ptr [ole32!_imp__GetCurrentProcess (760611e4)]
257 760878cc ff159c160676 call dword ptr [ole32!_imp__OpenProcessToken (7606169c)]
261 760878e1 e8c9000000 call ole32!IsUserHiveOK (760879af)
265 760878fd ff1554160676 call dword ptr [ole32!_imp__RegOpenUserClassesRoot (76061654)]
269 760f9014 e8fe430100 call ole32!WPP_SF_d (7610d417)
283 76087922 ff15fc160676 call dword ptr [ole32!_imp__RegOpenKeyExW (760616fc)]
286 760f905b e8b7430100 call ole32!WPP_SF_d (7610d417)
290 76087935 ff15e4130676 call dword ptr [ole32!_imp__CloseHandle (760613e4)]
294 760f9065 ff150c140676 call dword ptr [ole32!_imp__GetLastError (7606140c)]
295 760f90a1 e871430100 call ole32!WPP_SF_d (7610d417)
298 7608793e e811010000 call ole32!RegHelpResumeImpersonate (76087a54)
304 76087966 ff15fc160676 call dword ptr [ole32!_imp__RegOpenKeyExW (760616fc)]
307 760f90e3 e8dfd70100 call ole32!WPP_SF_Sdd (761168c7)
309 76087979 ff15f4160676 call dword ptr [ole32!_imp__RegCloseKey (760616f4)]
That ole32!IsUserHiveOK looks interesting, so let's chase that down and see what we find, again just focusing in on the call statements:
0:010> uf ole32!IsUserHiveOK
200 760879cc e83c000000 call ole32!IsElevatedToken (76087a0d)
205 760879e5 e83ae2ffff call ole32!GetTokenElevationType (76085c24)
221 760941e8 e81a000000 call ole32!IsUIAccessToken (76094207)
This is, indeed, interesting. We're checking IsElevatedToken, and then we're calling GetTokenElevationType. What can TokenElevationType tell us? Let's check MSDN:
The TOKEN_ELEVATION_TYPE enumeration indicates the type of token linked to the token being queried by the GetTokenInformation function or set by the SetTokenInformation function.
Syntax
typedef enum {
TokenElevationTypeDefault = 1,
TokenElevationTypeFull,
TokenElevationTypeLimited
} TOKEN_ELEVATION_TYPE ,
*PTOKEN_ELEVATION_TYPE;
Constants
- TokenElevationTypeDefault
-
The token does not have a linked token.
- TokenElevationTypeFull
-
The token is linked to an elevated token.
- TokenElevationTypeLimited
-
The token is linked to a limited token.
We can see how, using both elevation state and TokenElevationType, we can determine both the elevation state and if UAC is enabled or disabled. So, we've unraveled what's happening for COM.
But, almost immediately after posting, people began posting about exceptions to the rule, which we began investigating. The lesson here: OLE != OLE Automation. They are different things. And it turns out that OLE Automation doesn't have the fix we incorporated into COM itself. They're different code, incorporated into different DLLs, maintained by different teams. What does OLE Automation do? Let's take the same approach, disassembling the function and zeroing in on the calls it makes:
0:010> uf oleaut32!OpenClassesRootKeyExW
150 75a49f80 e8c7feffff call OLEAUT32!SuspendImpersonate (75a49e4c)
151 75a49f8b ff151412a475 call dword ptr [OLEAUT32!_imp__GetCurrentProcess (75a41214)]
151 75a49f92 ff157413a475 call dword ptr [OLEAUT32!_imp__OpenProcessToken (75a41374)]
155 75a49fad e8cafeffff call OLEAUT32!IsProcessElevated (75a49e7c)
159 75a5ab15 ff153413a475 call dword ptr [OLEAUT32!_imp__RegOpenUserClassesRoot (75a41334)]
173 75a49fd4 ffd3 call ebx
178 75a49fdc ff151012a475 call dword ptr [OLEAUT32!_imp__CloseHandle (75a41210)]
182 75a78782 ff15ec11a475 call dword ptr [OLEAUT32!_imp__GetLastError (75a411ec)]
185 75a49fe8 e842000000 call OLEAUT32!ResumeImpersonate (75a4a02f)
191 75a4a05e ffd3 call ebx
192 75a4a066 ff158013a475 call dword ptr [OLEAUT32!_imp__RegCloseKey (75a41380)]
Things look a bit different here - all we call is IsProcessElevated. If you're running as admin with UAC disabled, this returns true - and the function never calls in to determine the token elevation type. OLE Automation did not get the same update that COM did!
Now, from the Windows side of things, we already have a bug open to fix this, but since I spread the word that it's working and some of you have contacted me suggesting that it isn't, I wanted to make sure it was clear: COM was, indeed, fixed to work with per-user registrations and UAC disabled, but OLE Automation was not.
What can you do in the interim? These are the workarounds I have heard about so far:
- Use MIDL generated proxy/stub marshalling for interfaces instead of type libraries
- Load the type library from the COM dll directly instead of reading it from the per-user registry hive
Incidentally, for those of you who were perplexed that Live Mesh was released but didn't support running as admin with UAC disabled until Windows Vista SP1 ... what do you think the odds are that there are some per-user COM registrations in there? Hmm...
About a month ago (can you tell I'm a little behind?) we launched the Windows Client TechCenter. My little corner of the site (which is technically at http://technet.microsoft.com/en-us/windows/aa905066.aspx but it's easier to remember http://technet.com/appcompat or http://technet.microsoft.com/en-us/appcompat/default.aspx) dives in to application compatibility and UAC.
There are two things I've been hearing a lot from customers lately. The first is that we need to focus more on the process, providing project plans and making it easier to get started while helping people feel more confident that they haven't missed something along the way. That's a long-term project I'm working on - I presented an overview of our current best practices thinking at both MMS and TechEd this year. The second is to organize all of the knowledge that we have. I remember when we used to struggle just to make knowledge available. Now, we have so much knowledge available, it's hard to find the information which you need.
The TechCenter is my first attempt at helping with the second item. I included key resources and overview materials, and then split out deeper dive materials by role: Project Managers, Testers, Debuggers, and Developers. Within each role, I have attempted to find the best documents (most of which include links for further reading if you find something which strikes a chord in you).
I welcome any feedback - have we hit the right roles? Have we given enough information per role? Collecting knowledge is the easy part - indexing it is harder. It's not quite an end to end learning plan, but I hope it's a valuable first step which we can evolve and continue to make better!
I send out a lot of links to my articles in response to questions that come up, but the other day I had a chance to use a pile of them to solve a fairly complicated problem end to end. So, I figured I'd share how we can piece together all of this knowledge to solve a more sophisticated problem.
Let's begin at the beginning. The CorrectFilePaths shim wasn't working. We were trying to redirect c:\somedata.txt to %userappdata%\somedata.txt, but it wasn't working. Why not? We weren't sure.
So, we started out by turning on shim debug spew to see if the shim was being wired up. Indeed it was - we could see it picking up the shim when we launched the process. We could also look at the process in Process Monitor and see in the stack that the call to write c:\somedata.txt was passing through AcLayers!NS_CorrectFilePaths::APIHook_CreateFileA. So, we knew that the shim wasn't improperly applied.
Our next hypothesis, then, was that the shim's command line was not configured properly. I tried copying and pasting from Process Monitor in case there was a copy error, but no such luck. So, it was time to go in with a debugger and see what was happening.
Now, where do we set the debugger breakpoint? Well, why not when we enter the shim? So, I set a bp on AcLayers!NS_CorrectFilePaths::APIHook_CreateFileA and took a look at the arguments we were passing to this function. What did I see?
\somedata.txt
Indeed, it never specified the C drive - just the root of whatever drive you happened to be running on. And, since CorrectFilePaths just uses a literal string match, the c: was causing the match to fail.
Replace that argument with \somedata.txt;%userappdata\somedata.txt and everything worked fine!
So, using a bit of knowledge of Process Monitor, a bit of knowledge on the Debugging Tools for Windows, and knowledge from this blog, we could actually solve a real-world problem. And that's what I like to see. Let me know if you are finding gaps that nobody is talking about yet, and we'll see if we can get them filled here!
At TechEd last week, I had the opportunity to sit on a panel of bloggers and answer any and all questions people wanted to come and throw at us. We had a mixture of pre-submitted questions and audience questions, and overall it was great fun.
Joining in the panel were:
Have a look, and if you don't think we were given hard enough questions, then we hope to do this again at TechEd EMEA. Thanks to everyone who asked questions, watched the show online, or stopped by and hung out with us live.
If you didn't get a chance to see it, it's available for download now:
http://technet.microsoft.com/en-us/events/teched/cc561184.aspx
(It's the 3rd video down the list as of today.)
Last week, we updated the documentation for the Application Compatibility Toolkit. It's kind of hidden, though - if you go to the Application Compatibility Toolkit download page, you will find a new item in the list of files:
ACT50_Doc_Update_Installation_Instructions.zip (1.9 MB)
It's got a bit of a silly name (because it's not just instructions - it's the update also) and a silly package (or no package, really - you drag and drop the new chm into a protected Program Files folder, so you'll get UAC prompted), but it is goodness.
Liz Ross is the technical writer who creates the docs for ACT. She's got some other goodies as well, and this is the latest manifestation of the workflow we've put together. I'm busy translating shim docs from source code to geek, and she's busy translating them from geek to human.
Have a look. I'm particularly interested in getting shim documentation out faster, and hopefully updating without waiting for the next release of ACT can help you be more effective resolving application compatibility issues.
We'd love to hear your feedback on the updated docs!