Visual Basic .NET Nightmare or Guide to upgrading a Guru

Part Deux

Page 4

Let’s not start with the Basics

BTDT (Been there, done that). So we’ll cut in a bit to where we’ve already been and expand our horizons. That old hyper LinkLabel is still inept. That’s right no AutoEnable function there, yet.

So why wait for someone else to do it when you well know that, if you want to get something done, you should do it yourself! I’m going to open up my hyper link project. Run it, okay it still works.  This go round I’m going to give up code snippets in easy to copy text boxes.

Trick 2: Okay so it’s not much to look at to start.  What we want to end up with is a linklabel as part of our control.  Go into code view and change the line for inheritance to this:

Inherits System.Windows.Forms.LinkLabel

Instead of this:

Inherits System.Windows.Forms.UserControl

Imports System

Imports System.Drawing

Imports System.Windows.Forms

Imports System.ComponentModel

Namespace MyStuff.controls

End Namespace

Public Shared Sub main()

 

End Sub

#Region "Internal Events"

Now click the left drop down and select LinkContol events. Then, looking back at Hyperlink project shows me this, click the linkclicked event. Drag it into our region. Then go ahead and collapse that and add a Properties region under it. Then type this line and hit enter.

Property AutoEnabled() As Boolean

Okay the property structure is now set. We need our Internal field variable, let’s set a new region above our Events region and label that Internal Variables.

Now add this variable

Private IsAutoEnabled As Boolean

Ok for me the name convention is simple. “Is” means it’s Boolean and the rest tells me what property it’s associated with. So we need to program our set and get. Up to this point everything below form designer code should look like this.

 At this point you should be able to compile without errors. Now we need a Hyperlink Property. Where is this link going to go? Remember that we can go anywhere with our ProcessStart component, but I get ahead here. Let’s get that property in first.

Property AutoHyperLink() As String

Now set its variable and code the property. Using the same steps and the str naming convention. Your variable should look like this.

Private strAutoHyperlink As String

Cool now to make it work off both properties in the click event. Here’s one line of code to handle getting out of the click.

If Me.strAutoHyperlink = "" Or Me.IsAutoEnabled = False Then Exit Sub

Next we need to get our process enabled. Looking back at the old hyperlink project we see the drag and drop process control on our form designer window. Let’s do the same in our designer window for our control. Drag and drop and rename it to LinkControlProcess, got it? Good. Now write one more line of code.

Me.LinkControlProcess.Start(Me.strAutoHyperlink)

So is it ready? Yes and no. Let’s lean towards yes to see what it can’t do. Run build against this project. Any errors? Not on my end, so what do we do next to use this simplified linklabel LinkControl? Well we need to work off a form, so let’s add a test form to this project. Name it TestForm, why not? We do not intent to keep it forever, do we?

If you look in your tool box for drag and drop controls, you’re not going to see the LinkControl, yet. With the windows form up, go to the tool box so that all the windows controls are visible, now right click anywhere on it. Click Add/Remove. This will bring up the customize toolbox. Lots of stuff not checked here.  Click browse and go to the BIN area of your project. Select the exe of your project. The control should add and you’ll get the default cog icon for your control. It will most likely be at the bottom of your windows form controls. Now draw it on to your form. If everything went right, you should have the linklabel control on your form with the name of LinkControl1, barring typos of course.

Now check its properties. It should have both of our auto properties. Go ahead and give it a try.  Set the solution to start with this project and then the project start up to TestForm. Put your favorite website in the AutoHyperLink property, set AutoEnable to true and run it. If it doesn’t work at this point, debug your code and see where you went wrong. If that doesn’t work, typos are evil, then copy the whole shebang so far from here.

 

 And try again.

Issue2: While in the middle of this project/lesson I installed Mozilla Suite. Ver. 1.7.5.  And I did not set it to the default browser. However, it’s keyed itself into the system in a particular way as to break I.E’s ability to receive a link from the system and have it work. With Mozilla running, it receives all links. When it’s not, I.E. starts(sometimes), but the links are not received. This of’course was causing a problem all the way back to our project and sending back an error.

