SWC and XP

Link. February 22, 2003. Comments [0]. Posted in: Enterprise Services
Christian Weyer asks why Services Without Components is broken on Windows XP. I don't know the exact details of it, but I do know a few things I found out after lurking a while.

Keep in mind that last time I took a look at this was a few months ago, so it might have changed, but I highly doubt it.

Transaction support for SWC is configured through the IServiceTransactionConfig interface. Now, the original interface, with an IID of {772b3fbe-6ffd-42fb-b5f8-8f9b260f3810} is indeed supported on WinXP, and it sort of works. Or at least, it looks like it. [1]

However, it turns out, if I may say so myself, that someone made a bad versioning decision for .NET server, and went against all the COM versioning practices used before. In .NET Server, IServiceTransactionConfig supports 1 other method: ConfigureBYOT().

The problem is, it's not that they redefined the interface. Worse, they renamed it. So, in previous PSDK headers we had the following definition for IServiceTransactionConfig:


    MIDL_INTERFACE("772b3fbe-6ffd-42fb-b5f8-8f9b260f3810")
    IServiceTransactionConfig : public IUnknown
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE ConfigureTransaction( 
            /* [in] */ CSC_TransactionConfig transactionConfig) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE IsolationLevel( 
            /* [in] */ COMAdminTxIsolationLevelOptions option) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE TransactionTimeout( 
            /* [in] */ ULONG ulTimeoutSec) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE BringYourOwnTransaction( 
            /* [string][in] */ LPCWSTR szTipURL) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE NewTransactionDescription( 
            /* [string][in] */ LPCWSTR szTxDesc) = 0;
        
    };

Notice, however, there's no ConfigureBYOT() method, even though the PSDK docs mentioned it was there. What we have now are two interfaces: IServiceTransactionConfigBase, and IServiceTransactionConfig, which inherits from the first one.

There's the rub. What is now named IServiceTransactionConfigBase is exactly what used to be called IServiceTransactionConfig, and has the same GUID; they just renamed it, and created a new interface with the same name as the old one with a new GUID which is only supported in .NET Server. The definitions for these new interfaces are:


    MIDL_INTERFACE("772b3fbe-6ffd-42fb-b5f8-8f9b260f3810")
    IServiceTransactionConfigBase : public IUnknown
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE ConfigureTransaction( 
            /* [in] */ CSC_TransactionConfig transactionConfig) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE IsolationLevel( 
            /* [in] */ COMAdminTxIsolationLevelOptions option) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE TransactionTimeout( 
            /* [in] */ ULONG ulTimeoutSec) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE BringYourOwnTransaction( 
            /* [string][in] */ LPCWSTR szTipURL) = 0;
        
        virtual HRESULT STDMETHODCALLTYPE NewTransactionDescription( 
            /* [string][in] */ LPCWSTR szTxDesc) = 0;
        
    };

    MIDL_INTERFACE("59f4c2a3-d3d7-4a31-b6e4-6ab3177c50b9")
    IServiceTransactionConfig : public IServiceTransactionConfigBase
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE ConfigureBYOT( 
            /* [in] */ ITransaction *pITxByot) = 0;
        
    };

The reason this is terrible is because it breaks source code, even if it doesn't break binary code. If you compile your application agains the old headers, everything will [sort of] work fine on XP, even if you can't use ConfigureBYOT(), since it doesn't exist. (which is fine by me, btw). However, if you recompile it against the new headers, suddently it doesn't work on XP, because it picks up the GUID for the new definition of IServiceTransactionConfig, only existing on .NET Server (so QueryInterface() now fails). [2]

What they should have done, was leave IServiceTransactionConfig alone, and define a new interface with a new name, called IServiceTransactionConfigEx or IServiceTransactionConfig2 or whatever, which is what the common COM versioning rules of thumb are.

Up to a couple of months ago, this wasn't documented anywhere, and the PSDK docs still said that IServiceTransactionConfig, even with the new ConfigureBYOT() method, was supported on XP (which was now a lie, thanks to the GUID change). Not only that, but IServiceTransactionConfigBase is not documented anyway, either.

I just looked at the docs for the February 2003 Platform SDK documentations, and it seems this has been corrected. CoEnterServiceDomain() and friends are now documented as being supported on Windows Server 2003 only. And, in fact, the SWC support in the .NET Framework 1.1 will only work in WS 2003.... the ServiceDomain class won't even instantiate in XP. I was told in very certain terms that the public message from now on would be that SWC was NOT supported on XP.

[1] I have a feeling far more is broken below... I had a few issues with aborting transactions explicitly within a service domain last I fooled around with this...
[2] I haven't installed yet the latest PSDK, so I don't know if this blunder has been fixed...

5. März

Link. February 21, 2003. Comments [2]. Posted in: Personal
This is one of my favourite Megaherz songs (great band, if you like this kind of music!), and lately, I've been feeling sort of like the chorus of the song:
Du weißt nicht was du willst 
Du weißt nicht wo du stehst 
weißt nicht woher du kommst 
wohin du gehst 
Du weißt nicht was dich treibt 
was am Ende für dich bleibt 
Warum bist du so blass 
so kalt so herzlos 
Du weißt nicht was du tust 
weißt nicht woran du glaubst 
Sag mir wozu und ob 
du mich noch brauchst 
Wenn's einfach nicht mehr passt 
Wenn du mich wirklich nur noch hasst 
Warum bist du noch hier Wofür 
Was willst du noch von mir 

