File: Instrumentation\EventSource.cs
Project: ndp\fx\src\wmi\managed\System\Management\System.Management.csproj (System.Management)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
namespace System.Management.Instrumentation
{
    using System;
    using System.Runtime.InteropServices;
    using System.Collections;
    using System.Text.RegularExpressions;
    using System.Threading;
    using System.Security;
    using System.Globalization;
    using System.Runtime.Versioning;
 
    class ComThreadingInfo
    {
        public enum APTTYPE
        {
            APTTYPE_CURRENT = -1,
            APTTYPE_STA = 0,
            APTTYPE_MTA = 1,
            APTTYPE_NA  = 2,
            APTTYPE_MAINSTA = 3
        }
 
        public enum THDTYPE
        {
            THDTYPE_BLOCKMESSAGES   = 0,
            THDTYPE_PROCESSMESSAGES = 1
        }
 
        [ComImport]
        [Guid("000001ce-0000-0000-C000-000000000046")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IComThreadingInfo 
        {
            APTTYPE GetCurrentApartmentType();
            THDTYPE GetCurrentThreadType();
            Guid GetCurrentLogicalThreadId();
            void SetCurrentLogicalThreadId([In] Guid rguid);
        }
 
        Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
 
        ComThreadingInfo()
        {
            IComThreadingInfo info = (IComThreadingInfo)CoGetObjectContext(ref IID_IUnknown);
 
            apartmentType  = info.GetCurrentApartmentType();
            threadType = info.GetCurrentThreadType();
            logicalThreadId = info.GetCurrentLogicalThreadId();
        }
 
        public static ComThreadingInfo Current
        {
            get
            {
                return new ComThreadingInfo();
            }
        }
 
        public override string ToString()
        {
            return String.Format("{{{0}}} - {1} - {2}", LogicalThreadId, ApartmentType, ThreadType);
        }
 
        APTTYPE apartmentType;
        THDTYPE threadType;
        Guid logicalThreadId;
 
        public APTTYPE ApartmentType { get { return apartmentType; } 
        }
        public THDTYPE ThreadType { get { return threadType; } 
        }
        public Guid LogicalThreadId { get { return logicalThreadId; } 
        }
 
        [ResourceExposure( ResourceScope.None),DllImport("ole32.dll", PreserveSig = false)]
        [return:MarshalAs(UnmanagedType.IUnknown)]
        static extern object CoGetObjectContext([In] ref Guid riid);
    }
 
    sealed class EventSource : IWbemProviderInit, IWbemEventProvider, IWbemEventProviderQuerySink, IWbemEventProviderSecurity, IWbemServices_Old
    {
        IWbemDecoupledRegistrar registrar = (IWbemDecoupledRegistrar)new WbemDecoupledRegistrar();
 
        static ArrayList eventSources = new ArrayList();
 
        InstrumentedAssembly instrumentedAssembly;
 
        public EventSource(string namespaceName, string appName, InstrumentedAssembly instrumentedAssembly)
        {
            lock(eventSources)
            {
                // This is a pathalogical case where the process is shutting down, but
                // someone wants us to register us as a provider.  In this case, we ignore
                // the request.  This would be problematic if the eventSources list has already
                // been enumerated and all other eventSources unregistered.  If we were allowed
                // to register a new event source, it would never be unregistered
                if(shutdownInProgress != 0)
                    return;
 
                this.instrumentedAssembly = instrumentedAssembly;
             int hr = registrar.Register_(0, null, null, null, namespaceName, appName, this);
 
                if(hr != 0)
                    Marshal.ThrowExceptionForHR(hr, WmiNetUtilsHelper.GetErrorInfo_f());
 
                // If we've gotten here, we were successful with the Register call
                eventSources.Add(this);
            }
        }
 
#if OldShutdown
        ~EventSource()
        {
            // Kill worker thread
            if(lengthFromSTA != -1)
            {
                alive = false;
                SetEvent(hDoIndicate);
//                doIndicate.Set();
            }
 
            registrar.UnRegister_();
        }
#endif
 
        ~EventSource()
        {
            // 
 
 
 
 
 
 
 
 
 
            UnRegister();
        }
 
        void UnRegister()
        {
            lock(this)
            {
                // Only unregister one time
                if(registrar == null)
                    return;
 
                // Kill worker thread
                if(workerThreadInitialized == true)
                {
                    alive = false;
                    doIndicate.Set(); // SetEvent(hDoIndicate);
                    GC.KeepAlive(this);
                    workerThreadInitialized = false;
                }
                registrar.UnRegister_();
                registrar = null;
            }
        }
 
