A blogban leírtak a szerzők saját véleménye, és nem a munkáltatójuké.

Metódushívás decoupled, singleton .NET-es WMI provider esetén

Az IRF tárgy egyik házi feladatában (4D) WMI providert kell készíteniük a hallgatóknak, ami egy .NET-es egyszerű webszerver menedzselését teszi lehetővé. Az egyik hallgató futott bele abba a problémába, hogy implementált egy metódust, de amikor WMI-on keresztül meg akarta hívni PowerShellből, akkor a provider leállt, a PowerShell ablakban meg látszólag nem történt semmi. Ránézve a kódra és a PowerShell Get-WmiObject hívásra látszólag minden rendben volt, az Eseménynaplóban találtunk csak egy részletesebb hibát, de első ránézésre az se segített sokat:

.NET Runtime version 2.0.50727.3082 - System.NullReferenceException:
Object reference not set to an instance of an object.
   at System.Management.Instrumentation.AutomationType.CalculateKey(ObjectDictionarydict)
   at PublishProvider.Get(CallContext context, ICIMResultHandler resultHandler)
   at WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(String objectPath, Int32 flags, IWbemContext wbemContext, IWbemObjectSink wbemSink)

Így aztán meg kellett közelebbről is vizsgálni a kódot, és kicsit jobban elmerülni a .NET WMI Provider Extensions lelkivilágában. WMI Providert alapvetően C++ nyelven lehetett írni bizonyos COM interfészek implementálásával, később aztán .NET támogatás is megjelent hozzá később. A 3.5-ös .NET Frameworkben újraírták ezt a .NET-est részt, és így született meg a WMI Provider Extensions, amiben egyszerűen attribútumok segítségével lehet definiálni, hogy mik a tulajdonságai, metódusai a providernek, majd az installutil elvégzi a MOF fájl generálást és a provider beregisztrálását. (Egy egyszerű .NET-es provider futtatásáról már írtam korábban.)

A providernek nagyon egyszerű teszt kódja volt, egy sima decoupled, singleton provider: egy osztály a statikus Main metódussal, és egy másik a WMI attribútumokkal. Az MSDN-es példakódtól egy dologban különbözött a kód, a WMI-ba regisztrálandó osztályok megadásánál:

// teszt kod: publish/revoke használata:
WmiProviderOsztaly m = new WmiProviderOsztaly();
InstrumentationManager.Publish(m);

// MSDN peldakod: registertype (callback) hasznalata
InstrumentationManager.RegisterType(typeof(WmiProviderOsztaly));

A két módszerről túl sok leírás nincsen, az InstrumentationManager leírásában ennyi szerepel:

Decoupled providers are hosted by an application. Two methods can be used by the application to make instances of WMI classes available: publish/revoke or the callback method. The callback method uses the RegisterType and UnregisterType methods.

In the publish/revoke model, the WMI infrastructure provides default behavior for many of the methods you have to write yourself in the callback method. These include the enumeration and bind methods. In this model, the application creates instances and publishes them. The application is responsible for ensuring that the key properties of the classes are respected. The application is also responsible for deleting instances.

In the callback model, the WMI infrastructure expects the application to have methods that handle enumeration, binding and any other methods required to implement the functionality of the provider. It calls into the application for this functionality and fails if it does not exist or is not implemented properly. The application registers the type of its WMI classes with the infrastructure by calling RegisterType and indicates that it no longer wants the WMI classes exposed by calling UnregisterType.

A Publish/revoke módszert használva a providerben, ha PowerShellből lekérjük a WMI objektumot, akkor a hívást sikeresen végrehajtja, a tulajdonságokat le lehet kérdezni. Viszont metódushívásnál a Powershell egyszerűen megáll, és a fenti kivétel kerül bele az eseménynaplóba.

A kivétel a Visual Studio debuggerében

Megnéztem Visual Studio 2008-ból indítva a providert, hogy ad-e valami további részletet a kivételről, azonban túl sok plusz információt nem szolgáltatott. Kaptam egy FatalExecutionEngineError-t:

wmi-provider-vs-error

A local és a callstack ablakok sem adtak túl sok útmutatást:

wmi-error-callstack

Itt most csak a GetObjectAsync hívás látszik, a kivétel stack trace-ében lévő többi hívás nem.