ServicedComponents and Exceptions

Link. February 17, 2003. Comments [0]. Posted in: Enterprise Services
Morten wonders about Enterprise Services and Exceptions. This is a topic that interests me greatly, and one I've had mixed success with.

For all I can see, having an object somewhere on your method signature (either as an argument or return type) ensures the custom exception is marshaled back to the client. It seems this needs to be of type object, too, because replacing it by some other reference type (like string), doesn't work, and you get back ApplicationException again.

But, alas, I'm not sure if this is just a side-effect, or this is indeed the real reason, which I highly doubt. Same appears to happen with the .NET framework v1.1, btw, at least insofar as I can see. Clues, anyone?

Meeting Don

Link. February 13, 2003. Comments [0]. Posted in: Personal
Finally got to meet Don yesterday.... he's quite the celebrity, posing for photos and stuff :)

AOP ServicedComponents

Link. February 7, 2003. Comments [1]. Posted in: Enterprise Services
I haven't blogged about this, since I imagined everyone had already seen it. But today Clemens announced he finally cracked one of the problems he had.

I can only say it sounds awfully cool, and look forward to seeing it in action myself!

Trip Next Week

Link. February 5, 2003. Comments [0]. Posted in: Personal
I guess this is as good a time as any other to announce I'll be all next week out of town.

I'll be arriving in Seattle on Saturday night, and leaving Friday at midnight. If anyone's in the area (and I believe a few of you guys will be), and cares to meet even for just a cup of coffe, let me know. I'd love to chat for a while!

Introducing Rotor: _CorExeMain2

Link. February 2, 2003. Comments [0]. Posted in: .NET
Today, I started looking at the runtime startup code. This journey begins in _CorExeMain2(), implemented in sscli\clr\src\vm\ceemain.cpp, which is declared like this:
__int32 STDMETHODCALLTYPE _CorExeMain2( // Executable exit code.
    PBYTE   pUnmappedPE,                // -> memory mapped code
    DWORD   cUnmappedPE,                // Size of memory mapped code
    LPWSTR  pImageNameIn,               // -> Executable Name
    LPWSTR  pLoadersFileName,           // -> Loaders Name
    LPWSTR  pCmdLine)                   // -> Command Line

The names of the arguments the function takes should be self-explanatory, specially if you look at the code in clix.exe. The function itself is fairly short, consisting mostly of error handling code. In a nutshell, it does this:

  1. Verify the strong name signature of the assembly, if there is one present, via the StrongNameSignatureVerification() function (implemented in sscli\clr\src\dlls\mscorsn\strongname.cpp
  2. Handle all command line arguments, and store them for later use
  3. Initialize the CLR Execution Engine
  4. Execute the actual Main() method of the module loaded
  5. Once this ends, cleanly shutdown the Execution Engine

There isn't much more to say about this, but I can't help but nitpick and poke around the things that are probably far less relevant than anything you might read elsewhere :) For example, I had no idea the Runtime could take command line arguments itself.... just try writing a simple application like this:

using System;
class Test
{
   public static void Main(String[] args)
   {
      Console.WriteLine(args.Length);
   }
}

Now, try running it with a command line like "App.exe -COR somethinghere"... and low-and-behold, it prints 0! The magic of this is inside the ParseCor() method of the CorCommandLine class, implemented in sscli\clr\src\vm\clsload.cpp. I must admit, though, that I was unable to actually find anywhere in the code they where used.

OK, now going back to the serious stuff. The EE initialization is done through the CoInitializeEE(), which handles some locking stuff and then calls the TryEEStartup() function, which itself calls the real potato: EEStartup().

At a glance, EEStartup does, among other things, initialize the Stack Probes and the event store, load configuration data (not the application .config file, though, not yet.), initialize the thread manager, remoting services and context system, the JIT, the GC, SyncBlock cache, the P/Invoke services, security subsystem, and, of course, setup the default domain. The configuration loading code is done by the EEConfig class, implemented in sscli\clr\src\vm\eeconfig.cpp

While this function is not really complicated per se, it sets up the entire VM execution environment. Thus, really understanding everything that's going on will take some more time. This is where the good stuff begins!

Syndicate

About

Tomas Restrepo is a software developer located in Colombia, South America. His interests include .NET, Connected Systems, PowerShell and lately dynamic programming languages. More...

tomasrestrepo @ twitter My Flickr photostream My saved links on delicious My Technorati Profile

email: tomas@winterdom.com
msn: tomasr@passport.com

View my profile on LinkedIn

MVP logo

Ads


Categories

Statistics

Total Posts: 1041
This Year: 111
This Month: 0
This Week: 0
Comments: 819

Archive

Other

Copyright © 2002-2008, Tomas Restrepo.

Powered by: newtelligence dasBlog 2.2.8279.16125

Sign In