Hi
I have this problem that I have been trying to solve for few days.

The problem is this:
I have developed a MMC Snap-in DLL in C#. All the MMC COM-interfaces are
redefined on .Net-side and following attributes are given to each
interface:

 [   ComImport,
 InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 Guid("955AB28A-5218-11D0-A985-00C04FD8D565")     ]

The C# MMC snapin implements IComponent and IComponentData interfaces.
When MMC.exe executes, it can recognize this C# DLL as a COM Snap-in DLL
and loads and displays it correctly in Snap-in console's left pane.

IComponentData has an interface-method named Initialize() that is
implemented by MySnapin class and called by MMC at start-up. Inside
Initialize(object  pUnknown), I initialize an instance member (say,
myObject) of the MySnapin class with the object passed by MMC to the
Initialize(..) method during start-up. This object is saved  (as per MSDN
documentation) so that it can be reused later-on to get IConsoleNamespace2
or any other MMC supported interfaces by simple casting. And this casting
merely calls QueryInterface() to get the particular interface to which it
is casted.

And here is the problem. When I access this saved object myObject (by
casting it to IConsoleNamespace2) from anywhere within MMC-created-Thread
(that is the thread that loads the snapin itself), it works fine.

However, when I create a Timer(System.Threading.Timer or
System.Timers.Timer) inside MySnapin class and I access myObject (by
casting it to IConsoleNamespace2) within the timer-callback method--I get
an exception with the following message:

QueryInterface for interface IConsoleNamespace2 failed.

Things I have tried so far but have not worked:
1) When I WriteLine() ApartmentState for MMC main thread, it gives me STA
inside Initialize(). So I concluded that MMC is running in STA.
2) When I WriteLine() ApartmentState for Timer callback method, that
thread gives me MTA which is okay as all Timer callbacks are using
Threadpool threads and these are MTA by nature.

3) So with an assumption that it is an Apartment-mismatch, I took out
Timer from mySnapin code and created a Thread and specifically set the
apartment state to STA, but still the Thread-method gives the same error
when it accesses the myobject. It did not work forcing me to think that it
is not an apartment issue.

4) As per my needs, I want to to use this solution with timer.

The code snippet is given below. It has been commented to describe the
problem:

/////////////////////////////////////////////////////////////////////////
 [ProgId("SystemManagerClient.SnapinBase")]
    [Guid("6B884F7C-2870-4454-B347-94AD58382A7D")]
     [SnapinAttribute("My Product", "MyCompany", "1.0")]

     public class SnapinBase :
          IComponentData,
          IExtendContextMenu,
          IExtendPropertySheet,
          ISnapinHelp2
     {
    //This is the object that I want to initialize by Object pUnknown that
          //MMC COM framework passes me when it loads this DLL and calls
          //Initialize(Object pUnknown)
          System.Object myObject;

//Alternatively I tried casting the Object pUnknown
as //IConsoleNameSpace2 //and save it for use from thrred
          IConsoleNameSpace2 consoleNamespace;


          //This method works fine and is called only once by MMC COM
framework when it loads this dll that contains this class
          //along with oter classes.
          public void Initialize(Object pUnknown)
          {


               try
               {

                    //myObject_New=new System.Runtime.Remoting.ObjectHandle
(pUnknown);
                    //1st trial: Later access in myThread's DoSomething()
gives Cast invalid if myObject is casted to IConsoleNameSpace2
                    //See code for DoSomething()
                    myObject=pUnknown;

                    //2nd trial
                    //Or following:
                    //This when accessed over myThread's DoSomething()
gives QueryInterface() failed for IConsoleNameSpace2 interface.
                    //See code for DoSomething()
                    //consoleNamespace=(IConsoleNameSpace2)pUnknown;

                    // Allow startup initialization for each node
                    foreach(BaseNode node in nodes.Values)
                         node.Initialize();

                    // Add the images needed for the snapin
                    IImageList il = null;
                    console2.QueryScopeImageList(out il);

                    // Add the snapin - global images to the scope pane
                    images.LoadImageList(il);


                    // Forward to the root node to see if any nodes care
to add their node specific
                    // icons to the image list
                    RootNode.OnAddScopePaneImages(il);

                    //////////////////////////////////////
                    //Following is the thread that will later on use
this.myObject that I saved earlier in this method

                    myThread=new Thread(new ThreadStart(this.DoSomething));
                    myThread.IsBackground=true;
                    myThread.ApartmentState=ApartmentState.STA;


               }
               catch(Exception e)
               {
                    System.Diagnostics.Debug.WriteLine("Initialize failed -
 " + e.Message);
               }
          }


          public void DoSomething()
          {

               ControllerNode node;
               try
               {
                         Thread.Sleep(10000);

                         node = (ControllerNode)FindNodeByName("XPLOGO1");
                         node.DeviceState=2;

                         SCOPEDATAITEM sdi = new SCOPEDATAITEM();
                         sdi = node.ScopeDataItem;
                         sdi.nImage = node.GetSmallDeviceImage();
                         sdi.nOpenImage = node.GetSmallDeviceImage();
                         node.OnRefresh();

                    //The problem code starts here..
                         //object myObject_2 = myObject_New.Unwrap();

                    //IConsoleNameSpace2 cns2=(IConsoleNameSpace2)
myObject_New.Unwrap();


                    /*     if
(System.Runtime.Remoting.RemotingServices.IsTransparentProxy(myObject_2))
                              System.Diagnostics.Debug.WriteLine("The
unwrapped object is a proxy.");
                         else
                              System.Diagnostics.Debug.WriteLine("The
unwrapped object is not a proxy!");
                         IConsoleNameSpace2 cns2=myObject_2 as
IConsoleNameSpace2;
                         */

                    //This is what I want to achieve, but after this line
is executed,
                    //I get Invalid cast message when control jumps to
Exception Block
                    //Trial 1
                    IConsoleNameSpace2 cns2=(IConsoleNameSpace2)myObject;
                    cns2.SetItem(ref sdi);

                    //Alternatively If I save pUnknown as
IConsoleNameSpace2 in Initialize() and use it directly as
                    //folloowing, then I get QueryInterface() failed for
IConsoleNamespace2
                    //Trial 2
                    //consoleNamespace.SetItem(ref sdi);

               }
               catch(Exception e)
               {
                    System.Diagnostics.Debug.WriteLine(e.Message);
               }




          }

          //C# equivalent definitions of MMC COM interfaces.
          //One example of how I define them is given below. Rest of the
interfaces are also defined similar to this.
          //All the code works fine. It gives problem only when I go on a
different thread to access these.
          //Either STA thread created by me
          //or A timer callback thread that is MTA in nature as it uses a
thread from threadpool
          [
               ComImport,
               InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
               Guid("255F18CC-65DB-11D1-A7DC-00C04FD8D565")
          ]
               public interface IConsoleNameSpace2
          {
               void InsertItem(ref SCOPEDATAITEM a);
               void DeleteItem(uint a, int b);
               void SetItem(ref SCOPEDATAITEM a);
               void GetItem(ref SCOPEDATAITEM a);
               void GetChildItem(uint a, ref uint b, ref int c);
               void GetNextItem(uint a, ref uint b, ref int c);
               void GetParentItem(uint a, ref uint b, ref int c);
               void Expand(uint a);
               void AddExtension(CLSID a, ref SCOPEDATAITEM b);
          }


/////////////////////////////////////////////////////////////////////////

Any help would be really appreciated. Please write to me at
[EMAIL PROTECTED] if you want any more clarifications regarind this
problem.

Thanks
Raja

===================================
This list is hosted by DevelopMentor�  http://www.develop.com
NEW! ASP.NET courses you may be interested in:

2 Days of ASP.NET, 29 Sept 2003, in Redmond
http://www.develop.com/courses/2daspdotnet

Guerrilla ASP.NET, 13 Oct 2003, in Boston
http://www.develop.com/courses/gaspdotnet

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to