A kivétel WinDbg alól

Jobb ötletem nem volt, mint hogy ránézni WinDbg-gal, hátha ott jobban látszik, hogy mit történik a nem menedzselt kód hívásakor. Elindítottam a WinDbg-ot, File / Open executable, megadtam az alkalmazást, beállítottam a kezdő könyvtárat, majd lássuk mit ad:

wmi-provider-windbg

A debugger rögtön megállítja a folyamatot a létrehozása után, indítsuk el (go parancs):

0:000> g

Erre elindul a provider, betölt egy csomó DLL-t, majd várni kezd a kérésekre. Ha meghívjuk a metódust, ami a hibát kiváltja, akkor a WinDbg a következő kivételt kapja el:

(8e0.ee0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=022f1ee4 ecx=012f3c40 edx=012fb1c8 esi=012fb2a0 edi=012fce30
eip=6d4e0159 esp=0356f038 ebp=0356f068 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
*** WARNING: Unable to verify checksum for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Management.I#\0c0688825a79e72951210318eef63c82\System.Management.Instrumentation.ni.dll
System_Management_Instrumentation_ni+0x10159:
6d4e0159 8b5004          mov     edx,dword ptr [eax+4] ds:0023:00000004=????????

Lássuk hol járunk (kb – a stack listázására szolgáló parancs):

0:005> kb
ChildEBP RetAddr  Args to Child
0356f068 6d4dac62 012f2c14 00000000 012f3c40 System_Management_Instrumentation_ni+0x10159
0356f09c 6d4d40e5 012fce04 012fcd50 012fce24 System_Management_Instrumentation_ni+0xac62
0356f0e8 79f047fd 012fcd40 012fcd30 00000000 System_Management_Instrumentation_ni+0x40e5
0356f214 79f0462c 001e2a38 0356f40c 0356f484 mscorwks!COMToCLRWorkerBody+0x208
0356f270 79f62ac8 001e2a38 0356f40c 0356f484 mscorwks!COMToCLRWorkerDebuggerWrapper+0x37
0356f444 0097a832 001e2a38 0356f484 9455ff71 mscorwks!COMToCLRWorker+0x157
WARNING: Frame IP not in any known module. Following frames may be wrong.
0356f46c 599493ce 001d7e50 00000000 001e3150 0x97a832
0356f4dc 59949532 00000000 001d7b14 00000000 wmidcprv!CInterceptor_DecoupledClient::Helper_GetObjectAsync+0x119
0356f51c 59947161 01280038 001d7b14 00000000 wmidcprv!CInterceptor_DecoupledClient::GetObjectAsync+0x75
0356f550 77e799f4 001d7e78 000005c0 00000000 wmidcprv!CInterceptor_DecoupledClient::Internal_GetObjectAsync+0x51
0356f588 77ef421a 59947110 0356f59c 00000009 RPCRT4!Invoke+0x30
0356f9a8 77ef4bf3 001df740 001d8fe0 001dfa28 RPCRT4!NdrStubCall2+0x297
0356fa00 77600c15 001df740 001dfa28 001d8fe0 RPCRT4!CStdStubBuffer_Invoke+0xc6
0356fa40 77600bbf 001dfa28 001df638 001d5c28 ole32!SyncStubInvoke+0x33
0356fa88 7752ad31 001dfa28 001d8550 001df740 ole32!StubInvoke+0xa7
0356fb60 7752ac56 001d8fe0 00000000 001df740 ole32!CCtxComChnl::ContextInvoke+0xe3
0356fb7c 776007f5 001dfa28 00000001 001df740 ole32!MTAInvoke+0x1a
0356fbac 77602df3 001df9d0 001d8fe0 001df740 ole32!AppInvoke+0x9c
0356fc80 77600715 001df9d0 001c87a0 001df620 ole32!ComInvokeWithLockAndIPID+0x2c2
0356fccc 77e794bd 001dee3c 001df620 001dee3c ole32!ThreadInvoke+0x1cd
0356fd00 77e79422 776005d0 001dee3c 0356fdec RPCRT4!DispatchToStubInC+0x38
0356fd54 77e7934e 00000000 00000000 774ebfc8 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x113
0356fd78 77e8a384 001dee3c 00000000 774ebfc8 RPCRT4!RPC_INTERFACE::DispatchToStub+0x84
0356fdb8 77e8a3c5 001dee3c 001dedf8 00000000 RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0xc0
0356fdf8 77e7bcc1 001df780 001c7ea8 001deb98 RPCRT4!LRPC_SCALL::DealWithRequestMessage+0x2cd
0356fe1c 77e7bc05 001c7ee4 0356fe38 001deb98 RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0x16d
0356ff80 77e76caf 0356ffa8 77e76ad1 001c7ea8 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0x310
0356ff88 77e76ad1 001c7ea8 7c900000 0027fae0 RPCRT4!RecvLotsaCallsWrapper+0xd
0356ffa8 77e76c97 001c5380 0356ffec 7c80b713 RPCRT4!BaseCachedThreadRoutine+0x79
0356ffb4 7c80b713 001deaf8 7c900000 0027fae0 RPCRT4!ThreadStartRoutine+0x1a
0356ffec 00000000 77e76c7d 001deaf8 00000000 KERNEL32!BaseThreadStart+0x37

Ennyit lát egy nem menedzselt debugger a .NET-es kódból:) Az mscorwks a .NET Framework futtatókörnyezet, utána pedig a System.Management.Instrumentation assembly-be hívunk bele. Hogy lássuk, hogy mi történik a .NET-es kódban, használni kell a SOS kiegészítést. (a SOS-ról egy rövid leírás)

