Monday, December 29, 2008

How to Expose the Events of a Custom Control in the Parent Form

Say you have a custom control which has a PictureBox.  And you drop this control on a form.  But you want to be able to Code the MouseDown, MouseMove, MouseUp and Paint event of the PictureBox control that is on your custom control, and you want to code those events in the Form, not the control  You still with me?  You also don't want to create another control that inherits from your custom control to do this.  How can you do this?

There are actually a number of ways to do this.  Below are three ways:

1.  The easiest way to do this is to just raise an event in the Custom Control and handle that event in the Form.
      Public Event LinkClicked(ByVal sender As Object, ByVal e As EventArgs)
       Private Sub LinkLabel1_LinkClicked(ByVal sender As Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked
              RaiseEvent LinkClicked(sender, e)
       End Sub

2.  Another way is to have a PictureBox value in the form point to the PictureBox that is on the control.  And then address the Mouse events there.  You'll need a way to return the Control to you via a FindControl routine in your Custom Control

  Public Function FindControl(ByVal Name As String) As Control
    For Each c As Control In Me.Controls
      If c.Name.ToLower = Name.ToLower Then
        Return c
      End If
    Next
  End Function

Then in your Form you would do the following:

  WithEvents MyFullImage As PictureBox

And in your Form_Load event:
    MyFullImage = ImgEditor1.FindControl("FullImage") 'This is assuming the FullImage is the name of the Picturebox in your Control

And then you can do the following:
  Private Sub MyFullImage_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyFullImage.MouseDown

  End Sub


3.  Lastly you would still use the FindControl mentioned in method 2, but do the following

      'Add this to form_load
      Dim pctBox as PictureBox = MyUserControl1.FindControl("FullImage")
      AddHandler  pctBox.Click, AddressOf TestClick


      Private Sub TestClick(ByVal sender As Object, ByVal e As System.EventArgs)
              MsgBox("Testing AddHandler Method")
          End Sub









Wednesday, December 24, 2008

Referenced DLL kept getting deleted in vb.net project

I had a VB.NET project which referenced a specific DLL that came from another source (I didn't have the code just the dll file).  I added the dll to my project by browsing to the dll.  The problem occurred when I tried to rebuild the project.  All of a sudden I got a reference not found, and when I went to the directory where the dll was located it was no longer there.  The solution was simple one.  When adding the dll, in the Reference Properties window, you need to specify the "Specific Version" field to "True" instead of the default which is "False".  By doing this you don't delete the dll.


Tuesday, December 23, 2008

Passing an array of Structures with an array to unmanaged code from VB.NET

I had an array of structures and in the structure was an array.  There were a couple of issues.  The first thing was that I couldn't initialize the array while defining the structure (still haven't figured this one out yet).  The second thing was that when I passed the array to unmanaged code byref and when the unmanaged dll returned I would get an error.

What ended up fixing my problem was that in my structure was a Boolean variable.  When I changed that Boolean to Integer then all of a sudden everything worked.

I'll post code samples shortly.


Wednesday, December 10, 2008

How to access SharePoint sites through Microsoft Outlook

http://searchexchange.techtarget.com/tip/0,,sid43_gci1318679,00.html

Stop the Windows Authentication in Firefox

Whenever I have to go to the know or to timecard or to a teamsite, I get this dialog box which prompts me to enter a username and password in firefox.  I don't get this in IE.   The fix in firefox is this:

 

1. Open Firefox

2. Navigate to the url about:config

3. Locate the following preference names and put as the value the comma separated values of the address roots.

network.automatic-ntlm-auth.trusted-uris

network.negotiate-auth.delegation-uris

network.negotiate-auth.trusted-uris

Your value should look something like this: localhost,companyname.org


Create Shortcuts or Hotkeys to quickly send mail to a recipent

http://www.howtogeek.com/howto/the-geek-blog/create-shortcuts-or-hotkeys-to-quickly-send-mail-to-a-recipient/

Embed and Excel Worksheet into PowerPoint or Word 2007

http://blogs.howtogeek.com/mysticgeek/2008/11/23/embed-an-excel-worksheet-into-powerpoint-or-word-2007/

Wednesday, November 26, 2008

How to avoid auto checkout in VS 2005

From Tools->Options->Source Control (if its not shown, then check "show all settings" at the bottom of the page).  Then change "On Edit:" to "Prompt for check out"
 

Can't find Source Control unter Tools->Options in VS 2005

Apparently there is a Source Control option under Tools->Options in VS 2005 and I couldn't find it.  The soution appears to be the check box at the bottom of the Options dialog - "Show all settings".  If you check this then all the options will apear.
 
 

Thursday, November 13, 2008

How to copy files between your local computer and one connected through Remote Desktop

You can't drag and drop files, but you can copy and past files and folders.

From Microsoft (http://support.microsoft.com/kb/313292):

To view the disk drives and files for the redirected disk drive.  From your local machine.
1. Click Start, point to All Programs (or Programs), point to Accessories, point to Communications, and then click Remote Desktop Connection.  Or if you don't see the option, click Start->Run-> and type in mstsc.exe and hit enter.
2. Click Options, and then click the Local Resources tab.
3. Click Disk Drives, and then click Connect.  Or, click the More button and then check the Drives checkbox.

Wednesday, November 12, 2008

How to tell if you can run Windows Vista 64 bit

This is from the link below:
 
Confirm that your PC is capable of running 64-bit software.
1.Open the "System Properties" window
 a.If your Start menu is configured for Classic Start menu, right-click the My Computer icon on your desktop, and click Properties.
 b.If your Start menu is the Windows default Start menu, click the Start button, then right-click the My Computer icon in your Start menu, and click Properties.
2.Click the Advanced tab.
3.Click Environment Variables.
4.In the "System variables" list at the bottom of the Environment Variables window, look for a variable called "PROCESSOR_ARCHITECTURE". If your PC has a 32-bit processor, this variable will have a value of "x86". If it has a 64-bit processor this variable will have a value of "x64".

Problems on Vista 64 bit operating systems

I have an application that has some COM references and it gives problems on Windows Vista 64 bit.  Apparently the solution is to build the application to specifically target x86 machines rather than "Any CPU" and when your application will run on a 64 bit operating system, it will run as a 32 bit WoW.  More information on
 
This is from the link below, but this is how you do it:
First:
   1.Click on Tools...Options
   2.Select Projects and Solutions
   3.Check the Show advanced build configurations option and click the OK button
To compile for x86:
   1.Click on Build...Configuration Manager
   2.Click on the Platform dropdown for your project in the list and select <New...>
   3.In the Project Platform dialog select x86 from the new Platform dropdown and click OK
 
The message board item where I got the above information is below
 

What is WoW mean

WoW in the context of 32-bit WoW means Windows on Windows.  It basically means a emulating a type of windows on another windows platform.
 
More information can be found here:
 

Thursday, October 23, 2008

Interpolate an array to twice its size in VB.NET

I had an array that I wanted to "interpolate".  The simplified version is the array (one-dimensional) had the following values:

011000

Now this array is a one dimensional array that contains values for an image. For this example, the width of the image is 2 digits.  I wanted to interpolate this array so that the width of the image is 4 digits.

Initially my thought was just to do this:

001111000000

This was simple as I just looped through the original array as such:

for index = 0 to oldarray.length - 1
    newarray[index*2] = oldarray[index]
    newarray[index*2 + 1] = oldarray[index]
end for


But the problem with this is that the old image looked like this:

01
10
00

The new image looks like this:
0011
1100
0000

Which is fine, except when I realized that I interpolated ONLY the WIDTH of the array, and not the height.  What I wanted was something like this:

001100111100110000000000

0011
0011
1100
1100
0000
0000

Now for some reason I couldn't figure this out.  But the solution is actually quite simple.  You have to set 4 values for each one in the old array.  In the above example, I interpolate the width, now I just need to interpolate the height.  Below is the example.

     For index As Integer = 0 To oldarray.length - 1
        If (index > 0 AndAlso (index Mod NEWARRAYWIDTH/ 2))) = 0) Then // I know what the width of the new image will be, and the old one is half as large
          row = row + 1
        End If
        newIndex = index Mod CInt((NEWARRAYWIDTH / 2))
        nearray((row * 2) * NEWARRAYWIDTH + (newIndex * 2)) = oldarray(index)
        nearray((row * 2) * NEWARRAYWIDTH + ((newIndex * 2) + 1)) = oldarray(index)
        nearray(((row * 2) + 1) * NEWARRAYWIDTH + (newIndex * 2)) = oldarray(index)
        nearray(((row * 2) + 1) * NEWARRAYWIDTH + ((newIndex * 2) + 1)) = oldarray(index)
      Next