        static int shutdownInProgress = 0;
        static ReaderWriterLock preventShutdownLock = new ReaderWriterLock();
        static void ProcessExit(object o, EventArgs args)
        {
            // We can be called multiple times, but only one time will we
            // try to unregister all the event sources
            if(shutdownInProgress != 0)
                return;
 
            // Notify anyone interested that a shutdown as been initiated
            Interlocked.Increment(ref shutdownInProgress);
 
            try
            {
                // Wait for anyone currently in a DCOM callback to finish
                preventShutdownLock.AcquireWriterLock(-1);
 
                // Unregister all existing event sources
                lock(eventSources)
                {
                    foreach(EventSource eventSource in eventSources)
                        eventSource.UnRegister();
                }
            }
            finally
            {
                // Let any straglers call start their calls
                preventShutdownLock.ReleaseWriterLock();
                Thread.Sleep(50);
 
                // Wait for any stragler that started
                preventShutdownLock.AcquireWriterLock(-1);
                preventShutdownLock.ReleaseWriterLock();
            }
        }
        static EventSource()
        {
            // We'll register for both ProcessExit and DomainUnload.  It is OK
            // if both are called, but bad if neither are called.  See comments
            // in ~EventSource();
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(ProcessExit);
            AppDomain.CurrentDomain.DomainUnload += new EventHandler(ProcessExit);
        }
 
        IWbemServices pNamespaceNA = null;
        IWbemObjectSink pSinkNA = null;
        IWbemServices pNamespaceMTA = null;
        IWbemObjectSink pSinkMTA = null;
 
        private class MTARequest
        {
            public AutoResetEvent doneIndicate = new AutoResetEvent(false);
            public Exception exception = null;
            public int lengthFromSTA = -1;
            public IntPtr[] objectsFromSTA;
            public MTARequest(int length, IntPtr[] objects)
            {
                this.lengthFromSTA = length;
                this.objectsFromSTA = objects;
            }
        }
 
        ArrayList reqList = new ArrayList(3);
        object critSec = new object();
        
        AutoResetEvent doIndicate = new AutoResetEvent(false);
        
 
        bool workerThreadInitialized = false;
        /*
        [DllImport("kernel32")] static extern IntPtr CreateEvent(IntPtr pSecurity, int manual, int initial, IntPtr name);
        [SuppressUnmanagedCodeSecurity, DllImport("kernel32")] static extern int SetEvent(IntPtr handle);
        [SuppressUnmanagedCodeSecurity, DllImport("kernel32")] static extern int WaitForSingleObject(IntPtr handle, int timeout);
        IntPtr hDoIndicate = CreateEvent(IntPtr.Zero, 0, 0, IntPtr.Zero);
        IntPtr hDoneIndicate = CreateEvent(IntPtr.Zero, 0, 0, IntPtr.Zero);
        */
 
        // Worker thread for each EventSource
 
        
 
        //
        // Ensure we are able to trap exceptions from worker thread.
        // Called from IndicateEvents which in turn is protected from
        // concurrent access.
        //
        
 
        public void MTAWorkerThread2()
        {
            while(true)
            {
                doIndicate.WaitOne(); //WaitForSingleObject(hDoIndicate, -1);
                if(alive == false)
                {
                    break;
                }            
                 // get requests from the request queue. Since two Set within short time on evtGo can wake this thread only once
                // workerthread should check until we empty all the results. Even if we consume the request that is not set,
                // workerthread will wake up one more time unnecessarily and do nothing
                while(true)
                {
                    MTARequest reqToProcess = null;
                    lock (critSec)
                    {
                        if (reqList.Count > 0)
                        {
                            reqToProcess = (MTARequest)reqList[0];
                            reqList.RemoveAt(0);
                        }
                        else
                        {
                            break;  // break the inner while true
                        }
                    }
                    try
                    {
                        if (pSinkMTA != null)
                        {
                            int hresult = pSinkMTA.Indicate_(reqToProcess.lengthFromSTA, reqToProcess.objectsFromSTA);
                            if (hresult < 0)
                            {
                                if ((hresult & 0xfffff000) == 0x80041000)
                                    ManagementException.ThrowWithExtendedInfo((ManagementStatus)hresult);
                                else
                                    Marshal.ThrowExceptionForHR(hresult, WmiNetUtilsHelper.GetErrorInfo_f());
                            }
                        }
                    }
                    catch(Exception e)
                    {
                        reqToProcess.exception = e;
                    }
                    finally
                    {
                        reqToProcess.doneIndicate.Set(); //SetEvent(hDoneIndicate);
                        GC.KeepAlive(this);
                    }
                }
            }
        }
 
 
        bool alive = true;
 