0:005>.loadby sos mscorwks

Így már belelátunk a menedzselt hívási verembe is:

0:005> !clrstack
OS Thread Id: 0xee0 (5)
ESP       EIP
0356f038 6d4e0159 System.Management.Instrumentation.AutomationType.CalculateKey(System.Management.Instrumentation.ObjectDictionary)
0356f070 6d4dac62 PublishProvider.Get(System.Management.Instrumentation.CallContext, System.Management.Instrumentation.ICIMResultHandler)
0356f0a8 6d4d40e5 WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(System.String, Int32, WmiNative.IWbemContext, WmiNative.IWbemObjectSink)
0356f328 79f047fd [GCFrame: 0356f328]
0356f484 79f047fd [ComMethodFrame: 0356f484]

Most pont ott vagyunk, ahol a NullReferenceException történt:) A !clrstack meg tudja mutatni a paraméterek értékét is (jobbára):

0:005> !clrstack -p
OS Thread Id: 0xee0 (5)
ESP       EIP
0356f038 6d4e0159 System.Management.Instrumentation.AutomationType.CalculateKey(System.Management.Instrumentation.ObjectDictionary)
    PARAMETERS:
        this = <no data>
        dict = 0x00000000

0356f070 6d4dac62 PublishProvider.Get(System.Management.Instrumentation.CallContext, System.Management.Instrumentation.ICIMResultHandler)
    PARAMETERS:
        this = <no data>
        context = <no data>
        resultHandler = <no data>

0356f0a8 6d4d40e5 WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(System.String, Int32, WmiNative.IWbemContext, WmiNative.IWbemObjectSink)
    PARAMETERS:
        this = 0x012fab80
        objectPath = <no data>
        flags = <no data>
        wbemContext = <no data>
        wbemSink = 0x012fcd40

0356f328 79f047fd [GCFrame: 0356f328]
0356f484 79f047fd [ComMethodFrame: 0356f484]

Ott látszik, hogy a CalculateKey-nek átadott paraméter null, valószínűleg ez okozza a NullReferenceException-t.

Ha továbbléptetjük, akkor elérkezünk a nem kezelt kivételhez, amit megnézhetünk a !PrintException segítségével:

0:005> g
ModLoad: 5e3a0000 5e42d000   C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\diasymreader.dll
CLR: Managed code called FailFast, saying "System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Management.Instrumentation.AutomationType.CalculateKey(ObjectDictionary dict)
   at PublishProvider.Get(CallContext context, ICIMResultHandler resultHandler)
   at WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(String objectPath, Int32 flags, IWbemContext wbemContext, IWbemObjectSink wbemSink)"