Resolution: If everything was cool, you could just launch IE with the prompt to make sure "I’m the default browser" is selected and reset it. But This version of IE doesn’t do that so much anymore.

External Test: Launching a website from a run command line. This should be comparable to our Start Process code.

So we have a Reg hack (Remember to always backup your Reg files when making changes, even if I don’t )

New Key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\User Agent

Value Added: Mozilla/4.0 (compatible; MSIE 6.0; Win32)

That caused I.E. to prompt me. And now we are back in business.

Resolution 2:  Or you could just set program access and defaults back to I.E, which seemed way easier once I found that.

Okay our AutoEnabled feature is still pretty weak. We need to have it do some more. So we are going to start by setting up a functions region, then put in a public function for all its capabilities. Our functions will be available to the form it lands on so we will not label them as internal.

Put it right under the events region. Now for our function:

Using the optional argument we can pass a link directly to the function from our program using the control if we want to. So let’s give it a variable to copy to if something gets passed.

Now let’s move some code from the link event. Our process start.

Change a variable link to the one the function is using. Then change our conditional if AutoEnabled to call our function.

Add in some conditional code to switch between our optional link for the function or the autolink, if nothing then exit and send back a false reading for the call. And this line was missing:

Your function should look like so:

 

 Now we have some stuff going on in here. But we also want to override the autotext feature for the text value if the end user hasn’t already altered it by identifying the LinkControl name in the text property and changing it to the link text when it’s been changed. This takes us back to our property set code by adding this line.

This fires when focus leaves the property setting. So if a person types in a link and tabs out, hits enter, or click elsewhere it changes the text property.

All is well as long as the end user doesn’t type in a link that’s just not going to go anywhere. In which case our program, or just our control, will fail and throw an error. Oddly as I thought about writing this I referred to the help file and saw some very similar statements to which I was thinking, so to save some typing you can read the intro here. Other than that I’d say the same, it’s time to graduate from on error to something more viable, something more specific, so as I grasp it, you might, too. Our new words are Try and Catch, for our code we want this wrapped around our start process, because this is where the bad link will cause us problems.

We also want to utilize the exception object which will be created when an error occurs. Since we are coding a control which shouldn’t throw out information to the end user, we want to create a new property setting that the program can resource. We also want our Property to be specific to the error. So we’ll call it LinkFailure.

ReadOnly Property LinkFailure() As String

There is no point in allowing this to be set so we’ll make it read only. We’ll set our internal field variable as:

Private strLinkFailreError As String

Then once we’ve got that we want to wrap our start process code in a try catch structure. Then we’ll return false from our function and set the error message in our property.

Here’s our whole function.

        Public Function AutoLink(Optional ByVal LinkOveride As String = "None") As Boolean

            Dim MyLink As String

            MyLink = Me.strAutoHyperlink

            If LinkOveride <> "None" Then MyLink = LinkOveride

            If MyLink <> "" Then

                Try

                    Me.LinkControlProcess.Start(MyLink)

                    Me.LinkVisited = True

                    Return True

                Catch e As Exception

                    Me.strLinkFailreError = e.Message()

                    Return False

                End Try

            Else

                    Return False

            End If

        End Function

This will prevent your code from failing within the container program and should pass enough info for the program to handle it, such as resetting the AutoHyperLink property to something viable. To see it work let’s capture the click event within our form and msgbox the error message on a bad link. Add this to your form code and put a bad link in the AutoHyperLink property

    Private Sub LinkControl1_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkControl1.LinkClicked

        If Me.LinkControl1.LinkFailure <> "" Then MsgBox(Me.LinkControl1.LinkFailure)

    End Sub

Well now let’s try our built in link function. Works the same as Start Process, but with built in error handling that doesn’t kill your program. Add a button and toss this single line of code in your form. Mess with the URL to see what happens when you experience link failure.