I installed VS 2003 after VS 2005

 I initially has VS 2003 and then installed VS 2005, no problems.  However, I had to re-install my operating system and because I had deadlines, when I got back up and running, I just installed VS 2005 because most of my work was with that.  But recently, I had a program that wouldn't convert from vs 2003 to vs 2005, so I needed to look at it in 2003.  So I went back and installed VS 2003.  Nothing really bad happened, except when I doubled on a VS 2005 solution, it tries to open it in VS 2003 and I get an error.  I have to right click on the solution and select Microsoft Visual Studio Version Selector which then opens the solution in VS 2005.  I haven't found a better solution.

Thursday, October 16, 2008

Missing MSVCR80.dll and COREDLL.DLL

I built an application in VS2005 and in dependency walker it shows that it was missing MSVCR80.dll, so I did a search on my machine and got one that was in the C:\Program Files\Microsoft Visual Studio 8\VC\cd\DLL\mipsiv\.  But in dependency walker, the MSVCR80.dll was missing another dll called COREDLL.DLL, when I searched for this file on my machine I couldn't find it.  I figured I was screwed.
 
But then I realized that I had multiple copies of MSVCR80.dll on my machine, the one in the above directory was 47 KB, there was another one in the C:\Windows\WinSxS\x80_Microsoft.VC80....... directory that was 612K, and it seemed that I had a lot of versions that were 612 KB.  When I opened this in dependency walker it didn't need th COREDLL.DLL.  So I was golden.
 

Wednesday, October 1, 2008

How to Save the Output of a Paint Routine in .NET to a Bitmap File or save the image from a picturebox to a bitmap file

Another way to say this is how to save the image from a picturebox to a bitmap file.