(8e0.ee0): Break instruction exception - code 80000003 (first chance)
eax=00000001 ebx=00000000 ecx=00000001 edx=0356e29c esi=001d6788 edi=6d4d4253
eip=7c90120e esp=0356ddfc ebp=0356e2a8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc              int     3
0:005> !PrintException
Exception object: 012fce78
Exception type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
InnerException: <none>
StackTrace (generated):
    SP       IP       Function
    0356F038 6D4E015A System_Management_Instrumentation_ni!System.Management.Instrumentation.AutomationType.CalculateKey(System.Management.Instrumentation.ObjectDictionary)+0x56
    0356F070 6D4DAC62 System_Management_Instrumentation_ni!PublishProvider.Get(System.Management.Instrumentation.CallContext, System.Management.Instrumentation.ICIMResultHandler)+0xde
    0356F0A8 6D4D40E5 System_Management_Instrumentation_ni!WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(System.String, Int32, WmiNative.IWbemContext, WmiNative.IWbemObjectSink)+0x155

StackTraceString: <none>
HResult: 80004003

(Így utólag visszaolvasva a WinDbg most igazából felesleges volt, hisz csak menedzselt kódot néztünk, ezt ki lehetett volna úgy is deríteni, ha az AutomationType.CalculateKey-re állítunk be egy töréspontot a Visual Studio-ban. Nem baj, legalább láttunk WindDbg-ot is, jól jöhet még az, ha menedzselt és nem menedzselt kódot kell vegyesen debuggolni:)

Most már csak azt kéne kideríteni, hogy miért hívja meg a CalculateKey-t, ez egy singleton provider, tehát egy példány van belőle, így nincs szükség ManagementKey-ekre, hogy megkülönböztessük az egyes példányokat (kulcsokat használunk pl. amikor a Win32_Process által visszaadott folyamatokat meg akarjuk különböztetni).

A System.Management.Instrumentation osztályai reflektorfényben

A .NET Reflector eszköz segítségével lehet például megnézni a .NET Framework osztályainak kódját. Ha hozzáadjuk a System.Management.Instrumentation.dll-t (File / Open, majd a C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5 könyvtárban találjuk), akkor kikereshető a PublishProvider Get metódusa, ami meghívja a CalculateKey-t:

wmi-publishprovider-reflector

Hát itt túl sok bonyolult logika nincsen, ha valamit vissza akar adni, akkor meg kell hívni a CalculateKey-t. Ez pedig a context.Keys-t adja át, ennek az értékét meg tudjuk nézni, ha pl. Visual Studio-ban beállítunk egy breakpointot a PublishProvider.Get metódusra:

wmi-provider-publishprovider-breakpoint

Ha meghívjuk a metódust, akkor szépen meg is áll itt, és meg tudjuk nézni a context változó értékét:

wmi-provider-context

A Keys, nem meglepő módon, null értékű, ebből utána tényleg nem lehet megtalálni a WMI objektumot:)

Most már csak az a kérdés maradt hátra, hogy miért csak metódushívás esetén jön ez elő, a tulajdonságok lekérdezése miért megy publish esetén is. Ha beállítunk egy töréspontot egy tulajdonságlekérdezésre, akkor ott a következő hívási láncot kapjuk:

wmi1.exe!wmi1.WmiTest.Property1.get() Line 25	C#
 	[Native to Managed Transition]
 	[Managed to Native Transition]
>	System.Management.Instrumentation.dll!System.Management.Instrumentation.MetaPropertyInfo.GetValue(object oTarget) + 0x65 bytes
 	System.Management.Instrumentation.dll!System.Management.Instrumentation.ResultHandler.AddObjectToResult(object oResult = {wmi1.Cica}, out WmiNative.IWbemClassObject pOutInstance = null) + 0x97 bytes
 	System.Management.Instrumentation.dll!System.Management.Instrumentation.ResultHandler.AddResults(object[] result = {object[1]}) + 0x6a bytes
 	System.Management.Instrumentation.dll!PublishProvider.Enumerate(System.Management.Instrumentation.CallContext context, System.Management.Instrumentation.ICIMResultHandler resultHandler = {System.Management.Instrumentation.ResultHandler}) + 0x10e bytes
 	System.Management.Instrumentation.dll!WmiNative.WbemProvider.WmiNative.IWbemServices.CreateInstanceEnumAsync(string className, int flags, WmiNative.IWbemContext wbemContext, WmiNative.IWbemObjectSink wbemSink = {System.__ComObject}) + 0x158 bytes
 	[Native to Managed Transition]

