Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
biznatchio
Mar 31, 2001


Buglord

rolleyes posted:

Quick followup question - what are the implications of passing unmanaged resources to other methods? Does the 'using' in the parent maintain resource safety or would the target method need to do use it too? Or does it depend on the way exceptions are handled within the target method?

This code:

code:
using (StreamWriter sw = new StreamWriter(x))
{
    // zip zop zoobity dop
}
is exactly equivalent to the following code:

code:
StreamWriter sw = null;
try
{
    sw = new StreamWriter(x);
    // zip zop zoobity dop
}
finally
{
    if (sw != null && sw is IDisposable)
        ((IDisposable)sw).Dispose();
}
So as far as passing the StreamWriter to other methods; yes, you can do that. It's a normal local variable. However, once the flow of execution exits the using block, the StreamWriter will be disposed. And that happens regardless of whether the flow of execution left the block normally, or because an exception was thrown and unwound the call stack past it.

So if the method you're calling is going to write some stuff to the StreamWriter, then return without keeping state around, it'll work just fine. If the method is going to squirrel away the StreamWriter in a field somewhere and try to reference it later, you might have a problem if "later" is after execution has left the using block.

Adbot
ADBOT LOVES YOU

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?
I'd figured actually storing it (as opposed to just using it and returning) would be a bad idea for just that reason. The ability to stack multiple using statements is handy too.

Thanks for the help guys.

rolleyes fucked around with this message at 19:00 on Sep 10, 2011

Dr Monkeysee
Oct 11, 2002

just a fox like a hundred thousand others
Nap Ghost
It's sorta interesting to note that the stacking of using statements isn't anything special, it's just a statement idiom that's generally frowned upon elsewhere.

Just like c/c++ and Java it's possible to have control statements followed by a single statement instead of a block of statements. E.g.

code:
if (myCondition)
   MyObj.DoStuff();
Instead of:

code:
if (myCondition)
{
   MyObj.DoStuff();
}
Though the former is generally frowned upon as being less clear. Of course a control statement is just another kind of statement so it can also follow another control statement directly:

code:
if (myCondition)
   if (anotherCondition)
      MyObj.DoStuff();
Which again is just a shorter (and unrecommended) way of writing

code:
if (myCondition)
{
   if (anotherCondition)
   {
      MyObj.DoStuff();
   }
}
Since usings are just another kind of control statement you can write

code:
using (my using expression)
   using (my nested using expression)
      MyObj.DoStuff();
Since the idiom is common enough MS has blessed it in their style guide with a minor syntactical modification to make it less like the non-recommended way of doing control statement blocks:

code:
using (my using expression)
using (my nested using expression)
{
      MyObj.DoStuff();
}
Tada. "Stacked" using statements. Technically speaking you could write any nested control statements this way, it's just not done because except in the case of using statements it just looks weird and is generally considered to be less clear.

Dr Monkeysee fucked around with this message at 21:03 on Sep 11, 2011

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.
I was reading through some Microsoft example code when I came across this:
code:
        public event ProgressChangedEventHandler ProgressChanged;

        private void UpdateProgressChanged()
        {
            ProgressChangedEventHandler handler = ProgressChanged;
            if (handler != null)
            {
                double progress = _curFrame * 100.0 / _options.NumberOfOutputFrames;
                handler(this, new ProgressChangedEventArgs((int)progress, null));
            }
        }
I don't get why they are declaring the variable handler within UpdateProgressChanged, wouldn't it be simpler to just do a null check on the event directly like
code:
        public event ProgressChangedEventHandler ProgressChanged;

        private void UpdateProgressChanged()
        {
            if (ProgressChanged != null)
            {
                double progress = _curFrame * 100.0 / _options.NumberOfOutputFrames;
                ProgressChanged(this, new ProgressChangedEventArgs((int)progress, null));
            }
        }
That's the way I've always triggered events, is there some subtlety I'm missing that makes the extra variable declaration useful? This code is a parallel computation example if that makes any difference.

Orzo
Sep 3, 2004

IT! IT is confusing! Say your goddamn pronouns!

PDP-1 posted:

That's the way I've always triggered events, is there some subtlety I'm missing that makes the extra variable declaration useful? This code is a parallel computation example if that makes any difference.
http://stackoverflow.com/questions/2582052/c-event-handlers-not-thread-safe
http://piers7.blogspot.com/2010/03/3-races-with-net-events.html

By declaring a local copy you're ensuring thread safety.

epswing
Nov 4, 2003

Soiled Meat
Is it bad form to just declare events like

code:
public event ProgressChangedEventHandler ProgressChanged = delegate { };
No null check required, ever.

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.