        public void IndicateEvents(int length, IntPtr[] objects)
        {
            if (pSinkMTA == null)
                return;
            //
            // Checking for MTA is not enough.  We need to make sure we are not in a COM+ Context
            //
            if (MTAHelper.IsNoContextMTA())
            {
                // Sink lives in MTA
                int hresult = pSinkMTA.Indicate_(length, objects);
                if (hresult < 0)
                {
                    if ((hresult & 0xfffff000) == 0x80041000)
                        ManagementException.ThrowWithExtendedInfo((ManagementStatus)hresult);
                    else
                        Marshal.ThrowExceptionForHR(hresult, WmiNetUtilsHelper.GetErrorInfo_f());
                }
            }
            else
            {
                MTARequest myReq = new MTARequest(length,objects);
                int ndx;
                lock(critSec)
                {
                    // Do it from worker thread
                    if (workerThreadInitialized == false)
                    {
                        // We've never created worker thread
                        Thread thread = new Thread(new ThreadStart(MTAWorkerThread2));
                        thread.IsBackground = true;
                        thread.SetApartmentState(ApartmentState.MTA);
                        thread.Start();
                        workerThreadInitialized = true;
                    }
                    ndx = reqList.Add(myReq);
                    if( doIndicate.Set() == false ) //SetEvent(hDoIndicate);
                    {
                        reqList.RemoveAt(ndx);
                        throw new ManagementException(RC.GetString("WORKER_THREAD_WAKEUP_FAILED"));
                    }
                }
                myReq.doneIndicate.WaitOne(); //WaitForSingleObject(hDoneIndicate, -1);
                if (myReq.exception != null)
                {
                    throw myReq.exception;
                }
            }
            GC.KeepAlive(this); 
        }
 
        void RelocateSinkRCWToMTA()
        {
            ThreadDispatch disp = new ThreadDispatch(new ThreadDispatch.ThreadWorkerMethodWithParam(RelocateSinkRCWToMTA_ThreadFuncion));
            disp.Parameter = this;
            disp.Start();
        }
 
        void RelocateSinkRCWToMTA_ThreadFuncion( object param )
        {
            EventSource threadParam = (EventSource) param;
            threadParam.pSinkMTA = (IWbemObjectSink)RelocateRCWToCurrentApartment(threadParam.pSinkNA);
            threadParam.pSinkNA = null;
        }
 
        void RelocateNamespaceRCWToMTA()
        {
            ThreadDispatch disp = new ThreadDispatch(new ThreadDispatch.ThreadWorkerMethodWithParam(RelocateNamespaceRCWToMTA_ThreadFuncion));
            disp.Parameter = this;
            disp.Start();
        }
 
        void RelocateNamespaceRCWToMTA_ThreadFuncion(object param)
        {
            EventSource threadParam = (EventSource) param ;
            threadParam.pNamespaceMTA = (IWbemServices)RelocateRCWToCurrentApartment(threadParam.pNamespaceNA);
            threadParam.pNamespaceNA = null;
        }
 
        static object RelocateRCWToCurrentApartment(object comObject)
        {
            if(null == comObject)
                return null;
 
            IntPtr pUnk = Marshal.GetIUnknownForObject(comObject);
            int references = Marshal.ReleaseComObject(comObject);
            if (references != 0)
                throw new Exception();
 
            comObject = Marshal.GetObjectForIUnknown(pUnk);
            Marshal.Release(pUnk);
            return comObject;
        }
 
        public bool Any()
        {
            return (null == pSinkMTA) || (mapQueryIdToQuery.Count == 0);
        }
 
        Hashtable mapQueryIdToQuery = new Hashtable();
 
        // IWbemProviderInit
 
