views:

670

answers:

3

Error im getting:

An unhandled exception of type 'System.StackOverflowException' occurred in System.Management.dll

My callstack:

[Managed to Native Transition]
System.Management.dll!System.Management.ManagementScope.InitializeGuts(object o) + 0x1a3 bytes

System.Management.dll!System.Management.ManagementScope.Initialize() + 0xa3 bytes
System.Management.dll!System.Management.ManagementScope.Connect() + 0x5 bytes
Computer_Managerment.exe!Computer_Managerment.WMI.ComputerInformation.ComputerInformation(string ComputerName = "pc357", string UserName = "", string Password = "") Line 228 + 0xd bytes C#
Computer_Managerment.exe!Computer_Managerment.ScanAllComputers.Workerthread() Line 95 + 0x1e bytes C#
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x66 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes

Code where i get the stackoverflow:

try
{
  gManager = new ManagementScope(ConnectStr, oConn); //\\\\" + 
  gManager.Connect(); // This is where the crash happens
}
catch (UnauthorizedAccessException)
{
  // Code removed
}

The code basicly works in this fastion
1) I have a list of all the computers in AD ( Over 1k )
2) I have 10 threads spinning a while loop getting a compuer out of the Que List.
3) When they have a computer name they make a instance of the ComputerInformation class that does the gManager.Connect(); that again crashes.

Its my understanding that this crash/stackoverflow is happening inside native code, but i assume im doing something wrong. If any more code is required il happely post it.

Pr request more code: This is the code that the workers live in ( Normaly around 10 workers )

internal struct stWorkList
{
    public Queue<string> Work;
    public List<ComputerInformation> CompInfo;
    public int FailedComputers;
    public int FailedPingCheck;
    public int SuccessComputers;
    public int TotalComputers;
    public int FailedAuth;
    public int FailedToContactWMIServer;
}
stWorkList gWorkList;

void Workerthread()
{
    Monitor.Enter(gUserName);
    Monitor.Enter(gPassword);
    string UserName = gUserName;
    string Password = gPassword;
    Monitor.Exit(gPassword);
    Monitor.Exit(gUserName);

    while (true)
    {
    Monitor.Enter(gWorkList.Work);
    if (gWorkList.Work.Count == 0)
    {
     Monitor.Exit(gWorkList.Work);
     break;
    }

    string ComputerName = gWorkList.Work.Dequeue();
    Monitor.Exit(gWorkList.Work);

    if (ComputerName == null)
     continue;

    ComputerInformation iCI = new ComputerInformation(ComputerName, UserName, Password);

    Monitor.Enter(gWorkList.CompInfo);
    gWorkList.CompInfo.Add(iCI);

    switch (iCI.Status)
    {
     case eComputerCheckStatus.Connected:
      gWorkList.SuccessComputers++;
      break;

     case eComputerCheckStatus.FailedPingTest:
      gWorkList.FailedPingCheck++;
      gWorkList.FailedComputers++;
      break;

     case eComputerCheckStatus.UnauthorizedAccessException:
      gWorkList.FailedComputers++;
      gWorkList.FailedAuth++;
      break;

     case eComputerCheckStatus.FailedToContactWMIService:
      gWorkList.FailedToContactWMIServer++;
      gWorkList.FailedComputers++;
      break;

     case eComputerCheckStatus.UnkownFailed:
      gWorkList.FailedComputers++;
      break;
    }

    Monitor.Exit(gWorkList.CompInfo);
    iCI.Dispose();
    }
}

Constructor in the ComputerInformation class