Ah ok, that explains it. I've never seen that done before but it makes sense that they would be being extra careful about thread safety in a multi-threaded example.

Thanks!

Sedro
Dec 31, 2008
I wouldn't use events in a multithreaded scenario because there's still a race condition: the invocation list could change between the temporary multicast delegate assignment and the event raise finishing. You could fix that by wrapping the entire event fire in a mutex, but that seems like a quick way to introduce deadlocks. Instead use Task, Async, IObservable, etc for your multithreading needs.

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.
The second link that Orzo gave references a blog post by Eric Lippert that addresses that second race condition. He argues that thread safety is a two part problem: (1) the object raising the event has to guard against null references by making a local copy of the multicast delegate, and (2) any objects subscribed to the event have to internally track what events they are currently listening to and need to fail gracefully if an event is fired after they unsubscribe (or ignore it).

The first problem is solvable by making the local copy, but the second problem doesn't seem to have a really clean solution in the sense that you have the coupled logic of un/subscribing to events plus the internal 'what am I listening for' code. If you change one part you have to remember to change the other part or risk transient and unrepeatable bugs.

So yeah, either not using events or using them sparingly and only as a last resort seems to be the best option for multithreaded systems with transient event listeners.

biznatchio
Mar 31, 2001


Buglord

Sedro posted:

I wouldn't use events in a multithreaded scenario because there's still a race condition: the invocation list could change between the temporary multicast delegate assignment and the event raise finishing. You could fix that by wrapping the entire event fire in a mutex, but that seems like a quick way to introduce deadlocks. Instead use Task, Async, IObservable, etc for your multithreading needs.

Delegate instances (including multicast delegates) are immutable. If someone adds or removes themselves from the invocation list of an event while another thread is simultaneously iterating over the list to deliver event notifications, it won't break anything because the iterating thread is working from what is effectively a snapshot of the list.

What is still a potential race condition in multithreaded events is add/remove. Since the delegate instance is immutable, simultaneous access from two threads won't corrupt the list, but an update to the field made on one thread might be lost if another thread is in the middle of combining a new delegate instance together as well. Simple Monitor.Lock mutex in the event's add and remove blocks would make that problem go away though.

biznatchio fucked around with this message at 07:00 on Sep 12, 2011

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?
Ok, since this is something I imagine I'll come across sooner or later, let me just check I've got this.

Initially, I was wondering why creating a local copy would make any difference because it would still refer to the same instance (delegates are reference types yes?) so any changes would still be seen by the local copy. But, because delegates are immutable (a-la-strings) what actually happens when one is changed is that it creates a new instance with the changes and returns it, so the local copy still refers to the original instance but the 'real' copy now refers to a new instance?

And then I guess once the local copy falls out of scope the garbage collector eats it, assuming no other references.

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:

epswing posted:

Is it bad form to just declare events like

code:
public event ProgressChangedEventHandler ProgressChanged = delegate { };
No null check required, ever.

It's not terrible, but you do lose the ability to easily check if you even have handlers, and it won't work at all if you have an eventhandler that doesn't return void (doing so is a horror in and of itself, but it is used in some places, e.g. the AppDomain assembly load events).

I just defined two extension methods and used them instead:
code:
public static void Raise(this EventHandler handler, object sender, EventArgs e)
{
   if (handler != null)
      handler(sender, e);
}

public static void Raise<TEventArgs>(this EventHandler<TEventArgs> handler, object sender, TEventArgs e)
   where TEventArgs : EventArgs
{
   if (handler != null)
      handler(sender, e);
}

biznatchio posted:

What is still a potential race condition in multithreaded events is add/remove. Since the delegate instance is immutable, simultaneous access from two threads won't corrupt the list, but an update to the field made on one thread might be lost if another thread is in the middle of combining a new delegate instance together as well. Simple Monitor.Lock mutex in the event's add and remove blocks would make that problem go away though.

The default implementation of add/remove is thread safe though, so, unless you define them explicitly, you don't have to worry about it.

edit:

rolleyes posted:

But, because delegates are immutable (a-la-strings) what actually happens when one is changed is that it creates a new instance with the changes and returns it, so the local copy still refers to the original instance but the 'real' copy now refers to a new instance?

Yep.

dwazegek fucked around with this message at 09:16 on Sep 12, 2011

epswing
Nov 4, 2003

Soiled Meat

dwazegek posted:

I just defined two extension methods and used them instead

That's pretty spiffy. Extension methods are still black magic to me. I love them :)

Holy Diver
Jan 4, 2006