        int IWbemProviderInit.Initialize_(
            [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszUser,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszNamespace,
            [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszLocale,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemServices   pNamespace,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemProviderInitSink   pInitSink)
        {
            this.pNamespaceNA = pNamespace;
            RelocateNamespaceRCWToMTA();
 
            this.pSinkNA = null;
            this.pSinkMTA = null;
 
            lock(mapQueryIdToQuery)
            {
                mapQueryIdToQuery.Clear();
            }
 
            pInitSink.SetStatus_((int)tag_WBEM_EXTRA_RETURN_CODES.WBEM_S_INITIALIZED, 0);
            Marshal.ReleaseComObject(pInitSink);
 
            return 0;
        }
 
        // IWbemEventProvider
        int IWbemEventProvider.ProvideEvents_(
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pSink,
            [In] Int32 lFlags)
        {
            this.pSinkNA = pSink;
            RelocateSinkRCWToMTA();
 
            // 
 
            return 0;
        }
 
        // IWbemEventProviderQuerySink
 
        int IWbemEventProviderQuerySink.NewQuery_(
            [In] UInt32 dwId,
            [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszQueryLanguage,
            [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszQuery)
        {
            lock(mapQueryIdToQuery)
            {
                // HACK: for bug where CancelQuery is not called correctly
                // and we get a NewQuery where dwId is already in our hashtable
                if(mapQueryIdToQuery.ContainsKey(dwId))
                    mapQueryIdToQuery.Remove(dwId);
                mapQueryIdToQuery.Add(dwId, wszQuery);
            }
            return 0;
        }
 
        int IWbemEventProviderQuerySink.CancelQuery_([In] UInt32 dwId)
        {
            lock(mapQueryIdToQuery)
            {
                mapQueryIdToQuery.Remove(dwId);
            }
            return 0;
        }
 
        // IWbemEventProviderSecurity
        int IWbemEventProviderSecurity.AccessCheck_(
            [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszQueryLanguage,
            [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszQuery,
            [In] Int32 lSidLength,
            [In] ref Byte pSid)
        {
            return 0;
        }
 
        // IWbemServices
        int IWbemServices_Old.OpenNamespace_([In][MarshalAs(UnmanagedType.BStr)]  string   strNamespace,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][Out][MarshalAs(UnmanagedType.Interface)]  ref IWbemServices   ppWorkingNamespace,
            [In] IntPtr ppCallResult)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.CancelAsyncCall_([In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pSink)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.QueryObjectSink_([In] Int32 lFlags,
            [Out][MarshalAs(UnmanagedType.Interface)]  out IWbemObjectSink   ppResponseHandler)
        {
            ppResponseHandler = null;
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.GetObject_([In][MarshalAs(UnmanagedType.BStr)]  string   strObjectPath,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][Out][MarshalAs(UnmanagedType.Interface)]  ref IWbemClassObject_DoNotMarshal   ppObject,
            [In] IntPtr ppCallResult)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.GetObjectAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strObjectPath,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
//            pResponseHandler.SetStatus(0, (int)tag_WBEMSTATUS.WBEM_E_NOT_FOUND, null, null);
//            Marshal.ReleaseComObject(pResponseHandler);
//            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_FOUND);
 
            Match match = Regex.Match(strObjectPath.ToLower(CultureInfo.InvariantCulture), "(.*?)\\.instanceid=\"(.*?)\",processid=\"(.*?)\"");
            if(match.Success==false)
            {
                pResponseHandler.SetStatus_(0, (int)tag_WBEMSTATUS.WBEM_E_NOT_FOUND, null, IntPtr.Zero);
                Marshal.ReleaseComObject(pResponseHandler);
                return (int)(tag_WBEMSTATUS.WBEM_E_NOT_FOUND);
            }
 
            string className = match.Groups[1].Value;
            string instanceId = match.Groups[2].Value;
            string processId = match.Groups[3].Value;
 
 
            if(Instrumentation.ProcessIdentity != processId)
            {
                pResponseHandler.SetStatus_(0, (int)tag_WBEMSTATUS.WBEM_E_NOT_FOUND, null, IntPtr.Zero);
                Marshal.ReleaseComObject(pResponseHandler);
                return (int)(tag_WBEMSTATUS.WBEM_E_NOT_FOUND);
            }
 
            int id = ((IConvertible)instanceId).ToInt32((IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(System.Int32)));
            Object theObject = null;
 
            try
            {
                InstrumentedAssembly.readerWriterLock.AcquireReaderLock(-1);
                theObject = InstrumentedAssembly.mapIDToPublishedObject[id.ToString((IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(System.Int32)))];
            }
            finally
            {
                InstrumentedAssembly.readerWriterLock.ReleaseReaderLock();
            }
 
            if(theObject != null)
            {
                Type converterType = (Type)instrumentedAssembly.mapTypeToConverter[theObject.GetType()];
                if(converterType != null)
                {
                    Object converter = Activator.CreateInstance(converterType);
                    ConvertToWMI func = (ConvertToWMI)Delegate.CreateDelegate(typeof(ConvertToWMI), converter, "ToWMI");
 
            //
            // Regression: Reuters VSQFE#: 750, PS#141144    [marioh]
            // GetObjectAsync was missed. Again, here we have to call ToWMI before retrieving the pointer to the object
            // since we clone a new one during the ToWMI call. The code below was simply moved from a location further down
            // 
            lock(theObject)
                func(theObject);
            //
            // END: Regression: Reuters VSQFE#: 750, PS#141144    [marioh]
 
                    
                    IntPtr[] objs = new IntPtr[] {(IntPtr)converter.GetType().GetField("instWbemObjectAccessIP").GetValue(converter)};
                    Marshal.AddRef(objs[0]);
                    IWbemClassObjectFreeThreaded inst = new IWbemClassObjectFreeThreaded(objs[0]);
 
                    Object o = id;
                    inst.Put_("InstanceId", 0, ref o, 0);
                    o = Instrumentation.ProcessIdentity;
                    inst.Put_("ProcessId", 0, ref o, 0);
                    //               ConvertFuncToWMI func = (ConvertFuncToWMI)InstrumentedAssembly.mapTypeToToWMIFunc[h.Target.GetType()];
            //
            // Reuters VSQFE#: 750, PS#141144    [marioh]
            // The commented out code was moved up before accessing the object pointer in order to get the
            // newly cloned one.
            // 
//                    lock(theObject)
//                        func(theObject);
                    pResponseHandler.Indicate_(1, objs);
 
                    pResponseHandler.SetStatus_(0, 0, null, IntPtr.Zero);
                    Marshal.ReleaseComObject(pResponseHandler);
                    return 0;
                }
            }
            pResponseHandler.SetStatus_(0, (int)tag_WBEMSTATUS.WBEM_E_NOT_FOUND, null, IntPtr.Zero);
            Marshal.ReleaseComObject(pResponseHandler);
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_FOUND);
#if xxx
            IWbemClassObject classObj = null;
            IWbemCallResult result = null;
            pNamespace.GetObject("TestInstance", 0, pCtx, ref classObj, ref result);
            IWbemClassObject inst;
            classObj.SpawnInstance(0, out inst);
 
            TestInstance testInstance = (TestInstance)mapNameToTestInstance[match.Groups[1].Value];
 
            Object o = (object)testInstance.name;
            inst.Put("name", 0, ref o, 0);
            o = (object)testInstance.value;
            inst.Put("value", 0, ref o, 0);
 
            pResponseHandler.Indicate(1, new IWbemClassObject[] {inst});
            pResponseHandler.SetStatus_(0, 0, IntPtr.Zero, IntPtr.Zero);
            Marshal.ReleaseComObject(pResponseHandler);
#endif
        }
 
        int IWbemServices_Old.PutClass_([In][MarshalAs(UnmanagedType.Interface)]  IWbemClassObject_DoNotMarshal   pObject,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In] IntPtr ppCallResult)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.PutClassAsync_([In][MarshalAs(UnmanagedType.Interface)]  IWbemClassObject_DoNotMarshal   pObject,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.DeleteClass_([In][MarshalAs(UnmanagedType.BStr)]  string   strClass,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In] IntPtr ppCallResult)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.DeleteClassAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strClass,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.CreateClassEnum_([In][MarshalAs(UnmanagedType.BStr)]  string   strSuperclass,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [Out][MarshalAs(UnmanagedType.Interface)]  out IEnumWbemClassObject   ppEnum)
        {
            ppEnum = null;
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.CreateClassEnumAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strSuperclass,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.PutInstance_([In][MarshalAs(UnmanagedType.Interface)]  IWbemClassObject_DoNotMarshal   pInst,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In] IntPtr ppCallResult)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.PutInstanceAsync_([In][MarshalAs(UnmanagedType.Interface)]  IWbemClassObject_DoNotMarshal   pInst,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.DeleteInstance_([In][MarshalAs(UnmanagedType.BStr)]  string   strObjectPath,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In] IntPtr ppCallResult)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.DeleteInstanceAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strObjectPath,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.CreateInstanceEnum_([In][MarshalAs(UnmanagedType.BStr)]  string   strFilter,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [Out][MarshalAs(UnmanagedType.Interface)]  out IEnumWbemClassObject   ppEnum)
        {
            ppEnum = null;
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.CreateInstanceEnumAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strFilter,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            try
            {
                // Make sure we do not let a shutdown kill this thread
                preventShutdownLock.AcquireReaderLock(-1);
 
                // If we are already shutting down, don't do anything
                if(shutdownInProgress != 0)
                    return 0;
 
                // If batching takes longer than 1/10 of a second, we want to stop
                // and flush the batch
                uint timeLimitForBatchFlush = (uint)Environment.TickCount + 100;
 
                // Find the managed type that is being requested by this call
                Type managedType = null;
                foreach(Type type in instrumentedAssembly.mapTypeToConverter.Keys)
                {
                    if(0==String.Compare(ManagedNameAttribute.GetMemberName(type), strFilter, StringComparison.Ordinal))
                    {
                        managedType = type;
                        break;
                    }
                }
 
                // If we do not support the requested type, just exit
                if(null == managedType)
                    return 0;
 
                // size for batching
                int batchSize = 64;
 
                // Array of IWbemClassObject IntPtrs for batching
                IntPtr[] objs = new IntPtr[batchSize];
                IntPtr[] objsClone = new IntPtr[batchSize];
 
                // Array of converter methods for batching
                ConvertToWMI[] funcs = new ConvertToWMI[batchSize];
 
                // Array of IWbemClassObjectFreeThreaded instances for batching
                IWbemClassObjectFreeThreaded[] insts = new IWbemClassObjectFreeThreaded[batchSize];
 
                // IWbemObjectAccess handle for 'InstanceId'
                int handleInstanceId = 0;
 
                // Current number of objects in batch
                int count = 0;
 
                // The process identity string
                Object processIdentity = Instrumentation.ProcessIdentity;
 
                // Walk all published instances
                try
                {
                    // Don't let anyone add entries to the dictionary while we are enumerating it.
                    // Other people can read from the dictionary
                    InstrumentedAssembly.readerWriterLock.AcquireReaderLock(-1);
                    foreach(DictionaryEntry entry in InstrumentedAssembly.mapIDToPublishedObject)
                    {
                        // If the process is going away, stop indicating more instances
                        if(shutdownInProgress != 0)
                            return 0;
 
                        // Is this object the type requested by this query?
                        if(managedType != entry.Value.GetType())
                            continue;
 
                        // Initialize this batch entry if necessary.  Each element of the batch arrays
                        // are initialized 'just in time'.  If we have less than batchSize entries total
                        // (or it takes too long to batch), we do not unnecessarily allocate the batch entry
                        if(funcs[count] == null)
                        {
                            Object converter = Activator.CreateInstance((Type)instrumentedAssembly.mapTypeToConverter[managedType]);
                            funcs[count] = (ConvertToWMI)Delegate.CreateDelegate(typeof(ConvertToWMI), converter, "ToWMI");
 
                            //
                            // Reuters VSQFE#: 750    [marioh]
                            // In order for the instance data batching logic to work properly, we HAVE TO convert the .NET
                            // objects to WMI objects before we update the batching pointers since the ToWMI method in the generated
                            // code will Spawn new instances.
                            // 
                            lock(entry.Value)
                                funcs[count](entry.Value);
 
                            objs[count] = (IntPtr)converter.GetType().GetField("instWbemObjectAccessIP").GetValue(converter);
                            Marshal.AddRef(objs[count]);
                            insts[count] = new IWbemClassObjectFreeThreaded(objs[count]);
                            insts[count].Put_("ProcessId", 0, ref processIdentity, 0);
 
                            int cimType;
                            if(count==0)
                                WmiNetUtilsHelper.GetPropertyHandle_f27(27, insts[count], "InstanceId", out cimType, out handleInstanceId);
                        }
                        else
                        {
                            //
                            // Reuters VSQFE#: 750    [marioh]
                            // If we end up re-using an existing delegate from the batch array, we still have to convert
                            // the .NET to WMI objects and update the instance pointers.
                            //
 
                            // Copy the managed instance information into the IWbemClassObject'
                            // We're using a batch, therefore we have to convert them.
                            lock(entry.Value)
                                funcs[count](entry.Value);
 
                            objs[count] = (IntPtr) funcs[count].Target.GetType().GetField("instWbemObjectAccessIP").GetValue(funcs[count].Target);
 
                            //
                            // We have to AddRef the interface pointer due to the IWbemClassObjectFreeThreaded not addreffing
                            // but releasing in the destructor. Great huh?
                            //
                            Marshal.AddRef(objs[count]);
                            insts[count] = new IWbemClassObjectFreeThreaded(objs[count]);
                            insts[count].Put_("ProcessId", 0, ref processIdentity, 0);
 
                            int cimType;
                            if(count==0)
                                WmiNetUtilsHelper.GetPropertyHandle_f27(27, insts[count], "InstanceId", out cimType, out handleInstanceId);
                        }
 
                        // We have an instance to publish.  Store the instance ID in 'InstanceId'
                        string instanceId = (string)entry.Key;
                        WmiNetUtilsHelper.WritePropertyValue_f28(28, insts[count], handleInstanceId, (instanceId.Length+1)*2, instanceId);
 
                        //                        // Copy the managed instance information into the IWbemClassObject'
                        //                        lock(entry.Value)
                        //                            funcs[count](entry.Value);
 
                        // Increment the batch counter
                        count++;
 
                        // If we've reached batchSize, or if we've gone longer than 1/10th second since
                        // an Indicate, flush the batch
                        if(count == batchSize || ((uint)Environment.TickCount) >= timeLimitForBatchFlush)
                        {
                            // Do the Indicate to WMI
                            // NOTE: On WinXP, we cannot control whether the implementation of
                            // Indicate will immediately send the objects to WMI, or if it will
                            // batch them.  If it batches them, we cannot reuse them in a future
                            // call to Indicate, or change them in any way after the call to
                            // Indicate.  Because of this, we will always 'Clone' the objects
                            // just before calling Indicate.  The performance is negligable, even
                            // on Windows 2000, which can handle about 200,000 Clones per second
                            // on a 1 GHz machine.
                            for(int i=0;i<count;i++)
                                WmiNetUtilsHelper.Clone_f(12, objs[i], out objsClone[i]);
                            int hr = pResponseHandler.Indicate_(count, objsClone);
                            for(int i=0;i<count;i++)
                                Marshal.Release(objsClone[i]);
 
                            // If hr is not S_OK, we stop the enumeration.  This can happen if the
                            // client cancels the call.
                            if(hr != 0 )
                                return 0;
 
                            // Reset the batch counter
                            count = 0;
 
                            // Reset the time limit for another 1/10th second in the future
                            timeLimitForBatchFlush = (uint)Environment.TickCount + 100;
                        }
                    }
                }
                finally
                {
                    InstrumentedAssembly.readerWriterLock.ReleaseReaderLock();
                }
                if(count > 0)
                {
                    // NOTE: On WinXP, we cannot control whether the implementation of
                    // Indicate will immediately send the objects to WMI, or if it will
                    // batch them.  If it batches them, we cannot reuse them in a future
                    // call to Indicate, or change them in any way after the call to
                    // Indicate.  Because of this, we will always 'Clone' the objects
                    // just before calling Indicate.  The performance is negligable, even
                    // on Windows 2000, which can handle about 200,000 Clones per second
                    // on a 1 GHz machine.
                    for(int i=0;i<count;i++)
                    {
                         WmiNetUtilsHelper.Clone_f(12, objs[i], out objsClone[i]);
                    }
                    pResponseHandler.Indicate_(count, objsClone);
                    for(int i=0;i<count;i++)
                        Marshal.Release(objsClone[i]);
                }
            }
            finally
            {
                pResponseHandler.SetStatus_(0, 0, null, IntPtr.Zero);
                Marshal.ReleaseComObject(pResponseHandler);
                preventShutdownLock.ReleaseReaderLock();
            }
            return 0;
        }
 
        int IWbemServices_Old.ExecQuery_([In][MarshalAs(UnmanagedType.BStr)]  string   strQueryLanguage,
            [In][MarshalAs(UnmanagedType.BStr)]  string   strQuery,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [Out][MarshalAs(UnmanagedType.Interface)]  out IEnumWbemClassObject   ppEnum)
        {
            ppEnum = null;
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.ExecQueryAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strQueryLanguage,
            [In][MarshalAs(UnmanagedType.BStr)]  string   strQuery,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.ExecNotificationQuery_([In][MarshalAs(UnmanagedType.BStr)]  string   strQueryLanguage,
            [In][MarshalAs(UnmanagedType.BStr)]  string   strQuery,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [Out][MarshalAs(UnmanagedType.Interface)]  out IEnumWbemClassObject   ppEnum)
        {
            ppEnum = null;
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.ExecNotificationQueryAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strQueryLanguage,
            [In][MarshalAs(UnmanagedType.BStr)]  string   strQuery,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.ExecMethod_([In][MarshalAs(UnmanagedType.BStr)]  string   strObjectPath,
            [In][MarshalAs(UnmanagedType.BStr)]  string   strMethodName,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemClassObject_DoNotMarshal   pInParams,
            [In][Out][MarshalAs(UnmanagedType.Interface)]  ref IWbemClassObject_DoNotMarshal   ppOutParams,
            [In] IntPtr ppCallResult)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
 
        int IWbemServices_Old.ExecMethodAsync_([In][MarshalAs(UnmanagedType.BStr)]  string   strObjectPath,
            [In][MarshalAs(UnmanagedType.BStr)]  string   strMethodName,
            [In] Int32 lFlags,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pCtx,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemClassObject_DoNotMarshal   pInParams,
            [In][MarshalAs(UnmanagedType.Interface)]  IWbemObjectSink   pResponseHandler)
        {
            return (int)(tag_WBEMSTATUS.WBEM_E_NOT_SUPPORTED);
        }
    }
}
 
 
#if UNUSED_CODE
    class HResultException : Exception
    {
        public HResultException(int hr)
        {
            base.HResult = hr;
        }
    }
 
    class WbemStatusException : HResultException
    {
        public WbemStatusException(tag_WBEMSTATUS status) : base((int)status) {}
    }
 
    /*********************************************
     * Wbem Internal
     *********************************************/
    [TypeLibTypeAttribute(0x0200)]
    [InterfaceTypeAttribute(0x0001)]
    [GuidAttribute("6C19BE32-7500-11D1-AD94-00C04FD8FDFF")]
    [ComImport]
    interface IWbemMetaData
    {
        void GetClass([In][MarshalAs(UnmanagedType.LPWStr)]  string   wszClassName, [In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pContext, [Out][MarshalAs(UnmanagedType.Interface)]  out IWbemClassObject   ppClass);
    } // end of IWbemMetaData
 
    [GuidAttribute("755F9DA6-7508-11D1-AD94-00C04FD8FDFF")]
    [TypeLibTypeAttribute(0x0200)]
    [InterfaceTypeAttribute(0x0001)]
    [ComImport]
    interface IWbemMultiTarget
    {
        void DeliverEvent([In] UInt32 dwNumEvents, [In][MarshalAs(UnmanagedType.Interface)]  ref IWbemClassObject   aEvents, [In] ref tag_WBEM_REM_TARGETS aTargets);
        void DeliverStatus([In] Int32 lFlags, [In][MarshalAs(UnmanagedType.Error)]  Int32   hresStatus, [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszStatus, [In][MarshalAs(UnmanagedType.Interface)]  IWbemClassObject   pErrorObj, [In] ref tag_WBEM_REM_TARGETS pTargets);
    } // end of IWbemMultiTarget
 
    struct tag_WBEM_REM_TARGETS
    {
        public Int32 m_lNumTargets;
 
        //        [ComConversionLossAttribute]
        //        public IntPtr m_aTargets;
        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] UInt32[]  m_aTargets;
    } // end of tag_WBEM_REM_TARGETS
  
    [GuidAttribute("60E512D4-C47B-11D2-B338-00105A1F4AAF")]
    [TypeLibTypeAttribute(0x0200)]
    [InterfaceTypeAttribute(0x0001)]
    [ComImport]
    interface IWbemFilterProxy
    {
        void Initialize([In][MarshalAs(UnmanagedType.Interface)]  IWbemMetaData   pMetaData, [In][MarshalAs(UnmanagedType.Interface)]  IWbemMultiTarget   pMultiTarget);
        void Lock();
        void Unlock();
        void AddFilter([In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pContext, [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszQuery, [In] UInt32 Id);
        void RemoveFilter([In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pContext, [In] UInt32 Id);
        void RemoveAllFilters([In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pContext);
        void AddDefinitionQuery([In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pContext, [In][MarshalAs(UnmanagedType.LPWStr)]  string   wszQuery);
        void RemoveAllDefinitionQueries([In][MarshalAs(UnmanagedType.Interface)]  IWbemContext   pContext);
        void Disconnect();
    } // end of IWbemFilterProxy
 
    [TypeLibTypeAttribute(0x0202)]
    [GuidAttribute("6C19BE35-7500-11D1-AD94-00C04FD8FDFF")]
    [ClassInterfaceAttribute((short)0x0000)]
    [ComImport]
    class WbemFilterProxy  /*: IWbemFilterProxy, IWbemObjectSink*/
    {
    } // end of WbemFilterProxy
#endif