Jump to content

Gui for command line help!


Recommended Posts

Just caught the edit!

Wow, that's both complex and simple at the same time. A very clever way to handle the requirements.

Ok, so now I understand the textbox part fairly well.

I have to admit, when you first said I wouldn't get an example at first and pointed me to the references, my eyes glazed over and I went "Ohh geez!"

But this isn't very bad at all and it's a bit fun. :)

So in order for me to clear the window and add new things, my gut tells me I'll be making a Form2?

*Edit* You respond too fast!

You mean, popup another window (form) with these on it? I'm not totally sure I followed.

No, as in the new window replaces the old one. Like a web page, the first window is Index, and clicking on a link goes to the next page in the same window, clicking Home returns to the front page. I want my "Cancel" button to take me back to the first window.

Edited by Chocobits
Link to comment
Share on other sites


Yes, you would use a second form. I will let you try to figure out how to do this properly (a lot of people have a hard time with this at first) as I'm going to bed ;)

BTW, there are countless training videos and tons of great learning resources. Just have a look at this (start with Tier 1 and work your way up). There's also the guided tour. And the programming guide. And the "How Do I" video series on the VB Developer Center. And that is just the tip of the iceberg. There's TONS more out there (also tons of great books out there, tons of great community sites, etc). As usual, Google is your friend.

Link to comment
Share on other sites

Muahaha! You've created a madman!

I got it figured out after an hour of googling and playing around.

My "Change Product Key" button on Form1:

Private Sub Button0_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button0.Click
Dim Form2 As New Form2()
Me.Hide()
Form2.Show()
End Sub

My "Cancel" button on Form2:

Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click
Dim form1 As New Form1()
form1.Show()
Me.Close()
End Sub

Tested, it lets me swap back and forth between forms no prob!

I ran into the problems you mentioned I would. Closing Form1 causes program to exit, regardless if another form is open... Needs Hide option. And you can't reference Form1 in Form1 for some reason? You have to use 'Me'.

So I understand the mechanics behind this, is there a more efficient way of doing this or is this clean enough?

Also, can I tweak the position and size of both forms so that the user doesn't notice the open/close effect as much?

Edited by Chocobits
Link to comment
Share on other sites

Ok, I've resolved the UAC issue by using an external manifest.

Now I have a few bugs to work out and some fine-tuning.

Bug 1: Program crashes if it can't find the file listed by Process.Start

Bug 2: The program will exit correctly if it hasn't switched forms using the method I posted earlier, but if I have switched forms, the size of the process keeps growing in memory based on # of form switches, and doesn't unload from memory upon exit. This isn't a big issue (for this instance) because this app will only be run once per machine. In the future though I'd like to learn how to avoid this kind of sloppiness.

Feature help: A little embarrassing, but I can't figure out how to add text to the inside of a form window. IE I would like to put (Format XXXXX-XXXXX-XXXXX-XXXXX-XXXXX) above the text box.

I added a background image and icon to the program, tweaked button/form position, added another button that takes the user to a Genuine Validation Required download page to test successful activation of Windows.

I adjusted the size/position of both Forms so that the open/close effect isn't as noticeable.

So all that's left is ironing out the bugs and figuring out how to add text to the inside of form windows.

Link to comment
Share on other sites

Ok, I've resolved the UAC issue by using an external manifest.

That's good news :)

My "Change Product Key" button on Form1:

Private Sub Button0_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button0.Click
Dim Form2 As New Form2()
Me.Hide()
Form2.Show()
End Sub

My "Cancel" button on Form2:

Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click
Dim form1 As New Form1()
form1.Show()
Me.Close()
End Sub

That's NOT how it works. This is where you get to take a beginner's OOP (object oriented programming) lesson. I knew this was coming next ;)

you can't reference Form1 in Form1 for some reason? You have to use 'Me'

This will also become clear once you get the basics of OOP.

Bug 2: The program will exit correctly if it hasn't switched forms using the method I posted earlier, but if I have switched forms, the size of the process keeps growing in memory based on # of form switches, and doesn't unload from memory upon exit. This isn't a big issue (for this instance) because this app will only be run once per machine. In the future though I'd like to learn how to avoid this kind of sloppiness.

Again, the problem is not understanding OOP.

So here is the [really bad] OOP lesson for beginners (including the mandatory poor car analogy):

Form1 and Form2 are what we call Classes. To make a poor analogy, you can think of a class as the concept of an object, like say, the concept of a nice car. You wouldn't use the said concept (a mere idea) to drive around, you have to use an actual object that exists, which means it had to be created at some point. An instance of the class was created, which is now what you'd call an object, which you can actually make use of.