by angerbeet
I've got a custom ASP.NET control that I don't have the source code for. This control has events which I have added handlers for, but they don't behave as I expect them to.

The events are processed asynchronously and, when debugging, the postbacks never hit my Page_Load event (they go straight into the event handler). Any changes I make while in these handlers do not "hold". That is, if I have a string which I set equal to "test" in the handler, I can set a watch for that string and its value is not "test" until I enter back into the handler code. It's like there are two conflicting versions of the variable, one that exists in the rest of my code and one that exists in this control's handler.

What could be going on here? How do I get it so I can change and update values while in this control's event handlers?

edit: Never mind, got my answer:

quote:

The events are static so you cannot set page control properties which are instance variables.
For example you send an email or write to a log file in the event, however you can’t just update the page because event is not raised in the context of page.
When the control is displayed, the host page is already finished executing and sent to the browser. The AJAX actions are not part of the page, they are handled with a http handler.

Holy Diver fucked around with this message at 21:43 on Sep 12, 2011

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?
I've spent the last couple of evenings messing about with something which... well I've got it working after a few accidental infinite process creation loops, but I can't decide whether it was a dumb idea or not.

The users of that analysis app I was asking about a page or so back would find it useful to run it from both the command line and as a GUI. Rather than having two separate binaries I did some googling and now have a single binary which, through a dirty hack, does both. To summarise:
  • I'm collecting command line arguments as per this.
  • I've got access to Win32's CreateProcess as per this (because Process.Start() can't create detached processes - more on that in a bit).
  • The application is a WPF application (i.e. was created as a new WPF application in VS) but I've changed the output type to "Console Application" in the project properties.

The problem now is that when the app starts, up pops a GUI with a console window behind it. This is where the dirty hack comes in.
  • Decide on a 'special' command line argument which means 'Run in a GUI'.
  • If the application is started with arguments but without the 'special' argument then do not call InitializeComponent() in the MainWindow constructor - the app is now running as a console application and the GUI never loads. Do the console-based stuff and then call Environment.Exit().
  • If the application is started with zero arguments (i.e. double-clicked in explorer) then we assume we want to run as a GUI app, so in the MainWindow constructor there's a call like this:
    code:
    //6th parameter as 8 = DETACHED_PROCESS.
    //See [url]http://msdn.microsoft.com/en-us/library/ms682425%28v=vs.85%29.aspx[/url]
    //And [url]http://msdn.microsoft.com/en-us/library/ms684863%28v=vs.85%29.aspx[/url]
    CreateProcess(path, " /displaymode:gui", IntPtr.Zero, IntPtr.Zero, false, 0x00000008, IntPtr.Zero, null, ref si, out pi);
    
  • This starts another instance of the application disconnected from the console which started the first one, and because the 'special' command line argument is passed then this time the code in the MainWindow constructor calls InitializeComponent() and skips all the console stuff. Tadaa - we've just started up as a GUI application and the console is free because the initial instance has ended.

The only artifact of this you see when starting the application by launching it from explorer is that a console window briefly flickers on the screen as the initial instance starts, calls CreateProcess and exits before the second instance appears as a GUI.

While I'm frankly amazed that this is working, is this a really awful idea? The obvious downside is that the chain of execution for the console mode is all happening inside the MainWindow constructor but other than that I can't see anything immediately dangerous. I'd never build a large app like this but this is just a simple utility I'm building to replace a legacy version.


edit:
Just to clarify this is definitely not my own work - I found the rough description of how to do this in a stackoverflow post (I think) and googled the details.

rolleyes fucked around with this message at 23:17 on Sep 12, 2011

ninjeff
Jan 19, 2004

rolleyes posted:

I've spent the last couple of evenings messing about with something which... well I've got it working after a few accidental infinite process creation loops, but I can't decide whether it was a dumb idea or not.

The users of that analysis app I was asking about a page or so back would find it useful to run it from both the command line and as a GUI. Rather than having two separate binaries I did some googling and now have a single binary which, through a dirty hack, does both. To summarise:
  • I'm collecting command line arguments as per this.
  • I've got access to Win32's CreateProcess as per this (because Process.Start() can't create detached processes - more on that in a bit).
  • The application is a WPF application (i.e. was created as a new WPF application in VS) but I've changed the output type to "Console Application" in the project properties.

The problem now is that when the app starts, up pops a GUI with a console window behind it. This is where the dirty hack comes in.
  • Decide on a 'special' command line argument which means 'Run in a GUI'.
  • If the application is started with arguments but without the 'special' argument then do not call InitializeComponent() in the MainWindow constructor - the app is now running as a console application and the GUI never loads. Do the console-based stuff and then call Environment.Exit().
  • If the application is started with zero arguments (i.e. double-clicked in explorer) then we assume we want to run as a GUI app, so in the MainWindow constructor there's a call like this:
    code:
    //6th parameter as 8 = DETACHED_PROCESS.
    //See [url]http://msdn.microsoft.com/en-us/library/ms682425%28v=vs.85%29.aspx[/url]
    //And [url]http://msdn.microsoft.com/en-us/library/ms684863%28v=vs.85%29.aspx[/url]
    CreateProcess(path, " /displaymode:gui", IntPtr.Zero, IntPtr.Zero, false, 0x00000008, IntPtr.Zero, null, ref si, out pi);
    
  • This starts another instance of the application disconnected from the console which started the first one, and because the 'special' command line argument is passed then this time the code in the MainWindow constructor calls InitializeComponent() and skips all the console stuff. Tadaa - we've just started up as a GUI application and the console is free because the initial instance has ended.

The only artifact of this you see when starting the application by launching it from explorer is that a console window briefly flickers on the screen as the initial instance starts, calls CreateProcess and exits before the second instance appears as a GUI.

While I'm frankly amazed that this is working, is this a really awful idea? The obvious downside is that the chain of execution for the console mode is all happening inside the MainWindow constructor but other than that I can't see anything immediately dangerous. I'd never build a large app like this but this is just a simple utility I'm building to replace a legacy version.


edit:
Just to clarify this is definitely not my own work - I found the rough description of how to do this in a stackoverflow post (I think) and googled the details.

You don't need to do your "dirty hack" logic in MainWindow's constructor. If you open up your Application.xaml and remove the StartupUri attribute from the root element, then you can add an event handler to Application.Startup. Add your logic to check command line arguments and either create or not create MainWindow there.

Zhentar
Sep 28, 2003

Brilliant Master Genius
Say I have a function prototype like so:
code:
public T CreateAndDoSomething<T>(Action<T> somethingDoer) where T : new()
Is it even possible for type inference to resolve T there?

ljw1004
Jan 18, 2005

rum

Zhentar posted:

Say I have a function prototype like so:
code:
public T CreateAndDoSomething<T>(Action<T> somethingDoer) where T : new()
Is it even possible for type inference to resolve T there?

Yes, sure.

code:
static void Main() {
    Action<int> a = null;
    f(a);  // infers T=int

    f((int i) => { });  // infers T=int
}

static T f<T>(Action<T> a) where T : new() {
    return default(T);
}
However, it has to infer T from the Action<T> argument. It will never infer from what you do with the return type.

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?

ninjeff posted:

You don't need to do your "dirty hack" logic in MainWindow's constructor. If you open up your Application.xaml and remove the StartupUri attribute from the root element, then you can add an event handler to Application.Startup. Add your logic to check command line arguments and either create or not create MainWindow there.

Could you elaborate slightly? My XAML knowledge is not great, which is one of the reasons this is a WPF project (for learning). I already have a startup event handler which grabs the command line arguments (but doesn't do the processing on them). My App.xaml currently looks like this:
code:
<Application x:Class="myAppName.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             Startup="Application_Startup">
    <Application.Resources>
    </Application.Resources>
</Application>
If I move the command line argument processing into the Application_Startup() event handler and remove the StarupUri param from App.xaml, how do I then launch the WPF form when running in GUI mode? Is it the same as calling any other WPF form? In which case I guess I need to add something like this to Application_Startup() for the GUI case:
code:
MainWindow mainWindow = new MainWindow();
mainWindow.Show();  (or should it be mainWindow.ShowDialog()?)
Thanks for the advice so far.


edit:
I've pretty much answered my own question by trying this, and the short version is that the above is correct. The only thing I'm unsure of is Show() vs. ShowDialog(). Does it even matter when it's the first form to be shown?

rolleyes fucked around with this message at 20:58 on Sep 14, 2011

ljw1004
Jan 18, 2005

rum
Has anyone been watching the Windows 8 talks at today's BUILD conference?

UI guidelines for "Metro" apps, by Jensen Harris:
http://channel9.msdn.com/Events/BUILD/BUILD2011/BPS-1004

How to build Metro apps using C#/VB/XAML -- also covers C++/XAML and Javascript/HTML, but the .NET approach used async :) . By Ales Holocek and John Sheehan for the first half, and then Kieren Mockford and Chris Sells at the 1h08 mark:
http://channel9.msdn.com/Events/BUILD/BUILD2011/BPS-1005

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?

ljw1004 posted:

How to build Metro apps using C#/VB/XAML -- also covers C++/XAML and Javascript/HTML, but the .NET approach used async :) . By Ales Holocek and John Sheehan for the first half, and then Kieren Mockford and Chris Sells at the 1h08 mark:
http://channel9.msdn.com/Events/BUILD/BUILD2011/BPS-1005

Hopefully that will go some way to calming all the "omg no .NET in Windows 8" hysteria which blew up a couple of months back. I've caught bits of the presentation and skimmed a few news stories, at some point I really need to sit down and watch it all.

Zhentar
Sep 28, 2003

Brilliant Master Genius

ljw1004 posted:

However, it has to infer T from the Action<T> argument. It will never infer from what you do with the return type.

Ah, yeah. I secretly meant "without an explicitly typed Action<T>".

I'm pretty sure the answer to this is no, but is there any way to make a generic constraint on a generic class, e.g. where T : List<>?

Sedro
Dec 31, 2008

Zhentar posted:

Ah, yeah. I secretly meant "without an explicitly typed Action<T>".

I'm pretty sure the answer to this is no, but is there any way to make a generic constraint on a generic class, e.g. where T : List<>?

Sure, but you'll need to at least have a type param for the item. .NET generics don't use type erasure. Here are a few things you can do, depending on what you want to accomplish. What do you want to accomplish?
code:
static ICollection<TItem> ItemParamOnly<TItem>(ICollection<TItem> collection)
{
    return collection;
}

static TCollection CollectionParamOnly<TCollection>(TCollection collection)
    where TCollection : ICollection
{
    return collection;
}

static TCollection ItemAndCollectionParams<TCollection, TItem>(TCollection collection)
    where TCollection : ICollection<TItem>
{
    return collection;
}

static void Main(string[] args)
{
    var arrayList = new List<string>();
    var linkedList = new LinkedList<string>();

    // compile errors: can't cast from ICollection<string>
    arrayList = ItemParamOnly(arrayList);
    linkedList = ItemParamOnly(linkedList);

    // works, but uses non-generic ICollection
    arrayList = CollectionParamOnly(arrayList);
    linkedList = CollectionParamOnly(linkedList);

    // works, but type params can't be inferred
    arrayList = ItemAndCollectionParams<List<string>, string>(arrayList);
    linkedList = ItemAndCollectionParams<LinkedList<string>, string>(linkedList);
}

Ashex
Jun 25, 2007

These pipes are cleeeean!!!
I hacked together a really lovely VBscript for a project I'm working on.

Basically what it does it pull information about a workstation via WMI when I give it a text file with a list of them.

I have it working with a list of a few workstations around me (six of them). However when I give it the full list of 37 machines it craps itself with the message "Error: 438 - Object doesn't support this property or method" after one computer.

I assumed it was the second computer that made it die so I used a second script (both the same one just takes the computer as the argument) and it ran just fine, so what the gently caress?


Here is the hideous script:

code:
' -----------------------------------------------------------------
' Syntax: cscript collectsysteminfo.vbs file
' Author: Ahmed Osman
' Date: September 14, 2011
' Change log:
' no changes
'------------------------------------------------------------------
 
Option Explicit

On Error Resume Next

Dim oLogObject, oMsgOutput, oLogOutput, sLogFile, sMsgFile

set oLogOutput = nothing


Dim aArgs, strComputer, objWMIService, colItems, objItem, strMsg, logMsg
Dim arrComputers, item, strTextFile, num, objTextFile, objFSO, strText


Const ForReading = 1

If Wscript.Arguments.Count = 0 Then
   Wscript.Echo "No text file was specified."
   Wscript.Echo "Syntax: cscript collectsysteminfo.vbs file"
   Wscript.quit 1
Else
   strTextFile = Wscript.Arguments(0)
End If


'Read server file
set objFSO = CreateObject("Scripting.FileSystemObject")
set objTextFile = objFSO.OpenTextFile(strTextFile, ForReading)
strText = objTextFile.ReadAll
objTextFile.Close
arrComputers = Split(strText, vbCrLf)

'Start the loops
for each strComputer in arrComputers


Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 


' Save to CSV file
sLogFile = "Output.csv"
sMsgFile = "Details.txt"

set oLogObject = CreateObject("Scripting.FileSystemObject")
set oMsgOutput = oLogObject.CreateTextFile(sMsgFile)

If oLogObject.FileExists(sLogFile) Then
	set oLogOutput = oLogObject.OpenTextFile _
           (sLogFile, 8, True)
Else
	set oLogOutput = oLogObject.CreateTextFile(sLogFile)
		oLogOutput.WriteLine "Name,Memory," & _
    "Manufacturer,Model,NumberofCores,ProcSpeed,Drive,DiskSize,DiskFree,NumNics"
End If



if err Then
  if err.number = 462 Then
    Wscript.Echo "Error: Could not find a machine named " & strComputer
	oLogOutput.WriteLine strComputer
    Wscript.Quit 2
  else
    WScript.Echo "Error: " & err.number & " - " & err.description
    Wscript.Quit 3
  end if    
end if


' Get General information
Set colItems = objWMIService.ExecQuery( _
    "SELECT * FROM Win32_ComputerSystem",,48) 

	For Each objItem in colItems

		logMsg = _
			objItem.Name & "," & _
			Cint ( ( objItem.TotalPhysicalMemory + 1023 ) / 1073741824 ) & "," & _
			objItem.Manufacturer & "," & _
			objItem.Model & ","
			
		strMsg = strMsg & "Name: " & objItem.Name & vbCrLf _
				& "TotalPhysicalMemory: " & Cint ( ( objItem.TotalPhysicalMemory + 1023 ) / 1073741824 ) & " GB" & vbCrLf _
				& "Manufacturer: " & objItem.Manufacturer & vbCrLf _
				& "Model: " & objItem.Model & vbCrLf _

	Next

' Get Processor information	
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Processor",,48)
	For Each objItem in colItems 

		logMsg = logMsg & _
		objItem.NumberOfCores & "," & _
		objItem.MaxClockSpeed & ","
		
		strMsg = strMsg _
			   & "Number of Cores     : " & objItem.NumberOfCores          & vbCrLf _
			   & "Maximum Clock Speed : " & Int ( ( objItem.MaxClockSpeed ) / 1000) & " Ghz" & vbCrLf & vbCrLf										

	Next

' Get Disk information
Set colItems = objWMIService.ExecQuery( "Select * from Win32_LogicalDisk where DriveType=3",,48)

	For Each objItem in colItems

		
		logMsg = logMsg & _
				objItem.Name & "," & _
				Int( ( objItem.Size + 536870912 ) / 1073741824 ) & "," & _
				Int( ( objItem.FreeSpace + 536870912 ) / 1073741824 ) & ","
		strMsg = strMsg _
				& "Drive: " & objItem.Name & vbCrLf _
				& "    Size: " & Int( ( objItem.Size + 536870912 ) / 1073741824 ) & " GB" & vbCrLf _
				& "    Free: " & Int( ( objItem.FreeSpace + 536870912 ) / 1073741824 ) & " GB" & vbCrLf _
				& "    % Free: " & Int( 100 * ( objItem.FreeSpace + 536870912 ) / objItem.Size ) & vbCrLf & vbCrLf

	Next

' Get Network Adapter information	
Set colItems = objWMIService.ExecQuery( "Select * from Win32_NetworkAdapter where NetConnectionStatus=2",,48)
	For Each objItem in colItems
		num = num +1

	next


	
strMsg = strMsg & "Number of Active Nics: " & num & vbCrLf & vbCrLf & vbCrLf
logMsg = logMsg & num

WScript.Echo strMsg
oLogOutput.WriteLine logMsg
oMsgOutput.WriteLine strMsg
oLogOutput.Close
oMsgOutput.Close
next
wscript.quit (0)

Sprawl
Nov 21, 2005


I'm a huge retarded sperglord who can't spell, but Starfleet Dental would still take me and I love them for it!
It sounds like it might be a single machine causing the issue? Why not try each machine 1 at a time.

Zhentar
Sep 28, 2003

Brilliant Master Genius

Sedro posted:

Sure, but you'll need to at least have a type param for the item. .NET generics don't use type erasure. Here are a few things you can do, depending on what you want to accomplish. What do you want to accomplish?

That's about what I figured, thanks.

What I'm trying to accomplish is getting stronger typing with a collection class, while hopefully minimizing changes to my existing code and code duplication, and learning more about effectively using generics in the process.

Ashex
Jun 25, 2007

These pipes are cleeeean!!!

Sprawl posted:

It sounds like it might be a single machine causing the issue? Why not try each machine 1 at a time.

That's what is stupidly annoying, I ran it one machine at a time and it didn't freak out, but when I use the list it throws the error.

Say I have a text file with the following:

MachineA
MachineB
MachineC


I run it against that file and it spits out the information for MachineA just fine, but as soon as it gets to MachineB it breaks. So I go ahead and run it against just MachineB and it spits out the information just fine!

ninjeff
Jan 19, 2004

rolleyes posted:

edit:
I've pretty much answered my own question by trying this, and the short version is that the above is correct. The only thing I'm unsure of is Show() vs. ShowDialog(). Does it even matter when it's the first form to be shown?

Glad you got it working! :)

I suppose you'd use Show() if you wanted to show several windows at once or perform some other logic immediately after showing the first window, and ShowDialog() if you wanted to add some logic that would run after the first form closed. Note also that you could achieve both of these things in other ways if you wanted to.

If Application_Startup's only responsibility is to display the form, though, then yeah there should be no difference.

Zhentar
Sep 28, 2003

Brilliant Master Genius

Zhentar posted:

What I'm trying to accomplish is...

After poking around at it a bit more, I can actually explain the main problem I'm having.

I've got this:
code:
public class BaseClass
public class SubClass : BaseClass

public Container<SubClass> SomeFunctionOrOther()
And I need to be able to do both of these:
code:
Container<BaseClass> base = SomeFunctionOrOther();
Container<SubClass> sub = SomeFunctionOrOther();
The output of SomeFunctionOrOther must be stored as a object that inherits from a particular concrete class, so I can't use an interface with covariance.

Making it public Container<T> SomeFunctionOrOther<T>() sucks, in part because it can't infer the type so I'd have to add in the right type to hundreds of lines of code, and in part because generic constraints won't let me specify that T must be castable from SubClass. I'm also concerned that the complexity of my actual code may mean that I end up with a long list of types for some functions.

Sedro
Dec 31, 2008

Zhentar posted:

Making it public Container<T> SomeFunctionOrOther<T>() sucks, in part because it can't infer the type so I'd have to add in the right type to hundreds of lines of code...
That depends where SomeFunctionOrOther is defined. If you define it in a generic class, you could infer the type param from a constructor instead.
code:
public class Whatever<T>
    where T : BaseClass
{
    public Whatever(); // you'll have to specify the type param but only at construction
    public Whatever(T obj); // constructors can't infer type params from arguments
    public static Whatever<T> Create(T obj); // but static methods can
    public Container<T> SomeFunctionOrOther(); // non-generic function; doesn't need T specified
}

Zhentar posted:

...and in part because generic constraints won't let me specify that T must be castable from SubClass.
So a call to SomeFunctionOrOther<SubClass> can return a Container<SubClass>, Container<BaseClass> or Container<object>? That would be contravariance, and its possibility depends on what Container does.

Zhentar
Sep 28, 2003

Brilliant Master Genius

Sedro posted:

So a call to SomeFunctionOrOther<SubClass> can return a Container<SubClass>, Container<BaseClass> or Container<object>? That would be contravariance, and its possibility depends on what Container does.

I mean something like this:
code:
public class A
{
  public Container<BaseClass> base { get; set;}
}

public class B
{
  public Container<SubClass> sub { get; set; }
}

public Container<T> ContainerFullOfSubClass<T>()
{
  Container<T> retval = new Container<T>();
  retval.Add(new SubClass());
  return retval;
}

static void Main()
{
  A a = new A(); B b = new B();
  a.base = ContainerFullOfSubClass<BaseClass>();
  b.sub = ContainerFullOfSubClass<SubClass>();
}
But after thinking about it more, I'm starting to feel that it wouldn't actually be too much trouble to restructure things to allow using an interface and getting covariance.

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:

Zhentar posted:

I mean something like this:


You'd have to remove this line to make it work, you can't mix generics and non-generic types that way:

code:
retval.Add(new SubClass());
And no amount of where constraints will get it to work, since the only way to guarantee that Container<T> will be able to take a SubClass is if SubClass (or a base class of SubClass) is T . So you'd be using Container<SubClass> or Container<BaseClass> instead, in which case you no longer have any generic arguments.

Dietrich
Sep 11, 2001

I don't have vs2010 in front of me, but try this.

code:
public Container<T> ContainerFullOfSubClass<T>(Function<T> factory)
{
  Container<T> retval = new Container<T>();
  retval.Add(factory.Invoke());
  return retval;
}

static void Main()
{
  A a = new A(); B b = new B();
  a.base = ContainerFullOfSubClass(() => new BaseClass());
  b.sub = ContainerFullOfSubClass(() => new SubClass());
}

Zhentar
Sep 28, 2003

Brilliant Master Genius

dwazegek posted:

And no amount of where constraints will get it to work, since the only way to guarantee that Container<T> will be able to take a SubClass is if SubClass (or a base class of SubClass) is T .

Yeah, that was my point. That is an actual functional requirement of my code anyway; I just can't express that with constraints.

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?
Me and my text file pattern finding are back again.

Mostly done, but one particular pattern is trickier. These files have tags which denote the starts and ends of named regions. Within those regions are references to labels. I need to check that, for each label reference within a region, the label it refers to is also within that region and if it isn't write this out to the output file as an error. Just to make matters more fun these files support both line comments (//) and block comments (/* */) and both labels and references inside comments are to be ignored. I'm starting to get the impression I'm building a script interpreter here...

Anyway, to avoid multiple passes over each file to sort this all out, my plan goes something like:
  • Create a struct which represents a line item. Have fields for the line number, the column number and the item name.
  • Create another struct which represents a block item. Have fields for the start line number, start column number, end line number, end column number and the item name.
  • Create lists and/or dictionaries of these structs representing labels, label references, line comments, block comments and regions.
  • Make a single pass over the file, populating these lists/dictionaries.
  • Close the file and process the data.

Apart from using more memory, am I missing any serious downsides to this approach? Although I haven't done any profiling I'm assuming it'll be quicker as most of the work is done in memory rather than by spooling backwards and forwards over a file like searching a backup tape.

Che Delilas
Nov 23, 2009
FREE TIBET WEED

rolleyes posted:

Me and my text file pattern finding are back again.

I'm pretty sure it's preferable to use a bit of system memory rather than reading back and forth in a file, so I think you're on the right track.

Is there some other reason you need to know the positional information (column, line number)? If not, you could just do your checking incrementally as you read a block, kind of like this (I'm assuming that "labels" can be anywhere either before or after "label references"):

code:

//Pseudocode
open file
while not eof, get line
{
    Read until start of region
    while not end of region, get line
    {
        (if comment block, get line until end of comment block)
        If we see a label, add it to "Labels" HashSet
        If we see a label reference, add it to "References" HashSet
    }

    for each item in References 
        try and find a match in Labels
        print error message as necessary

    clear both HashSets for next region
    
}
Close File
With this approach you're still only making one pass over the file (you just pause in the middle a lot), and you don't have to store extraneous information like line number since you're always working within the confines of a single region. Again, I'm assuming you only really care about the labels and label references in this problem.

HashSet is a data structure that only allows unique items. Available in .Net Framework 3.5 and up.

Che Delilas fucked around with this message at 22:19 on Sep 20, 2011

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?

Che Delilas posted:

Stuff

Thanks, that's an approach I should really have considered. HashSet is new to me too so that's very handy.

Positional information is required as I need to spit any errors I find out to a file, e.g.:
pre:
Results for someFile.txt:
-------------------------

Label "someLabel" referred to at line 6 column 10 in region "someRegion" is not defined in this region.

...etc
The general idea is that this is a time-saving tool to catch formatting errors which are currently handled by waiting for something to break and then complaining to whoever produced the file until they fix it, so I'm trying to make the output as helpful as I can.

edit:
To put this in context, a region can be somewhere in the region (:v:) of 6,000 lines long so positional information saves a lot of time otherwise wasted hunting around masses of text.

rolleyes fucked around with this message at 22:34 on Sep 20, 2011

Che Delilas
Nov 23, 2009
FREE TIBET WEED

rolleyes posted:

Thanks, that's an approach I should really have considered.

The general idea is that this is a time-saving tool to catch formatting errors which are currently handled by waiting for something to break and then complaining to whoever produced the file that it's broken, so I'm trying to make the output as helpful as I can.

Ah yeah. Then I would suggest using a HashSet for labels (because you only need to know THAT they exist somewhere in the block, unless you want the program to warn about duplicate labels too :v:) and a List of structs for your label references, where the struct contains all the info you need like line and column number. So in pseudo:

code:
foreach Struct item in ReferenceList {
 if (!LabelHashSet.Contains(item.LabelName)) { write error message }
}
You can store the current region name in a local variable so it doesn't pollute the struct.

vvv Welcome.

Che Delilas fucked around with this message at 23:02 on Sep 20, 2011

rolleyes
Nov 16, 2006

Sometimes you have to roll the hard... two?
Yep that ought to work, and storing the positional information in the structs should let me use your incremental approach because I can then pull it back out in the foreach at the end of the region.

Thanks again.

Adbot
ADBOT LOVES YOU

Rahu
Feb 14, 2009


let me just check my figures real quick here
Grimey Drawer
Really easy question because I can't figure out what to type into the google.

I'm learning winforms and making a very simple program to try out various stuff, and I'm trying to add a small options screen with some configuration info in it.

What I want to do is make it impossible for the main window to have focus as long as the options window is up, as many programs do. I'm sure there's some simple way to accomplish this but I can't seem to find it.

  • Locked thread