Itt van a trükk, a tulajdonságok lekérdezésénél nem a GetObjectAsync-et és a PublishProvider.Get-et hívja, hanem amikor először lekéri az objektumot, akkor kiolvassa az összes tulajdonságát.

Az utolsó utáni kérdés pedig az, hogy mi történik máshogy a RegisterType esetén, ott miért nem futunk bele ebbe a hibába. Megpróbáltam hozzáadni egy töréspontot a WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync metódusra, de Visual Studio-ból sehogy se akart ráfutni, se teljes névvel, se részkombinációkkal,  se IWbemServices.GetObjectAsync alakban (ehhez a projekt tulajdonságainál be kellett kapcsolni az Enable unmanaged code debugging opciót). Úgyhogy maradt a WinDbg (ha kalapács van a kezünkben, mindent szögnek nézünk alapon:-).

Itt kicsit trükkösebb a breakpoint hozzáadás. Lehet névvel, ezzel itt se ment, de lehet a metódus azonosítóját is megadni a breakpointnak. Ezt kell tehát megszerezni:

Elindítjuk a programot, majd g, utána pedig ha betöltötte a .NET-es dll-eket is, akkor nyomunk egy Debug / Break parancsot. Majd (itt a kimenetek elég hosszúak, így csak a lényegi részt tartom meg):

0:006> !dumpdomain
...
Assembly: 001b0380 [C:\WINDOWS\assembly\GAC_MSIL\System.Management.Instrumentation\3.5.0.0__b77a5c561934e089\System.Management.Instrumentation.dll]
ClassLoader: 001b2af8
SecurityDescriptor: 001aa828
  Module Name
6d7e1000 C:\WINDOWS\assembly\GAC_MSIL\System.Management.Instrumentation\3.5.0.0__b77a5c561934e089\System.Management.Instrumentation.dll

A kékkel jelzett cím kell majd nekünk, az a System.Management.Instrumentation modul:

0:006> !dumpmodule -mt 6d7e1000
Name: C:\WINDOWS\assembly\GAC_MSIL\System.Management.Instrumentation\3.5.0.0__b77a5c561934e089\System.Management.Instrumentation.dll
...
Types defined in this module

      MT    TypeDef Name
------------------------------------------------------------------------------
6d823ad0 0x02000007 System.Management.Instrumentation.ManagedCommonProvider
6d823ba0 0x0200000b WmiNative.WbemProvider
...

A kékkel jelzett címen van a WbemProvider metódus táblája:

0:006> !DumpMT -MD 6d823ba0
EEClass: 6d7e426c
Module: 6d7e1000
Name: WmiNative.WbemProvider
mdToken: 0200000b  (C:\WINDOWS\assembly\GAC_MSIL\System.Management.Instrumentation\3.5.0.0__b77a5c561934e089\System.Management.Instrumentation.dll)
BaseSize: 0x20
ComponentSize: 0x0
Number of IFaces in IFaceMap: 4
Slots in VTable: 42
--------------------------------------
MethodDesc Table
   Entry MethodDesc      JIT Name
79286aa0   79104924   PreJIT System.Object.ToString()
6d81bb20   6d7e7728   PreJIT WmiNative.WbemProvider.WmiNative.IWbemServices.GetObject(System.String, Int32, WmiNative.IWbemContext, WmiNative.IWbemClassObject ByRef, IntPtr)
6d81bb40   6d7e7730   PreJIT WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(System.String, Int32, WmiNative.IWbemContext, WmiNative.IWbemObjectSink)
...

Megvan a metódus leírója, ez kell a breakpointhoz:

0:006> !bpmd -md 6d7e7730
MethodDesc = 6d7e7730
Setting breakpoint: bp 6D81BB40 [WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(System.String, Int32, WmiNative.IWbemContext, WmiNative.IWbemObjectSink)]

Akkor most már csak meg kell hívnunk a metódusunkat, és nézni, hogy merre megy majd tovább a hívás. Ebben segít pl. a pc parancs, ami a következő call utasításra ugrik (sajnos ez nem a .NET-es hívás, hanem az alatta levő assembly call, úgyhogy több van belőle). Ugorhatunk a GetProvider hívásra, majd ha onnan visszatérünk, akkor ki kell deríteni, hogy milyen típusú providert kapunk vissza. Ehhez jól jön pl. a !vars kiterjesztés, ami a sosex.dll-ben van benne:

