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:
A local és a callstack ablakok sem adtak túl sok útmutatást:
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:
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:
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:
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:
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:)