If Me.LinkControl1.AutoLink("www.newsweek.com") = False Then MsgBox("OOOps")

Cool we got a good thing started, but before we advance, we need to do a little window dressing, otherwise our custom control just looks, well, sad.  The next thing to do is give the properties appearing in the properties toolbox some descriptions.  This isn’t too hard; I’m recalling something hard in VB 6 that had to be done, to ‘get her done’. All we need to do is add an attribute to each property. Let’s start with our error, because it makes no since just looking at it.  Our property just needs this in front of it.

<Description("Read Only error message on link failure.")> _

Got it? The underscore allows it to be on its own line while still attaching it to the property function. Altogether you should have this.

<Description("Read Only error message on link failure.")> _

        ReadOnly Property LinkFailure() As String

            Get

                Return Me.strLinkFailreError

            End Get

        End Property

Then do the same for the other two and you should have them all like so:

 Yes? Okay, the curtains are done, now for the sham. We need an icon. Now you may wish to invent your own or borrow one from the millions in existence. Me, I just splashed some colors into an icon file. Add a new item, select icon file and it should take you right into an icon designer window. Splash a little color on it and save & close. Now we can add the icon to the whole project and see what happens.

Now just like the curtains, we need to dress it with an attribute. We are going to place our attribute right before our class begins, but below the name space and before the class declaration.

    <System.Drawing.ToolboxBitmap("Icon1.ico")> _

Not there? Well, you may have to remove and re add the control from the executable to get your icon piped through. Alright got that working? All dressed up?

Now it’s time to move forward with the power of this control. First remove the test form, see how appropriately named it was? Now change your project start up back to sub main. Change your solution start up to hyperlink project.

Now go back to the Hyperlink project which should still be in this solution. Open the form. And try and draw your nifty control onto it. Nice error message hen?

 

 Issue3: I almost see the point not being able to resource a control from an exe that it doesn’t belong to, the real problem here is, if you’re not privileged to have the whole studio at your finger tips, is; that Standard VB will not compile to a DLL file, at least not from the IDE. I really have to wonder what Microsoft thinks of us? Are we too stupid to be able to make DLLs? Are C programmers the premier and we are just the Red headed step children of Microsoft’s programming suite? Whatever the reason it’s a serious pain in the ass to be continually left out. Going back to Visual Basic 6 Learning edition versus Visual Basic 5 Control Creation Edition, here we have two in reverse. You could not make an exe with 5, but you could make an OCX, and you couldn’t make an OCX with VB 6 LE. Granted 5 was free, but hells bells, I bought VB 6 to be able to do both, make exe and OCX. Now the OCXes are gone, controls are resourced from a simple DLL file. And since getting VS 6 and playing with the big toys (Only way to get the Winsock control, what a rip that was, too. So many crappy Winsock controls out there to try and they all sucked!)

So here we are again, red headed and wanting. Does Microsoft just want all our money just to get something done or what?

Resolutions: Yes, it’s plural. For those who cannot just change their output to DLL and move along, here’s our first fix to this Nightmare’s continuing reoccurrence.

            Solution One as Follows: What comes with the Dot Net SDK is the compiler behind the IDE, which doesn’t have such restrictions that the IDE has as stand alone VB. Now for me, this was a major misstep, because I never had to compile anything before VB 6. And then it was hardly even noticeable to realize what I was doing. But I’d been in C++ before and I took an ANSI C programming class, ages ago. So it can’t be that hard, right? Right? Right?

The first thing to do is locate this file, for me, I just moved it to the top of my Projects folder making it easy to find; vbc.exe (Under VB 7.1, it is located under dot net in your windows directory, nicely hidden away, hidden, hee, right)

At this time I’m going to give it its own folder along side its companion RegAsm.exe. Learning how to use these things took some time for me. So lucky for you if you’re completely unfamiliar, just follow step by step.