0:003> !vars
Frame 0 (WmiNative.WbemProvider.WmiNative.IWbemServices.GetObjectAsync(System.String, Int32, WmiNative.IWbemContext, WmiNative.IWbemObjectSink)):
Arguments:
[0]:this:0x13021a4 (WmiNative.WbemProvider)
[1]:objectPath:<?>
[2]:flags:<?>
[3]:wbemContext:<?>
[4]:wbemSink:0x131d2e0 (WmiNative.IWbemObjectSink)
Locals:
[0]:Failed to retrieve method desc from IP.  Error = 0x80070057
0x0 (System.Int32)
[1]:Failed to retrieve method desc from IP.  Error = 0x80070057<?>
[2]:Failed to retrieve method desc from IP.  Error = 0x80070057
0x131d2f0 (System.Management.Instrumentation.CallContext)
[3]:Failed to retrieve method desc from IP.  Error = 0x80070057
0x1303bc0 (WMIClassCacheEntry)
[4]:Failed to retrieve method desc from IP.  Error = 0x80070057
<?>
[5]:Failed to retrieve method desc from IP.  Error = 0x80070057
0x13026fc (System.Management.Instrumentation.ProviderMetadata)

Ott van, amit keresünk, nézzük meg az objektumot:

0:003> !dumpobject 0x013026fc
Name: System.Management.Instrumentation.ProviderMetadata
MethodTable: 6d823e80
EEClass: 6d7e44c4
Size: 28(0x1c) bytes
 (C:\WINDOWS\assembly\GAC_MSIL\System.Management.Instrumentation\3.5.0.0__b77a5c561934e089\System.Management.Instrumentation.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
7933061c  400004e        4        System.Object  0 instance 01302718 m_oProvider
79333054  400004f        8 ...ections.Hashtable  0 instance 013027a4 m_htSupportedClasses
793044cc  4000050       14       System.Boolean  1 instance        1 m_bIsDecoupled
79330a00  4000051        c        System.String  0 instance 01300dac m_sNamespace
79330a00  4000052       10        System.String  0 instance 01301ef8 m_sProviderName

Látszik, hogy van egy m_oProvider nevű tagváltozónk, annak az értékére vagyunk kíváncsiak:

0:003> !do 01302718
Name: UMPProvider
MethodTable: 6d823fbc
EEClass: 6d7e4654
Size: 12(0xc) bytes
 (C:\WINDOWS\assembly\GAC_MSIL\System.Management.Instrumentation\3.5.0.0__b77a5c561934e089\System.Management.Instrumentation.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
79333054  4000089       24 ...ections.Hashtable  0   static 01300934 TypeToAutomationType
7933061c  400008a       28        System.Object  0   static 013009fc m_ProviderLock

Ott a keresett érték! A RegisterType az UMPProvider-t hívja. Ha megnézzük pl. Reflectorral, akkor annak a Get metódusa teljesen máshogy néz ki, ott azért nem jön elő ez a hiba.

No kicsit hosszúra nyúlt ez a vizsgálódás, lássuk mit is láttunk belőle:

Tanulságok

  • Az eredeti problémát viszonylag hamar megoldottuk, RegisterType-ot kell használni és nem Publisht. Ez nem tudom szándékos-e így, vagy esetleg valami bug, feltettem a kérdést az MSDN fórumon, remélem lesz majd rá válasz.
  • Ha a mélyére akarunk nézni, hogy mi történik egy ilyen komplexebb hívás esetén (aszinkron módon visszahív egy COM-os C++ komponens a .NET-es kódunkba), akkor arra is vannak eszközeink.
  • A Visual Studio debuggere kényelmes, gyorsan meg lehet találni benne a keresett értékeket. Ha ez valamiért nem jó, akkor lehet használni WinDbg-ot, a SOS kiegészítéssel .NET-es kódot is tud kezelni. Visual Studio után nem kényelmes a váltás:), de nagyon hatékony tud lenni, ha kiismeri az ember.
  • Egy ilyen apró hibával is el lehet egy fél napot tölteni:-)

Remélem hasznos lesz másnak is ez a bejegyzés, és sokat tanultam közben:)

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>