I have a Picture box where I load an image at design time.  At runtime, I allow the user the doodle on the image.  I would like to save this image to a bitmap file.  The way I allow the user to draw on the image is through the mousedown and mousemove event I write to an arraylist, and in the PictureBox's paint routine I draw out the contents of the arraylist.  When I try to do a Picturebox1.Image.Save, it doesn't work in that it saves the original image that I loaded at design time, not the one that I just drew on in mousedown and mousemove.  There are two ways the do this.  The harder method is below.  What it does is it creates a tempimage, then it draws to this temp image (what I am assuming here is that you've moved the code from your PictureBox1.Paint routine to a stand alone routine called PaintPictureBox1, this way you can call it from two places), and finally it returns the temp image.

Public Function CurrentPictureBox() as Bitmap

        Dim iNewWidth As Integer, iNewHeight As Integer
        iNewWidth = Int(PictureBox1.Image.Width)
        iNewHeight = Int(PictureBox1.Image.Height)

        tempImage = New Bitmap(iNewWidth, iNewHeight, System.Drawing.Imaging.PixelFormat.Format32bppRgb)        
        g = Graphics.FromImage(tempImage)      

        g.DrawImage(PictureBox1.Image, 0, 0, iNewWidth, iNewHeight)
        PaintPictureBox1(g)
    return tempImage
End Sub


The second method is simpler, in that it takes advantage of .NETs DrawToBitmap routine.

Public Function CurrentPictureBox() as Bitmap
            Dim tempImageAs New Drawing.Bitmap(PictureBox1.Image.Width, PictureBox1.Image.Height)
            PictureBox1.DrawToBitmap(tempImage, New Rectangle(0, 0, bmp.Width, bmp.Height))
            return tempImage
End Sub






Wednesday, September 24, 2008

How to get the index (GetIndex) from a ToolStripMenuItem

When we converted our application to VB.NET.  The upgrade wizard created this VB6.MenuItemArray, then using it it set the indices for all the menu items that were in it.  So when a user clicked on one of its menu items.  The .Click event was called and inside this a function called GetIndex was called and in our application we used this index to figure out what menu item was clicked.  Below is a short example of the code in our .Click event.

  Public Sub MenuBrushSize_Click(ByVal eventSender As System.Object, ByVal e As System.EventArgs) Handles MenuBrushSize.Click
    Dim Index As Short = MenuBrushSize.GetIndex(eventSender)
    Select Case Index
      Case 0
        'do something
      Case 1
        'do something
      Case 2
        'do something
      Case Else
        'do something
    End Select
  End Sub

When I moved over to 2005 and decided to use the ContextMenuStrip and subsequently the ToolStripMenuItem, I decided not to use the VB6.MenuItemArray.  But then I didn't want to have separate handler routines for each and every one of my menu items.  I wanted to have it all in one Subroutine.  But there isn't a GetIndex function for the ToolStripMenuItem.  So I had to create one, below is how I was able to do it:

  Public Function GetMenuItemIndex(ByVal sender As System.Object) As Short
    Dim oMenuItem As New System.Windows.Forms.ToolStripMenuItem
    oMenuItem = CType(sender, System.Windows.Forms.ToolStripMenuItem)
    If TypeOf oMenuItem.Owner Is ContextMenuStrip Then
      Dim parentMenu As ContextMenuStrip = oMenuItem.Owner
      For index As Integer = 0 To parentMenu.Items.Count - 1
        If oMenuItem.Name = parentMenu.Items(index).Name Then
          Return index
        End If
      Next
    ElseIf TypeOf oMenuItem.Owner Is ToolStrip Then
      Dim parentMenu As ToolStrip = oMenuItem.Owner
      For index As Integer = 0 To parentMenu.Items.Count - 1
        If oMenuItem.Name = parentMenu.Items(index).Name Then
          Return index
        End If
      Next
    End If
  End Function

This function basically checks the parent of the current menu, and gets the index of that menu item.  Basically I assume the menu item is part of some collection and I want to find out the index in the collection.

Below is how I use it.  Its pretty much the same, execept now my handles must specify all the menu items we are handling.

  Public Sub MenuBrushSize_Click(ByVal eventSender As System.Object, ByVal e As System.EventArgs) Handles _
    MenuBrushSize_0.Click, MenuBrushSize_1.Click, MenuBrushSize_2.Click, MenuBrushSize_3.Click

    Dim Index As Short = GetMenuItemIndex(eventSender)
    Select Case Index
      Case 0
        'do something
      Case 1
        'do something
      Case 2
        'do something
      Case Else
        'do something
    End Select
  End Sub


ContextMenuStrip is not modal like ContextMenu

I had an application that did something this

Menu.Show(Me.Image, e.x, e.y)
'Followed by a block of code
Block of code

The thing is my application didn't expect to execute the block of code until after the user selected the menu item.  So basically, when Menu.Show was called, we waited until the user clicked the menu item (at which point the code in the .Click) routine was called, and then we executed "Block of code"

Recently, I "updated" my application and decided to use the ContextMenuStrip for my menu.  Well, what happens now is after the Show method is called, the Block of code is executed immediately.  Which screws me up.

Haven't yet figured out a solution for this.

Wednesday, September 10, 2008

Saving global variables to an XML file

The block below is from the book Programming Microsoft Visual Basic 2005, which is an excellent book and should be on every VB Programmers shelf:

Here's a practical example of a technique that I used in several real applications. I gather all the global variables in a class named something like Globals or ProjectData that I can persist to an XML file stored on disk. To leverage the XML serialization mechanism offered by the .NET Framework, these global variables must be implemented as instance fields, but at the same time the class must be exposed as a singleton so that it can be accessed from anywhere in the application. Here's how you can build such a class:

' This code requires a reference to the System.Xml.dll assembly.

' (Classes must be public to use XML serialization.)
Public Class Globals
' This singleton instance is created when the application is created.
Private Shared m_Value As New Globals

' This static read-only property returns the singleton instance.
Public Shared ReadOnly Property Value() As Globals
Get
Return m_Value
End Get
End Property

' Load the singleton instance from file.
Public Shared Sub Load(ByVal fileName As String)
' Deserialize the content of this file into the singleton object.
Using fs As New FileStream(fileName, FileMode.Open)
Dim xser As New XmlSerializer(GetType(Globals))
m_Value = DirectCast(xser.Deserialize(fs), Globals)
End Using
End Sub

' Save the singleton instance to file.
Public Shared Sub Save(ByVal fileName As String)
' Serialize the singleton object to the file.
Using fs As New FileStream(fileName, FileMode.Create)
Dim xser As New XmlSerializer(GetType(Globals))
xser.Serialize(fs, m_Value)
End Using
End Sub

' Instance fields (the global variables)
Public UserName As String
Public Documents() As String
Public UseSimplifiedMenus As Boolean = True
Public UseSpellChecker As Boolean = True
End Class

Using the Globals class is straightforward because you must simply invoke the Load static method after the application starts and the Save static method before the application terminates. All the global variables can be accessed as properties of the Globals.Value object, as follows:

Globals.Value.UserName = "Francesco"
' Assign two items to the Documents array.
Globals.Value.Documents = New String(){"c:\doc1.txt", "c:\doc2.txt"}
' Save current global variables on disk.

Globals.Save("c:\myapp\globals.xml")

Interestingly, the very first time a given user runs the application, the XML file doesn't exist, thus the singleton Globals object will contain the default values for global variables you've defined by means of initializers.


Note 

Visual Basic 2005 comes with a very powerful mechanism for saving and retrieving user settings, which is conceptually similar to the one I illustrate in this section. You can read more about it in Chapter 16, "The My Namespace." However, the technique I just illustrated is more generic and flexible than the built-in Visual Basic mechanism is and can be used in many circumstances in which the built-in approach wouldn't work. For one, the built-in technique can store only one set of values for each user, and you can't manage multiple sets of preferences for a given user, merge current options with other users, move options to other computers, and so forth.


Wednesday, September 3, 2008

Official XML Comment Tags for .NET


The "official" XML comment tags

The following XML comment tags are officially supported in VB.NET: c,code, example, exception, include, list, para, param, paramref, permission, remarks, returns, see, seealso, summary and typeparam.

c: This tag is used to denote code, so it can be used to identify sample code associated with a particular entity within the source code. Note that the tag can only be used to represent a single line of code or to denote that some of the text on a line should be marked up as code. Example: <c>Dim MyObject As MyType</c>

code: This tag is used to denote more than one line of code, so it can be used to identify longer areas of sample code.

example: This tag may be used to describe an example of using a particular method or class. It is possible to include code samples within the example tag by making use of either the c or code tags.

exception: The exception tag allows a method's exception handling to be documented. The cref attribute allows the namespace of the exception handler to be included. Example: <exception cref="System.Exception" >Throws an exception if the customer is not found.</exception>

include: This tag allows documentation to be imported from an external XML file rather than being stored within the source code itself. As such it may be useful if the documentation is written by people other than the software developers (e.g. technical writers).

list: This tag allows bulleted or numbered lists or tables to be added to XML comments.

para: This tag indicates that the text within the tags should be formatted within a paragraph. As such it can be used to format text within other tags such as summary or returns. Example: <para>This is a paragraph</para>

param: The param tag is used to document a method's arguments. The tag's name attribute specifies the name of the argument to which the tag refers. The tag is also used by Visual Studio's Intellisense system to show a description of a method's arguments. It is also used by the Visual Studio Object Browser. Example: <param name="FileName" >The filename of the file to be loaded.</param>

paramref: This tag can be used to refer to a method's argument elsewhere within the method's XML comments. The tag's name attribute specifies the name of the argument to which the tag refers. Note that the param tag is actually used to describe the parameter. Example: Use the <paramref name="FileName"/> argument to specify which filename is loaded.

permission: The permission tag can be used to describe any special permissions a specific object needs. The object to which the permission refers is included as the cref attribute. Example: Class needs to write to the file system, ensure user has appropriate access.

summary: The summary tag describes a method or class, so it is the most important tag. As well as being used in a project's documentation, the tag is also used by Visual Studio's Intellisense system to show a description of the method or class being referenced. It is also used by the Visual Studio Object Browser.

remarks: The remarks tag can be used to supply additional information about a method or class, supplementing the details given in the summary tag. As with the summary tag, this tag is also used by Visual Studio's Intellisense system and the Visual Studio Object Browser.

returns: Describes the return value of a method. Example: <returns>True if user has permission to access the resource, otherwise False.</returns>

see: The see tag is used to reference other entities (such as classes) in the project. The see tag is intended for use within other tags such as the summary tag. Example: <seealso cref="System.Configuration"/>

seealso: The seealso tag resembles the see tag and has identical syntax, except that the text is intended to be used to create a separate seealso section for the entity's documentation.

typeparam: Typeparam is used in an identical way to param, except that it is used to document a type associated with a generic class or function.

value: Value is only used when documenting a property, and is used to describe the value assigned to that. The comment is not required for properties that are marked as read only. Example: <value>Sets the employee's salary</value>


Wednesday, July 16, 2008

How to update or refresh a Typed DataSet (xsd file) in the DataSet Designer in Visual Studio

I had this issue and had a mental fart and couldn't figure how to solve it.  I read some message boards where people said it was impossible, but the solution is simple.  If you have a typed dataset in the DataSet Designer and you make changes to the database in sql server (just say add a new column), you can refresh the Dataset by clicking on the Data Sources tab.  Then right click on your dataset or table and clicking "refresh'.

In my situation, my dataset was populated by a stored procedure.  So I had to go into Microsoft Sql Server Management Studio Express, Go the Programmability Folder/Stored Procedures and find my stored procedure.  right click it and select modify, then add the new column and execute it.

Then back in Visual Studio, I had to right click on my Dataset Table and select "Configure Dataset with Wizard" and expand the Stored Procedures, then find my stored procedure and at the bottom was the new column that I added.  Just check the column name and it was added to the dataset.

the above paragraph would probably also apply even if you didn't have a Stored Procedure by your main engine, as you could add and remove tables using the "Configure Dataset with Wizard".

-- Ted


Sunday, July 13, 2008

BannerBitmap conflicts with BannerText

I added a 500X70 banner bitmap to my setup application, however it seems to conflict with the BannerText.  And there doesn't seem to be a way to remove the BannerText.  The following website seems to have a solution.  I haven't tried it out, but it seems to run on the install file after you build your application. 

http://www.bokebb.com/dev/english/1993/posts/199395473.shtml


Add My App to the Open With Menu

I've had a VB.NET application which claim some file types.  When a user double-clicks on one of these file types the application is launched.  However when they right-click on it and select the "Open With" menu, my application comes up, but only the icon is shown.  There is no text with the icon.

I searched on the internets with no solution.  A fair number of people asked this question, like this person
http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic59830.aspx
but no answers.

I tried different things in the Setup part of the application with no luck.  Finally, I realized the issue was with the MUICache value in the Registry, however I did not want to run a .reg file after the install. 

Finally, I stumbled upon the answer, and it seems to be setting the AssemblyDescription value in the AssemblyInfo.vb file of your main executable.  What's odd is that in the recent past, I tried setting some values here and it didn't make a difference. 

The key might have to do is that fact that there was a blank values in the MUICache for my application, and once I deleted the key associated with my application from the MUICache then it registered.  On that note, it could be the AssemblyDescription, AssemblyTitle or AssemblyProduct values as they all have the same value.  I'll need to do more testing to verify exactly which one is the key value to be filled out.

Also, the MUICache values don't get removed when you uninstall your application.



Update
The above technique basically is crap. It only works if the entry doesn't exist in the MUICache. What I mean by that is if you have a blank entry in the MUICache, delete it, then install your application (or just launch it), a new entry will now be in the MUICache with the proper information. For some reason, a previous verison of mine entered a blank value into the MUICache, and now i can't get rid of it, or overwrite it through the install. I'd rather not remove it from my code, but I might end up having to.

Thursday, July 3, 2008

Constants for WND_Proc overrides

I know its possible to get these from some file on your machine, but whenever I need a constant I can't ever seem to find them.  Here is a list I found online:

   Public Const WM_USER As Integer = &H400
   Public Const WM_NULL As Integer = &H0
   Public Const WM_CREATE As Integer = &H1
   Public Const WM_DESTROY As Integer = &H2
   Public Const WM_MOVE As Integer = &H3
   Public Const WM_SIZE As Integer = &H5
   Public Const WM_ACTIVATE As Integer = &H6
   Public Const WM_SETFOCUS As Integer = &H7
   Public Const WM_KILLFOCUS As Integer = &H8
   Public Const WM_ENABLE As Integer = &HA
   Public Const WM_SETREDRAW As Integer = &HB
   Public Const WM_SETTEXT As Integer = &HC
   Public Const WM_GETTEXT As Integer = &HD
   Public Const WM_GETTEXTLENGTH As Integer = &HE
   Public Const WM_PAINT As Integer = &HF
   Public Const WM_CLOSE As Integer = &H10
   Public Const WM_QUERYENDSESSION As Integer = &H11
   Public Const WM_QUIT As Integer = &H12
   Public Const WM_QUERYOPEN As Integer = &H13
   Public Const WM_ERASEBKGND As Integer = &H14
   Public Const WM_SYSCOLORCHANGE As Integer = &H15
   Public Const WM_ENDSESSION As Integer = &H16
   Public Const WM_SHOWWINDOW As Integer = &H18
   Public Const WM_WININICHANGE As Integer = &H1A
   Public Const WM_DEVMODECHANGE As Integer = &H1B
   Public Const WM_ACTIVATEAPP As Integer = &H1C
   Public Const WM_FONTCHANGE As Integer = &H1D
   Public Const WM_TIMECHANGE As Integer = &H1E
   Public Const WM_CANCELMODE As Integer = &H1F
   Public Const WM_SETCURSOR As Integer = &H20
   Public Const WM_MOUSEACTIVATE As Integer = &H21
   Public Const WM_CHILDACTIVATE As Integer = &H22
   Public Const WM_QUEUESYNC As Integer = &H23
   Public Const WM_GETMINMAXINFO As Integer = &H24
   Public Const WM_PAINTICON As Integer = &H26
   Public Const WM_ICONERASEBKGND As Integer = &H27
   Public Const WM_NEXTDLGCTL As Integer = &H28
   Public Const WM_SPOOLERSTATUS As Integer = &H2A
   Public Const WM_DRAWITEM As Integer = &H2B
   Public Const WM_MEASUREITEM As Integer = &H2C
   Public Const WM_DELETEITEM As Integer = &H2D
   Public Const WM_VKEYTOITEM As Integer = &H2E
   Public Const WM_CHARTOITEM As Integer = &H2F
   Public Const WM_SETFONT As Integer = &H30
   Public Const WM_GETFONT As Integer = &H31
   Public Const WM_SETHOTKEY As Integer = &H32
   Public Const WM_GETHOTKEY As Integer = &H33
   Public Const WM_QUERYDRAGICON As Integer = &H37
   Public Const WM_COMPAREITEM As Integer = &H39
   Public Const WM_GETOBJECT As Integer = &H3D
   Public Const WM_COMPACTING As Integer = &H41
   Public Const WM_OTHERWINDOWCREATED As Integer = &H42
   Public Const WM_OTHERWINDOWDESTROYED As Integer = &H43
   Public Const WM_COMMNOTIFY As Integer = &H44
   Public Const WM_WINDOWPOSCHANGING As Integer = &H46
   Public Const WM_WINDOWPOSCHANGED As Integer = &H47
   Public Const WM_POWER As Integer = &H48
   Public Const WM_COPYDATA As Integer = &H4A
   Public Const WM_CANCELJOURNAL As Integer = &H4B
   Public Const WM_NOTIFY As Integer = &H4E
   Public Const WM_INPUTLANGCHANGEREQUEST As Integer = &H50
   Public Const WM_INPUTLANGCHANGE As Integer = &H51
   Public Const WM_TCARD As Integer = &H52
   Public Const WM_HELP As Integer = &H53
   Public Const WM_USERCHANGED As Integer = &H54
   Public Const WM_NOTIFYFORMAT As Integer = &H55
   Public Const WM_CONTEXTMENU As Integer = &H7B
   Public Const WM_STYLECHANGING As Integer = &H7C
   Public Const WM_STYLECHANGED As Integer = &H7D
   Public Const WM_DISPLAYCHANGE As Integer = &H7E
   Public Const WM_GETICON As Integer = &H7F
   Public Const WM_SETICON As Integer = &H80
   Public Const WM_NCCREATE As Integer = &H81
   Public Const WM_NCDESTROY As Integer = &H82
   Public Const WM_NCCALCSIZE As Integer = &H83
   Public Const WM_NCHITTEST As Integer = &H84
   Public Const WM_NCPAINT As Integer = &H85
   Public Const WM_NCACTIVATE As Integer = &H86
   Public Const WM_GETDLGCODE As Integer = &H87
   Public Const WM_SYNCPAINT As Integer = &H88
   Public Const WM_NCMOUSEMOVE As Integer = &HA0
   Public Const WM_NCLBUTTONDOWN As Integer = &HA1
   Public Const WM_NCLBUTTONUP As Integer = &HA2
   Public Const WM_NCLBUTTONDBLCLK As Integer = &HA3
   Public Const WM_NCRBUTTONDOWN As Integer = &HA4
   Public Const WM_NCRBUTTONUP As Integer = &HA5
   Public Const WM_NCRBUTTONDBLCLK As Integer = &HA6
   Public Const WM_NCMBUTTONDOWN As Integer = &HA7
   Public Const WM_NCMBUTTONUP As Integer = &HA8
   Public Const WM_NCMBUTTONDBLCLK As Integer = &HA9
   Public Const WM_KEYFIRST As Integer = &H100
   Public Const WM_KEYDOWN As Integer = &H100
   Public Const WM_KEYUP As Integer = &H101
   Public Const WM_CHAR As Integer = &H102
   Public Const WM_DEADCHAR As Integer = &H103
   Public Const WM_SYSKEYDOWN As Integer = &H104
   Public Const WM_SYSKEYUP As Integer = &H105
   Public Const WM_SYSCHAR As Integer = &H106
   Public Const WM_SYSDEADCHAR As Integer = &H107
   Public Const WM_KEYLAST As Integer = &H108
   Public Const WM_INITDIALOG As Integer = &H110
   Public Const WM_COMMAND As Integer = &H111
   Public Const WM_SYSCOMMAND As Integer = &H112
   Public Const WM_TIMER As Integer = &H113
   Public Const WM_HSCROLL As Integer = &H114
   Public Const WM_VSCROLL As Integer = &H115
   Public Const WM_INITMENU As Integer = &H116
   Public Const WM_INITMENUPOPUP As Integer = &H117
   Public Const WM_MENUSELECT As Integer = &H11F
   Public Const WM_MENUCHAR As Integer = &H120
   Public Const WM_ENTERIDLE As Integer = &H121
   Public Const WM_CTLCOLORMSGBOX As Integer = &H132
   Public Const WM_CTLCOLOREDIT As Integer = &H133
   Public Const WM_CTLCOLORLISTBOX As Integer = &H134
   Public Const WM_CTLCOLORBTN As Integer = &H135
   Public Const WM_CTLCOLORDLG As Integer = &H136
   Public Const WM_CTLCOLORSCROLLBAR As Integer = &H137
   Public Const WM_CTLCOLORSTATIC As Integer = &H138
   Public Const WM_MOUSEFIRST As Integer = &H200
   Public Const WM_MOUSEMOVE As Integer = &H200
   Public Const WM_LBUTTONDOWN As Integer = &H201
   Public Const WM_LBUTTONUP As Integer = &H202
   Public Const WM_LBUTTONDBLCLK As Integer = &H203
   Public Const WM_RBUTTONDOWN As Integer = &H204
   Public Const WM_RBUTTONUP As Integer = &H205
   Public Const WM_RBUTTONDBLCLK As Integer = &H206
   Public Const WM_MBUTTONDOWN As Integer = &H207
   Public Const WM_MBUTTONUP As Integer = &H208
   Public Const WM_MBUTTONDBLCLK As Integer = &H209
   Public Const WM_MOUSELAST As Integer = &H209
   Public Const WM_PARENTNOTIFY As Integer = &H210
   Public Const WM_ENTERMENULOOP As Integer = &H211
   Public Const WM_EXITMENULOOP As Integer = &H212
   Public Const WM_MDICREATE As Integer = &H220
   Public Const WM_MDIDESTROY As Integer = &H221
   Public Const WM_MDIACTIVATE As Integer = &H222
   Public Const WM_MDIRESTORE As Integer = &H223
   Public Const WM_MDINEXT As Integer = &H224
   Public Const WM_MDIMAXIMIZE As Integer = &H225
   Public Const WM_MDITILE As Integer = &H226
   Public Const WM_MDICASCADE As Integer = &H227
   Public Const WM_MDIICONARRANGE As Integer = &H228
   Public Const WM_MDIGETACTIVE As Integer = &H229
   Public Const WM_MDISETMENU As Integer = &H230
   Public Const WM_DROPFILES As Integer = &H233
   Public Const WM_MDIREFRESHMENU As Integer = &H234
   Public Const WM_CUT As Integer = &H300
   Public Const WM_COPY As Integer = &H301
   Public Const WM_PASTE As Integer = &H302
   Public Const WM_CLEAR As Integer = &H303
   Public Const WM_UNDO As Integer = &H304
   Public Const WM_RENDERFORMAT As Integer = &H305
   Public Const WM_RENDERALLFORMATS As Integer = &H306
   Public Const WM_DESTROYCLIPBOARD As Integer = &H307
   Public Const WM_DRAWCLIPBOARD As Integer = &H308
   Public Const WM_PAINTCLIPBOARD As Integer = &H309
   Public Const WM_VSCROLLCLIPBOARD As Integer = &H30A
   Public Const WM_SIZECLIPBOARD As Integer = &H30B
   Public Const WM_ASKCBFORMATNAME As Integer = &H30C
   Public Const WM_CHANGECBCHAIN As Integer = &H30D
   Public Const WM_HSCROLLCLIPBOARD As Integer = &H30E
   Public Const WM_QUERYNEWPALETTE As Integer = &H30F
   Public Const WM_PALETTEISCHANGING As Integer = &H310
   Public Const WM_PALETTECHANGED As Integer = &H311
   Public Const WM_HOTKEY As Integer = &H312
   Public Const WM_PRINT As Integer = &H317
   Public Const WM_PRINTCLIENT As Integer = &H318
   Public Const WM_PENWINFIRST As Integer = &H380
   Public Const WM_PENWINLAST As Integer = &H38F

Tuesday, July 1, 2008

System.IO.FileNotFoundException: Could not load file or assembly 'stdole, Version=7.0.3300.0

All of a sudden I started to get this error when deploying the application, without getting this error on the development machine.  It turns out that the problem has to do with .NET 2.0.  Apparently, the latest version does not include this file in the GAC.  And my application is looking for the file there .  There seems to be a number of possible fixes for this error.  The one that worked for me,  I got from the following website:

http://forums.msdn.microsoft.com/en/clr/thread/426dfa9c-1ab7-4b3e-9474-99edb377fcb6/

To summarize:
1.  Right click on the stdole.dll in the reference section of project and select local copy true. By default it will be false.  This will tell the application not to get it from the GAC.
2.  Add the file to your application.  In your setup application, go to View->Editor->File System.  In the pane that opens up, right click and select Add->Assembly.  Go to the following location:
C:\Program Files\Microsoft.NET\Primary Interop Assemblies and select stdole.dll.

Recompile your application and it should now work.

Below are some other suggestions:
- Remove the reference from your project (I couldn't do this as I use an old FlexGrid and it used it).
-
In "Project-Properties" - "Publish" - "Application Files..." - "stdole.dll" set "publish Status" to "Include". (I already had the file included when I got the problem).
- From the command-line run gacutil with the stdole.dll.  This is a workaround to get it up and running fast, but defeats the idea of having a setup application.

some other sites where people asked this question:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=9506&SiteID=1
http://forums.msdn.microsoft.com/en-US/vbgeneral/thread/17d097ae-9465-4a0d-82f1-5005b7dc26e0/

Wednesday, June 25, 2008

Find ComboBox disappeared in VS 2005

I had this problem when I installed VS 2005.  The fix is in this message board

http://forums.asp.net/p/1109112/1709908.aspx

The solution:

1. Right click the toolbar

2. Select Customize...

3. Drag and drop the "Edit | Go To Find Combo" from "Commands" tab to the Standard toolbar.



Monday, June 16, 2008

Bitmap Clone vs new Bitmap vs ???

I was loading a Bitmap Image from a FileStream and calling the Image.Clone function.  When I tried to save the Image to another file I got the following error "A generic error occurred in GDI+", below is the exact code I was using:

In  Class1.Function1 I had the following:

public Bitmap Functon1(string tempFileName)
{
                Bitmap bm;
                System.IO.FileStream fs;
                fs = new FileStream(tempFileName, FileMode.Open, FileAccess.Read);
                try
                {
                    bm = (Bitmap)System.Drawing.Bitmap.FromStream(fs);
                }
                catch
                {
                    throw;
                }
                finally
                {
                    fs.Close(); // I want to make sure the stream is closed
                }

                return (Bitmap)bm.Clone();
}
I placed the returned Bitmap into an ArrayList, called ListType.  Later on in the program I did the following and got the GDI+ error:
                pic.Image = (Bitmap)ListType[i];
                Bitmap tempImage = (Bitmap)pic.Image.Clone();
                tempImage.Save(@"c:\temp\file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

One solution was to replace, and I no longer got my error.
                Bitmap tempImage = (Bitmap)pic.Image.Clone();
With
                Bitmap tempImage = new Bitmap(pic.Image);

That seemed to work.  However, another developer that was using my program was using an Image Library that did a deep clone, and whenever he ran his clone method on the image in my ArrayList he got the GDI+ error.  Therefore, I felt that I had to change my Function1.  I found a solution on the following website:
http://forums.msdn.microsoft.com/en-US/netfxbcl/thread/970a7951-19f3-4ca3-8061-683b96c11a88/

The solution in my Function was:
        static public Bitmap Function1 (string tempFileName)
        {
            try
            {              
                using (FileStream fs = new FileStream(@tempFileName, FileMode.Open))
                {
                    int len = (int)fs.Length;
                    byte[] buf = new byte[len];
                    fs.Read(buf, 0, len);
                    using (MemoryStream ms = new MemoryStream(buf))
                    {
                        return new Bitmap(ms);
                    }
                }
         }

This solved the problem when the other developer called his deep clone method.  The explanation from the author of this block of code was:
GDI+ holds on to the stream handle and puts a lock on the file. Cloning is handled by GDI+, it probably copies the file handle too. You'll find that saving back the image to the same file will generate an exception too. The workaround is to load the image into memory first so GDI+ can't lock anything. For example:

Anyways, thats about it.

-- Ted



Thursday, June 12, 2008

"The page cannot be displayed" error for chm files

I had some chm files that I've always been able to open and read.  However, recently I moved them to other folders when all of a sudden I was not able to view the individual pages in these files.  I got a page cannot be displayed error.  It turns out that the reason is that I placed these chm files in a folder that had a "#".  These were C# books, so I created a folder called "C#"and placed the chm files in this folder.  This is what caused my problem.  Once I renamed the folder to "C Sharp" I was able to open the chm files.

Get VSS Password & User ID auto-entered by VSS

To get your VSS password & user ID auto-entered by VSS you need to define environment variables that contain this info.

Here is how to do it:

1.      Right-click My Computer and then click Properties.
2.      In the System Properties dialog box, click Advanced, and then click Environment Variables.
3.      Under User variables click New.
4.      In the New User Variable dialog box, in the Variable name box, type "SSUSER".
5.      In the Variable Value box, type your VSS username, and then click Ok.
6.      Repeat these steps to add "SSPWD" as an environment variable whose value is your VSS password.

Convert a Bitmap to a Raw Image in C#

I have a C dll that takes a Bitmap and writes it out to a Raw Image file, but was looking for a solution in C# and found this code on the following site: http://www.developerfusion.co.uk/forums/p/27321/160103/#160103

/// <summary>
/// Convert a bitmap to a byte array
/// </summary>
/// <param name="bitmap">image to convert</param>
/// <returns>image as bytes</returns>
private byte[] ConvertBitmap(Bitmap bitmap)
{
    //Code excerpted from Microsoft Robotics Studio v1.5
    BitmapData raw = null;  //used to get attributes of the image
    byte[] rawImage = null; //the image as a byte[]

    try
    {
        //Freeze the image in memory
        raw = bitmap.LockBits(
            new Rectangle(0, 0, (int)bitmap.Width, (int)bitmap.Height),
            ImageLockMode.ReadOnly,
            PixelFormat.Format24bppRgb
        );

        int size = raw.Height * raw.Stride;
        rawImage = new byte[size];

        //Copy the image into the byte[]
        System.Runtime.InteropServices.Marshal.Copy(raw.Scan0, rawImage, 0, size);
    }
    finally
    {
        if (raw != null)
        {
            //Unfreeze the memory for the image
            bitmap.UnlockBits(raw);
        }
    }
    return rawImage;
}



Tuesday, May 27, 2008

GetPath in VB.NET 2005

In VB6 we used to use App.Path to get the path of the application.  When I converted to VB.NET 2003, I started to using
System.Reflection.Assembly.GetExecutingAssembly.Location without actually knowing what I was doing, but it worked and I was getting the location of the path,

However, in VB.NET 2005, this stopped working and the path it would give me was something like:
C:\Documents And Settings\......\LocalSettings\Application Data\Microsoft\VisualStudio\8.0\ProjectAssemblies\_ean0rwersws\.....

Now the "eanOrwersws" was a random folder that it generated whenever I rebuilt the application.  This seemed odd to me.

It turns out that the better way to get the Path of the application is to use one of the following calls:
System.Windows.Forms.Application.StartupPath <-- This returns the path without a "\"

I can't tell the difference between the following two calls, but they both return the path with a "\" at the end.
System.AppDomain.CurrentDomain.BaseDirectory()
AppDomain.CurrentDomain.SetupInformation.ApplicationBase()


Wednesday, May 21, 2008

Detect the Shift, Ctrl, Return Key pressed at the same time

Another simple one.  I needed to detect if the Shift, Ctrl, and Return key were pressed at the same time.  Now, the three combinations, could consist of the Alt key as well.  Anyways, for some reason I just wasn't getting it, even though I knew it was a simple problem.  This is my solution.  If you were to debug this.  Just open a new Windows Application project and paste this in.  The key thing if you were to debug this is to put the breakpoint on the Debug line.  If you put the breakpoint on the Select Case statement (which I was doing and which was messing me up), it will appear that its not working.  Basically the reason is that if you press the Shift, Ctrl, and Return key, the first time through the Routine it will detect the Shift, or Ctrl keys, and it won't go into your if statement.  However, after it goes through those checks, it will evaluate the Return key that was pressed.  Now, when the return key is pressed you check if the Shift and Control keys are also down through the statement e.Shift and e.Control.  This returns true and you are set.

  Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
    Select Case e.KeyCode
      Case Keys.Enter
        If e.Shift And e.Control Then
          Debug.Write("all three pressed")
        End If
    End Select
  End Sub

The MSDN documentation has an example where you use the e.Modifiers value, and to be honest at this point I am not sure how that value gets set.  But the above procedure does work.

-- Ted

Wednesday, May 14, 2008

Missing References Folder in Solution Explorer in VS2005

I upgraded to VS2005 and all of a sudden I couldn't find my references folder in the Solution Explorer.  Yes,  I could see it via the Properties of a project, but I liked seeing it as a folder like I did in VS2003.  The solution it turns out is very simple, in the top of the Solution Explorer is a button you can press to "Show All Files" this toggles it on and off.

Thursday, May 1, 2008

Update - Datagridview - Sorting Numeric Columns that are not bound...

I found an example on a website that did what I mention above but does it a lot better.  Below is the pasted code

    Private Sub grd_SortCompare(ByVal sender As
Object, ByVal e As System.Windows.Forms.DataGridViewSortCompareEventArgs) Handles grdList.SortCompare
        e.SortResult = CompareEx(e.CellValue1.ToString, e.CellValue2.ToString)
        e.Handled = True
        Exit Sub
    End Sub


    Public Function CompareEx(ByVal s1 As Object, ByVal s2 As Object) As Integer

        Try
' convert the objects to string if possible.
            Dim a As String = CType(s1, String)
            Dim b As String = CType(s2, String)

' If the values are the same, then return 0 to indicate as much
            If s1 = s2 then return 0

' Look to see if either of the values are numbers
            Dim IsNum1 As Boolean = IsNumeric(a)
            Dim IsNum2 As Boolean = IsNumeric(b)

' If both values are numeric, then do a numeric compare
            If IsNum1 And IsNum2 Then
                If Double.Parse(s1) > Double.Parse(s2) Then
                    Return 1
                ElseIf Double.Parse(s1) < Double.Parse(s2) Then
                    Return -1
                Else
                    Return 0
                End If
' If the first value is a number, but the second is not, then assume the number is "higher in the list"
            ElseIf IsNum1 And IsNum2 = False Then
                Return -1
' if the first values is not a number, but the second is, then assume the number is higher
            ElseIf IsNum1 = False And IsNum2 Then
                Return 1
            Else
' If both values are non nuermic, then do a normal string compare
                Return String.Compare(s1, s2)
            End If
        Catch ex As Exception
            Console.WriteLine(ex.ToString)
        End Try

' If we got here, then we failed to compare, so return 0
        return 0
    End Function

Datagridview - Sorting Numeric Columns that are not bound to a DataSource

Or more precisely sorting Double (floating point, decimal) Columns that are not bound to a DataSource.

There are a lot of examples out there to sort datagridview columns that are bound to a datasource, but I could only find one example that had a solution to solving the problem of sorting when the data is not bound to a datasource.

This is the data that I have, in a csv file
Dharmit,Male,10.001,First
Lomesha,Female,11.001,Second
Jaymit,Male,7.001,Third
Ambrish,Male,8.001,First
Chanda,Female,172.00101,Second

The third column (lets call it Order) contains data that is not integers, they are double values.  I load it into a datagrid view by reading each line to a String Array, and then loading the array to the datagridview.

When I do a sortascending on the Order column, it sorts it as if it was String/ or Text instead of as a number.  If the Order column had values like 10, 11, 7, 8, 172 it would sort it properly, but the decimal point screws it up into thinking that it is text.  The solution to this problem is to use the SortCompare event, and to manually figure out if values are equal, greater than or less than.  Initially I didn't understand the sortResult values.  What does 1, -1, and 0 mean.  And to be honest I still don't know, just trial and error.  Some things to keep in mind.  The Data must not be be bound, and the VirtualMode must be False, and the SortCompare is called when the Sort is called, in my case I call it programatically and have set it such.  Also the code below assumes the data is numeric.

  Private Sub DataGridView1_SortCompare(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewSortCompareEventArgs) Handles DataGridView1.SortCompare
    If Double.Parse(e.CellValue1) > Double.Parse(e.CellValue2) Then
      e.SortResult = 1
    ElseIf Double.Parse(e.CellValue1) < Double.Parse(e.CellValue2) Then
      e.SortResult = -1
    Else
      e.SortResult = 0
    End If
    e.Handled = True
    Exit Sub
  End Sub



Thursday, April 3, 2008

MSVCR71.dll not found or MSVCP71.dll not found

I had an application and everything works fine in Windows XP, however when I installed the application on Vista, certain features did not work and gave me an error that MSVCR71.dll was not found.  Well, sure enough the dll wasn't on the Vista machine and it was on the other machines that I was testing on.

My initial thought was to add the dll's to the setup application.  But then I read an article that if you wanted to deploy these dll's to just add the merge module VC_User_CRT71_RTL_X86_---.msm from Program Files\Common Files\Merge Modules.  So I did this.  Right-click on your Setup application, select Add, then select Merge Module... and then select the module.  In the properties for the file, make sure you install it in the application folder and not the setup folder.  Ok, I tried this and still my application wasn't working. 

So I finally decided to just add the dll's directly.  Well, I right-clicked on the setup application, select Add, File.  And then navigated to the Windows\System32\ directory.  Found MSVCR71.dll and MSVCP71.dll (it turns out you need this one as well), and when I attempted to add them, I got a message that said that these two dll's were found in the vc_user_stl71_rtl_x86_---.msm and would I like to add that instead.  So I said "Yes", then I got a message to add VC_User_CRT71_RTL_X86_---.msm, so I said ok.  Installed the application on the Vista machine and everything worked fine.    What ends up getting installed on the Vista machine are the dll's, not the msm files.

Anyways, the moral of the story is that if you need a dll, just go straight to it, instead of trying to figure out what msm files.  The setup application is smart enough to figure out if that dll has an associated merge module.  I think :-)

Monday, March 24, 2008

Implicit conversion from 'System.Array' to '1-dimensional array of Byte' in copying the value of 'ByRef' parameter 'Value' back to the matching argument

I converted a project from VB6 to VB2003 to VB2005.

In VB6 we had the following type of code:

      Dim tempBytes() As Byte, readFileHandle As Long
      readFileHandle = FreeFile
      Open imgFile For Binary Access Read As #readFileHandle
      ReDim tempBytes(1 To LOF(readFileHandle))
      Get #readFileHandle, 1, tempBytes 'dataoffset is 0-based; GET is 1-based

What this basically did was it opened an image file and then read in the image file to a byte array.

When we converted to VB2003, the code was converted and fixed as such:
        Dim tempBytes() As Byte
        Dim readFileHandle As Integer
        readFileHandle = FreeFile()
        FileOpen(readFileHandle, imgFile, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared)         '!!## errors?
        ReDim tempBytes(LOF(readFileHandle) - 1)           
        FileGet(readFileHandle, tempBytes, 1)            'dataoffset is 0-based; GET is 1-based

In converting it to VB2005, I decided to turn Option Strict ON, which gave a warning on the following line.  The warning is the subject of this post:
        FileGet(readFileHandle, tempBytes, 1)            'dataoffset is 0-based; GET is 1-based

The warning made sense, tempBytes is type Byte, and FileGet is expecting a System.Array.

The way to fix this is to cast tempBytes as an array, and the warning will go away, and it will still work.
            FileGet(readFileHandle, DirectCast(tempBytes, Array), 1)            'dataoffset is 0-based; GET is 1-based




Single Instance Applications is a lot easier in VB 2005

For more information, read the following post:

http://blogs.msdn.com/tyler_whitney/archive/2005/11/23/VB-Application-Model.aspx


From the article:

So what's a Single-Instance application?  Imagine launching an application where additional attempts to launch the app while the first one is running doesn't actually launch a new instance of the app.  Instead the original instance of the app gets notified that another launch attempt occurred.  When we introduced an application model for Visual Basic in VB 2005, one of the things we wanted to do is make it drop-dead easy to create single-instance applications.


Pretty much what you need to do in VB 2005 is to right click on your main project and go to properties. 
then select Application, then make sure you have "Enable application framework" checked.

Then check of "Make single instance application"

For the other items. I have everything checked, and the authentication mode, I chose Windows, and the shutdown mode, I chose When startup form closes, and for the Splash screen, I have code that takes care of this.

Either way, this is a lot easier than writing code in order to make this happen properly.

-- Ted


Thursday, March 13, 2008

Integer Division in VB.NET

Copied this from http://www.devx.com/vb2themax/Tip/18244

It pretty much talks about the difference between doing division with the "/" vs "\"

Use integer division operator
Use "\" instead of "/" when performing divisions between Integers. The "/" operator returns a Single value, therefore the seemingly efficient line


C% = A% / B%
actually requires three implicit conversions, two for converting the operands from Integer to Single (to prepare them for the division) and one to convert the result from Single to Integer (to complete the assignment). If you use the "\" operator you don't incur in this overhead, and the division itself is faster. While we are on this topic, keep in mind that the "/" operator returns a Double value if at least one of its operands is a Double; therefore if you wish the highest precision when dividing two Integer or Single values, you should manually coerce one of them into Double type:

' this prints 0.3333333
Print 1 / 3
' this prints 0,333333333333333
Print 1 / 3#


Tuesday, March 11, 2008

Using the ^ operator that can slow your application down

I recently had an application where we used the "^" operation to do a Power operation.

For example in order to square X, we did X^2.  It turned out that using the "^" operator was slower than using X*X, or even using Math.Pow(X, 2).  It wasn't noticeably faster if you only did this once or twice, but in our situation, we called this function millions of times, so a little improvement made a big difference.

-- Ted

Tuesday, February 26, 2008

Use PerformClick to call a Menu Item's Click event from your code

Another easy one, and I've done this before too, just forgot about it.

But I had an Menu Click event that I wanted to call from code.  When you call Menuitem1.Click you get an error, because it expects a sender and some args.  I started down the path of supplying the arguments, when I stumbled across the PerformClick event, that you can just call.  Yeah.

Another option would be to move your code from the Menu Click event to another function, and call that function from both the MenuClick event and from any where else you would like to.

How to have different colors for different items in a combobox in VB.NET

I have a drop down style combobox in VB.NET 2003, and I would like to assign different colors to different items in the combobox.  I came across the following article on vbcity:
http://vbcity.com/forums/faq.asp?fid=15&cat=ListBox%2FComboBox

The article shows you how to add images to combobox items and different colors.  You  can also download code and try things out yourself.  However, for me all I wanted was to color different items a different color.  Using some of the concepts from the article,  this is how one can do such a thing:

1.  The first thing one needs to do, in the drawmode property of the Combo Box, to select either OwnerDrawFixed, OwnerDrawVariable.
2.  Next, in the DrawItem Event the user can do something the the following:

        Dim g As Graphics = e.Graphics

        Dim bBlue As SolidBrush = New SolidBrush(Color.Blue)
        Dim bRed As SolidBrush = New SolidBrush(Color.Red)
        Dim bOrange As SolidBrush = New SolidBrush(Color.Orange)

            If e.Index = 0 Then
                g.DrawString("Value1", Me.ComboBox1.Font, bBlue, e.Bounds.Left, e.Bounds.Top)
            ElseIf e.Index = 1 Then
                g.DrawString("Valu2", Me.ComboBox1.Font, bRed, e.Bounds.Left, e.Bounds.Top)
            Else
                g.DrawString("Value3", Me.ComboBox1.Font, bOrange, e.Bounds.Left, e.Bounds.Top)
            End If
        bBlue.Dispose()
        bRed.Dispose()
        bOrange.Dispose()


This basically colors the first value, Blue, the second value Red and everything else Orange.


Sunday, February 24, 2008

My Autos Window has Disappeared in VB.NET

This might not be a big deal, but the other day I had to help a team member work out some problems he was having.  Well, this person has just installed VB.NET on his computer.  In order to figure out the problem, I had to debug the application, well while in debug mode, I noticed that the Autos window, and Locals window didn't exist.  Well, I figured I could just show it by going to the View Menu.  However, when I went there I couldn't find the Autos Window or the Locals Window.  I couldn't figure what was going on on his machine, but was able to use the Watch window to figure the values.  I guess sometimes we don't realize how specific parts of our work environment got there, and we just take them for granted.  I've always had the Autos Window and Locals Window, so I've never had to actually add it back.

Anyways, after checking MSDN library, I found that the Auto's Window can be shown and hidden by going to the Debug Menu/Window/ And selecting it from that submenu.  You can also show it by pressing  Ctrl+Alt+V, and then the letter A.


Friday, February 22, 2008

Beware when removing items from an ArrayList

I have an arraylist, and each item contains a structure.  The structure contains a point and an index value.  There are times when I need to go through the arraylist and delete all the items which have an index equal to a specific value.  So for example, the arraylist contains the followint
 
0 -- pt = 1, index = 0
0 -- pt = 2, index = 0
0 -- pt = 3, index = 0
0 -- pt = 6, index = 1
0 -- pt = 9, index = 1
 
When I tried to loop through through the array using a For Loop, I had the problem where after deleting the first point, the second point was moved to the first position, and the for loop missed it.  This is the code I used for the For Loop:
 
  For i = 0 To aList.Count - 1
   If aList(i).Index = Index Then 'The Index was supplied to the function
    aList.RemoveAt(i)
   End If
  Next
 Furthermore, the for loop ends up giving you an out of bounds error, because the size of the array changes.  So my solution was to use a while loop, like so:
  While i < aList.Count - 1
   If aList(i).Index = Index Then 'The Index was supplied to the function
    aList.RemoveAt(i)
   Else
    i = i + 1
   End If
  End While
Now the first thing I asked when I did this is what happens if you have an arraylist like so:
0 -- pt = 1, index = 0
0 -- pt = 2, index = 1
0 -- pt = 3, index = 1
0 -- pt = 6, index = 0
0 -- pt = 9, index = 0
 
In this situation the arraylist will delete the first item, then i will still be equal to 0, and it will look at the the item with value pt = 2, it will keep it.  It will then look at pt = 3, it will keep it.  It will look at pt = 6, and delete it.  Then look at pt = 9 and delete it as well.  So it looks like this should work without any problems.  Though I'm sure there is something that I'm missing here.
 
 
 

Tuesday, February 12, 2008

How to make a form a child of a control in VB.NET

I had a control.  The control would open a Form.  I wanted to make the Form a child of the control.  For some reason I couldn't get this to work.  What I wanted was this Form to be on top of the control, and I didn't want the form to be moved out of the control.  I also wanted the form to close if the control was closed.  Anyways, I just couldn't get it to work properly.

I tried doing the following:
                Form1.Owner = Me.Parent         

But then I had to set the Form1 as the TopMost control.  And this didn't allow me to click on other parts of the control.

Anyways, the things that worked was thie following line:
                Form1.TopLevel = False                'This is the key line in order to make Form1 a Child of this Control

I also do the following (which I did before):
                Form1.Parent = Me
                Form1.IsMdiContainer = False
                Form1.BringToFront()

I no longer do the call to Form1.Owner = Me.Parent as it is not needed and having that call there messes things up.



Friday, February 8, 2008

How to completely validate input in a TextBox even on paste

I had a textbox and I wanted to make sure that the text entered was only alpha numeric.  I put in validation logic in to KeyPress which you can find just by doing a google search.  However, most of the sample code out there limits the data as you enter it, one character at a time.  What if you want to allow people to paste text into your textbox, and still validate the data pasted.

The solution was to put validation logic into the TextChanged event as well.  I don't remember exactly the scenario, but there might be situations where your validation logic my interpret the Ctrl-V as an invalid character, and it won't allow you to paste your values in.  The way I was able to work around this was in the KeyDown event to check if the Ctrl button was pressed, if it was pressed, I would set a flag.  In the KeyPress event I checked if the flag was set.  If it was set, then I didn't go into my validation logic (which would have interpreted the Ctrl-V as an invalid character), I just exited the sub.  This way the text was pasted, but in TextChanged, I would then validate the text that was pasted.


How to get the Short Filename to a Windows File in VB.NET

I had an application that needed to call an external exe and supply it with an input and output filename.  The problem I had was that if the filename had a space in it, the executable would give me an error.  I tried putting double quotes around the entire call, double quotes around the filenames, single quotes.  But nothing would work.  I didn't have access to the code of the executable.

What I ended up doing was to use the Short Filename.  Below is code that helped me do it.  I found it on some message board, but didn't save the reference.

    Private Const MAX_PATH As Integer = 260

    Private Declare Auto Function GetShortPathName Lib "kernel32" ( _
    ByVal lpszLongPath As String, _
    ByVal lpszShortPath As System.Text.StringBuilder, _
    ByVal cchBuffer As Integer) As Integer

    Public Function GetShortFileName(ByVal LongPath As String) As String
        Dim ShortPath As New System.Text.StringBuilder(MAX_PATH)
        Dim BufferSize As Integer = GetShortPathName(LongPath, ShortPath, ShortPath.Capacity)
        Return ShortPath.ToString()
    End Function


Tjust call GetShortFileName with the filename you want to change and it will return the Windows Short Filename.

-- Ted

Monday, February 4, 2008

Debug Visual C++ DLL from VB.NET

FYI, I am running .NET 2003.  I have a VB.NET project that calls functions in a C++ DLL.  Every once in a while, there is a problem with functions in the DLL, and usually we just put MessageBox statements in the DLL, rebuild it and then run the VB.NET program to try to figure out what is wrong.  However, this process takes up time as we have to continually go back and forth until we figure out the problem.  What I wanted was to just debug my C++ code, from the debugger.  I did some google searches and came up with bits and pieces.  The one thing that I found was that a lot of people have asked this question in a number of message boards without any answers.

Using some of the hints suggested, I was able to come up with a method that works.

I created a brand new Visual C++ dll project (called testcplusplusdll), with one cpp file (mainfile.cpp).  This is what it had:

#include <windows.h>
#define CALLINGCONV __declspec(dllexport) __stdcall

int CALLINGCONV Trace() {
    int hgt,wid;
        hgt = 2;
        wid = 2;
        hgt = hgt + wid;
        MessageBox(NULL,"trace1","Trace13",0);   

  return 1;
}

In the Project Properties.  Project->testcplusplusdll Properties
Under Configuration Properties -> Debugging.  For the command I entered the path to the executable of the VB.NET program (we'll get into that in a little bit).  For Attach, I have the value "No", for Debugger Type, I have "Native Only" but others might work (just haven't tried it yet), everything else on that page was left to the default. 

Under the Linker Folder, I kept the default settings, but they are:
under Debugging. for Generate Debug Info I have "Yes (/DEBUG)"
Generate Program Database File - "$(OutDir)/testcplusplusdll.pdb"

That's it for the C++ project.  Build it, and make sure it compiles.  The compiled dll ended up in a Folder called "Debug"

Now, on to the VB.NET project.  I created a new Project.  The location where it put the project wasn't in the same location as the C++ project.  On the form, I placed a button.  And Below is the code that I added to the Form.

    Private Declare Function Trace Lib "..\..\testcplusplusdll\debug\testcplusplusdll.dll" Alias "?Trace@@YGHXZ" () As Integer

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Trace()
    End Sub


A couple of points.  To figure out the Alias of the C++ function, I used the Depends application that came with VB6.  The value for Lib, is  the path to the testcplusplusdll.dll that I compiled earlier.

I build the project.  I am still in the Debug Configuration.

Now, I go back to my C++ project, and as I mentioned earlier, and under onfiguration Properties -> Debugging->Command, I entered the path to the executable of the VB.NET project I just built.

Now I set a beakpoint in the C++ code, and run the C++ project (it takes a while but be patient).  It will popup the Form1, and when I click on Button1, it will stop in my C++ code.  Yeah.


A couple of things that I read about that I tried that didn't make a difference:
1.  In the VB.NET program, under Project Properties under Debugging, there is a checkbox for "Unmanaged Code Debugging", checking it or unchecking it didn't make a difference.
2.  In the VB.NET, if you click on the Solution, and then go to Project->Properties.  You can do "Debug Source Files" and "Debug Symbol Files".  I had entered the location of the c++ source files to this location, and the location of the c++ pdb file in the Symbol Files location, but when I removed it, it didn't seem to make a difference.

Hopefully this is helpful to someone.


Sunday, January 27, 2008

CtrlV Shortcut causes a conflict with a Paste Menu Item

I have a form with a Menu Item, that I call "mnuPaste" that has a CtrlV shortcut associated to it.   On this form I have a TextEntry control.  If you try to paste text into the TextEntry control by hitting Ctrl-V, it will not paste because the Ctrl-V gets consumed by the mnuPaste Menu Item.

Now I still haven't found the perfect solution.  Ideally I would like the innermost control to have precedence.  So first TextEntry gets the Ctrl-V, then if we are not on the TextEntry control,  the Form's mnuPaste has precedence.  However, I can't seem to get this going.

The best I can do is direct the Ctrl events to the ActiveControl like this:

In the Form declare this function:

Private Declare Auto Function SendMessage Lib "user32" ( ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr ) As IntPtr

Then overide ProcessCmdKey in the Form:

Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
  SendMessage(
Me.ActiveControl.Handle, msg.Msg, msg.WParam, msg.LParam)
End
Function

You can also use this type of call to send Ctrl from the MDI Parent to the Child form.  In that case you would replace Activecontrol with ActiveMdiChild.






Wednesday, January 23, 2008

Initialize an array

This might seem very simple, but for some reason I forgot how to initialize an array in vb.net

In C++ you would do something like this:
int values[] = {1,2,3}

But I couldn't remember how to do it in VB.NET.
Anyways, below is how one would do it:
Dim values() As Integer = {1, 2, 3}