Step 1: Add a text file to your project. Name it compile.txt. It should open right up. Next it’s going to bear a distinct resemblance to this where your directory is to your source files on your computer.

  "/t:Library"

"/out: D:\My Projects\Lessons\Hyper Master\MyStuff.Controls.Dll"

"/r:System.dll,System.Windows.Forms.Dll,System.Drawing.Dll"

"/res:D:\My Projects\Lessons\Hyper Master\Icon1.ico"

"D:\My Projects\Lessons\Hyper Master\LinkControl.vb"

"D:\My Projects\Lessons\Hyper Master\AssemblyInfo.vb"

Step 2: Next we want to edit the Assembly Info file. Fill in the attributes. Like so:

<Assembly: AssemblyTitle("Hyper Master")>

<Assembly: AssemblyDescription("Link Control")>

<Assembly: AssemblyCompany("My Company")>

<Assembly: AssemblyProduct("Link Control")>

<Assembly: AssemblyCopyright("2005")>

<Assembly: AssemblyTrademark("")>

<Assembly: CLSCompliant(True)>

Easy enough. Now for the fun stuff. With the way I’ve been doing this I create a shortcut in each project folder to launch the compiler using the compile file. So after you’ve located the appropriate vbc.exe file, create a short cut to it, then edit. Your command line should look something like this.  

"D:\My Projects\My DLLs\vbc.exe" "@D:\My Projects\Lessons\Hyper Master\compile.txt"

 Then add the start up location to where the vbc.exe file is, note this is where your output will land unless otherwise specified in your compile file.

 "D:\My Projects\My DLLs"

 Okay so what are we doing here? Basically we are going to compile the old fashion way, with a line by line request to the compiler stored in a file. The first command tells it to make a library a.k.a. DLL. Walla, DLLs for the stand alone VBer. Next we tell it what files to compile and we are adding our icon as a resource within our DLL.

Step3: Okay you can do this the quick way or the thorough way. The quick way is just run the shortcut icon you created. The compiler works fast so you may not see anything but a flash. If all went well, you’ll have a dll file, if not its generated errors you didn’t see. The other way is to open a command window (Aka the DOS derivative, consol window, etc, etc.) Now just drag and drop your shortcut into it and hit enter, this way you don’t lose the window and scroll through any errors generated.

Step 4: Now add your control DLL file to your toolbox and you should be able to drag and drop it on a form in a new project. Or not. Did we get an error with the name of the control’s icon? Yep, still working my way through this issue. For now copy your icon file to the DLL folder so that it can read the file. (Yea I know, why is it embedded then? Eventually we’ll get to that, too.)

Step 5: Adding your DLL to the general assembly collection, so that it’s always in the list of control you can add to your toolbox. Either via a shortcut, or within the cmd window, send this line:

 "D:\My Projects\My DLLs\RegAsm.exe" "MyStuff.Controls.Dll"

 Of’ course you want to use a folder path that applies to your computer. Success with this varies. It seems easier just to browse to your DLL, but more may come up about it’s availability in your general assemblies later. Maybe a section called Dot Net Secrets.

             Solution Two: Will most likely be our next project lesson.

 Well as a reusable control for easy linking in your project, this one isn’t too bad. It’s definitely not one to put on the market for resale, such a thing would be a gimp thing to do. Especially since there’s hardly any unique code in the control. Not using auto enabled just leaves the control as its parent, the Link Label.

 Okay here’s the whole class for easy Copy & Paste.

 

Finally getting your icon inside your DLL. I put in a webpage as a reference here. It had the easiest solution so far. Someone marked it as a bug and generated a work around. So basically I am repeating what's on that page. Add a class below your name space.

Class MyIco

End Class

Then change your sham line to this:

<System.Drawing.ToolboxBitmap(GetType(MyIco), "Icon1.ico")> _

Compile. Now you can reuse your control in all your projects. More on portability, adding a strong name and adding it to the general assembly cache later.

 

Page 5