public ComputerInformation(string ComputerName, string UserName, string Password)
{
    gComputerName = ComputerName;
    gHardDriveList = new List<stHarddiskInfo>();
    gProccessInfo = new List<stProccessInfo>();
    gCPUInfo = new List<stCPUInformation>();
    gOSInfo = new stOSInfo();
    gMemoryInfo = new List<stMemoryInfo>();
    gPreformanceMemory = new stPreformanceMemory();
    gProccessOverView = new stProccessOverview();
    gMonitorInfo = new List<stMonitorInfo>();
    gNetworkInfo = new List<stNetworkInfo>();
    netMon = new Ping();

    PingResponse response = netMon.PingHost(ComputerName, 1);
    if (response == null || response.PacketsReceived == 0)
    {
     gStatus = eComputerCheckStatus.FailedPingTest;
     gHasError = true;
     return;
    }
    gComputerIP = response.ServerEndPoint.Address.ToString();

    ConnectionOptions oConn = new ConnectionOptions();
    oConn.Timeout = new TimeSpan(0, 0, 10);

    if (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(UserName))
    {
     oConn.Username = UserName;
     oConn.Password = Password;
    }

    string ConnectStr = "\\\\" + ComputerName + "\\root\\cimv2";
    try
    {
     gManager = new ManagementScope(ConnectStr, oConn); //\\\\" + 
     gManager.Connect();  // this is where it crashes
    }
    catch (UnauthorizedAccessException)
    {
     gStatus = eComputerCheckStatus.UnauthorizedAccessException;
     gHasError = true;
     return;
    }
    catch (Exception Ex)
    {
    if (Ex.Message.Contains("The RPC server is unavailable"))
    {
     gStatus = eComputerCheckStatus.FailedToContactWMIService;
    }
    else
     gStatus = eComputerCheckStatus.UnkownFailed;

    gHasError = true;
    return;
    }

    gStatus = eComputerCheckStatus.Connected;

    try
    {
     GetRunningProccessInfo();
     GetCPUInformation();
     GetHardDriveInfo();
     GetOSInfo();
     GetMemoryInfo();
     GetMonitorInfo();
     GetComputerSystem();
    }
    catch
    {
     gStatus = eComputerCheckStatus.UnkownFailed;
     gHasError = true;
    }
}
+1  A: 

This is purely speculation, but if it is something you are doing wrong, then it should be in the parameters that are being passed to the initialization of gManger.

The next thing, if you were to post something, is the oConn object instantiation. Possibly there are some incorrect parameters there that are causing problems later on.

I haven't used this class in my coding, so beyond just looking at the parameters, this is all... with one caveat:

the MSDN article on ManagementScope had an interesting tid-bit about this library not being able to be used by partially trusted code.

For more information see .Net Framework Security section of this page.

Otherwise, good luck.

EDIT: Just an additional thought. Since this is happening with multiple threads, there may be some issues if a string is trying to be read from/written to from across threads. It might be helpful to see a larger context from your code.

I'm sorry I'm not of more help here, but maybe my thoughts will help you (or anyone else) resolve this.

fauxtrot
Just for grins, what WMI provider are you using?
fauxtrot
Added more code
EKS
I've thought some more on this, when debugging, does one instance succeed and then subsequent instances fail, or does the first fail? I found some discussion at http://objectmix.com/dotnet/109277-wmi-threading.html It seems that this might be related to your problem.
fauxtrot
When You are copying the username and password, try using the Copy/CopyTo method. If there is a problem in your code, Its probably happening there, as the reference is passed upon blocking, then handed off merrily to be changed by threads later on for next computer. A tell/tale sign of this would be durning debug to look at the value of UserName/Password 2 steps before crash, 1 step before crash at crash.
fauxtrot
Thank you for the suggestion.The username and password never changes, but i did try using string.Copy() but i get the same error.
EKS
+1  A: 

I doubt you will get a smoking gun answer here as you have not posted enough code. Most StackOverflow errors come from a looping error.

I ran the code you posted with no trouble. Here is how I would debug:

Make sure you are not sharing any object on the threads!!! Close all connections and do not reuse them.

  1. Run the code you posted outside of the thread loop.
  2. Run the code in a loop without threading.
  3. Use the thread pool instead of Threadstart. A good TP one is SmartThreadPool which has advantages over the built in one.

Try the above and if you still have a problem post more code.

Gary
Code works just fine outside the thread loop, the code used to work inside the loop but its not anymore.I dont share any information in the between the threads other then the username and password thats read on thread startup.
EKS
+1  A: 

good point to start, is to check if this code is throwing exception.

        ManagementScope scope = new ManagementScope(@"\\localhost\root\cimv2");
        scope.Connect();

Update
You doesnt have Monitor.Enter/Exit block on iCI initialization (and where existing problem exception).
to check if this is the problem you can make simple log.

  gManager = new ManagementScope(ConnectStr, oConn); 
  Debug.WriteLine("connect to "+ComputerName+" by "+UserName+"/"+Password);
  gManager.Connect();             // this is where it crashes
  Debug.WriteLine("success on "+ComputerName+" by "+UserName+"/"+Password);

if my suggestion is right, you will receive in log, something like this:
"connect to computer1"
"connect to computer2"
and immidiately exception.

Avram
Why would i use that on local variables?
EKS
I used a volitile bool to make sure only 1 thread can create a instance of ManagementScope and then use it to connect. That worked, im giving you the bounty because you where the closest.
EKS