So if you followed so far, you understand you can't actually make use of Form1 or Form2 directly, being classes. You have to create an instance of them, and use those. When the program starts, VB automatically creates an instance of Form1 for you and then shows it (it's abstracted away to make it simpler for beginners -- in C# you would see your main Form being instantiated inside "program.cs" which loads first; in VB it's hidden from you). If you wanted to change something to this form's properties (like say, the background color), you would have to change the background color of the instance (the actual object, not the class). You use the "Me" keyword to refer to its current instance. And if you try to do "Form1.BackColor = Color.Black;" it will warn you too, telling you to use "Me" instead. "Me.BackColor = Color.Black;" will work as you'd expect. This is much like you wouldn't try to do a black paint job on the concept of that nice car, but on the car that was actually created. Hopefully you're still with me :)

Now, if you want to show a 2nd form, you have to create an instance of it too e.g. "Dim someName As New Form2()". This creates an instance (creates an object you can use) which is called "someName", from the Class "Form2" (the concept, or "blueprint" of what you want to create -- "Form2" is only there to tell it what to make an instance of). Then you tell it to show that instance e.g. "someName.Show()". Mind you, that doesn't get rid of the instance of Form1. It's still there, it was not destroyed -- even if you asked it to hide it, it's still there. When you close that instance of Form2, the instance of Form1 is still running.

So the code you written creates an instance of Form2 and shows it, merely hiding the current instance of Form1. Then once you close Form2, instead of Showing the already instantiated Form1, you're creating *another* instance of it, and showing that -- every time you close an instance of Form2, it creates a new instance of Form1 and shows that. That's a bit like using your car (Form1 being a car), and then once you have to move something heavy you use your truck (an instance of Form2), but once you're done with the truck, instead of going back to using your car, you get another one (a new instance of a car). Eventually you end up with a bunch of cars and a lot of debt (heavy resource usage, as many instances of Form1 are created and running at the same time).

Most people can't afford using resources like this, and the logical thing to do is to just reuse the existing car. Similarly, the logical thing to do would be just showing the already existing instance of Form1. There's really easy way to do this too:

In Form1's code, you write code that will create an instance of the Form2 class, hides the instance of Form1 as usual, and shows that instance of Form2. However, you want it to show that instance of Form1 again once you're done with that instance of Form2. The easiest thing to do is using ".ShowDialog()" instead of ".Show()". That will show the instance of Form2 and *wait* there. The following lines of code will only be executed once you close that instance of Form2 (just let it close for real -- DON'T create another instance of Form1). So it would be really easy to just add "Me.Show()" underneath that, thus showing that same Form1 instance again.

So in Form1's code, you'd have:


Dim someName As New Form2()
Me.Hide()
someName.ShowDialog()
Me.Show()

That solves your problem (no code necessary in Form2)

There are several other ways though, like passing a reference of the instance of Form1 (reference to that object) to that Form2 instance (to its constructor), which would store it, and would call this object's .Show() method when closing, revealing it.

In Form2's code, you'd store that reference to Form1's instance in a global variable, like this (right below "Public Class Form2"): "Private parentForm As Form".

Then you'd declare your own constructor with the arguments you want -- like one to pass along that reference to Form1's instance:


Public Sub New(ByVal refToForm1sInstance As Object)
InitializeComponent()
parentForm = refToForm1sInstance
End Sub

Now, when you create that instance of Form2, you have to pass that instance ("Me") to it, like such:


Dim someName As New Form2(Me)
Me.Hide()
someName.Show()

which will show that instance of Form2 and hide the instance of Form1.

And to show that instance of Form1 again when the instance of Form2 closes, you'd do "parentForm.Show()" in the Form2_FormClosing event.

This works too, but it's a wee bit more complicated. So it's probably simpler for you to just do Me.Hide(), form2InstanceNameHere.ShowDialog(), Me.Show() instead (works fine too, same end result).

Hopefully that wasn't too hard to follow... I could make a better explanation but that would be fairly long.

I can't figure out how to add text to the inside of a form window. IE I would like to put (Format XXXXX-XXXXX-XXXXX-XXXXX-XXXXX) above the text box

Use a label control. It's there exactly for this kind of stuff.

Bug 1: Program crashes if it can't find the file listed by Process.Start

When you have code that is susceptible of failing, you wrap it inside a try/catch block. In VB, you would do:


Try
Process.Start("filethatdoesntexist.exe") 'oops
Catch ex As System.Exception
'do whatever you want with it here, like popup a simple error message:
MessageBox.Show(ex.Message, "Oh Noes!", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

That "Catch ex As System.Exception" will basically catch *any* type of exception as it's the most generic exception type. You can have more than one catch in there too, placing the more "specialized" types of exceptions first, finishing with the most general type.

Trying Process.Start on a non-existing executable will actually generate a "System.ComponentModel.Win32Exception" exception type. More generic than that, you would have System.Runtime.InteropServices.ExternalException. More generic than that, you would have System.SystemException, and finally the most generic one is System.Exception.

Using try/catch blocks is good practice. Handling errors is good, but it's even better to prevent them. You could easily check if the executable file exists when the form loads. If it doesn't exist, then you can disable the button or something like that. Or the code that is called when you click the button could verify if the executable exists first; if it's there simply run it (still using a try/catch block), otherwise give an error message. You do have to think about all these small things and come up with such solutions. Just like you wanted to validate the serial number before calling slmgr.vbs

Hopefully that helps :)

Link to comment
Share on other sites

Wow very detailed response. I had a feeling there was a bit more depth to switching forms. Thanks for the info, I will make some updates and see what happens!

I'm running into another problem now:

The program compiled with VB.net requires... .Net runtimes to be installed on the machine it's run from..

This is awfully cumbersome for an app that runs as one of the final steps of an unattended Windows setup.. It'd mean I have to slipstream .Net or use some awkward process to integrate that before the app runs..

And then there's also the issues of customer expectations. Some simply don't WANT the runtimes installed or would have chosen not to have them installed given the choice. We have to be very careful when doing a

system wipe/OS restore on a customer's machine; we can't assume it is safe to remove anything that was on their machine that they haven't expressly told us to (excluding installed apps of course), and we DEFINITELY can't be adding software that they haven't told us to. Is there a workaround for this?

*Edit* I have had some success with VMWare's ThinStall program for avoiding the issue of installing certain apps necessary for other apps to work. If worst comes to worst I could try to create a thinstalled version of my app that includes a virtualized .net environment.. But I'm hoping there's an easier way :)

Edited by Chocobits
Link to comment
Share on other sites

The program compiled with VB.net requires... .Net runtimes to be installed on the machine it's run from

The .NET Framework 3.5 is already included in Win7 (which is what I believe you wanted to activate). If you also want to activate Vista, then that still has the .NET Framework 3.0 included. On XP or earlier there's no version already installed, but it's not like you're going to activate that with slmgr.vbs either.

Everything you've used will easily work using the plain old .NET Framework 2.0 or later. You can select which one you're targeting when you create a new project, but you can also do it for existing projects. For VB, go to the project menu, select YourProjectName's properties, then the compile tab, and the advanced compile options button at the bottom. The targeted version of the .NET framework is at the bottom there.

Link to comment
Share on other sites

Ahh, thanks for the explanation. I knew W7 would work, but I was worried if Vista would.

Ok, I'm going to clean up the app with the suggestions above and see if it's in a state I'd trust to use 'in the field' per se. :)

*Edit*

Forgot to mention earlier:

When I made my manifest, I created it as blank code inside my project and named it App.Manifest. When I compiled, it generated the correct name, matching the executable, but added a lot of extraneous lines that made it not work. Manually editing these lines out fixed it. Any reason the manifest is compiling funny?

Edited by Chocobits
Link to comment
Share on other sites

Here's the update:

The (simple) suggestion you gave didn't quite work :(

Form1 "Change Product Key" button:

Private Sub Button0_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button0.Click
Dim frm2 As New Form2()
Me.Hide()
frm2.Show()
Me.Show()
End Sub

Unless I remove the Me.Show() line, it doesn't hide Form1. If I remove the line, the program has the same memory/closing problem. If I'm ok with Form1 not being hidden (the forms are the same size and pop up in the same place so it's not a huge deal here) then it works. I need moar learning on this part lol. :)

As for the other functionality: Superb! It does exactly what it's supposed to!

Tested the product key replacement in a VM with a list of "bad keys" (blacklisted), key will change. Of course it fails Activation with these keys. Once I change to a Genuine key, Activation goes through without a hitch.

There are 2 annoyances though:

1. The scripting seems to take an exorbitant amount of time (40-80 seconds) both to change the product key and to attempt activation.

2. The Activation actually shows TWO dialogue boxes total: One that says "Activating Windows...." that needs an "OK" press to go away, and another that gives the final status "failed" or "successfully" that only goes away with an OK click.

Now, the 2nd message is important and I want that displayed. The first message is just annoying and unnecessary. Is there any way I can improve the speed here and destroy that first message?

*Edit* Added another 1.5gigs of ram to my VM, that doubled the speed of the Activation. It's still a bit sluggish but bearable.

Edited by Chocobits
Link to comment
Share on other sites

The (simple) suggestion you gave didn't quite work :(

Because you missed the .ShowDialog() part ;)

1. The scripting seems to take an exorbitant amount of time (40-80 seconds) both to change the product key and to attempt activation.

slmgr.vbs takes forever to do this. Not much you can do about it. The VB app isn't really making any difference.

Now, the 2nd message is important and I want that displayed. The first message is just annoying and unnecessary. Is there any way I can improve the speed here and destroy that first message?

If you don't like the functionality provided by slmgr.vbs, then it might be better not to use it.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...