http://www.developer.com/

Back to article

More Windows Secrets for Visual Basic


January 29, 2003

Introduction

Welcome to the second article in the .NET secrets series!

I'm Karl Moore and, once again, you're reading another bundle of secrets I've adapted from my soon-to-be-released book, VB .NET and ASP.NET Secrets.

This week, I'm continuing to look at Windows application secrets. Today, we'll figure:

  • The .NET method of checking for a previous instance
  • How to convert the contents of a RichTextBox control to HTML
  • What you need to do to support dragging-and-dropping from Windows Explorer
  • The exact code you need to capture the screen, quickly and easily

Got any .NET tips and tricks of your own? I'd love to hear about them and possibly formulate them into this series (with full credit given, naturally!). Drop me a line—karl@karlmoore.com.

But without further ado... the secrets!

The .NET Way of Checking for Previous Instances

There are times when it's useful to check whether another instance of your application is running. For example, when starting up your program, you may want to check whether another version is already running in the background and, if it is, give that instance the focus.

In Visual Basic 6, you had the App.PrevInstance property to do this. In VB.NET, we need to check whether the current process is running more than once. That's what our code does here, encapsulated in the PrevInstance function. It returns a True if your application is already running on the same machine:

Public Function PrevInstance() As Boolean
  If Diagnostics.Process.GetProcessesByName _
     (Diagnostics.Process.GetCurrentProcess.ProcessName) _
               .Length > 1 Then
     Return True
  Else
     Return False
  End If
End Function

You might use this code as so:

If PrevInstance() = True Then
  ' Get all previous instances
  Dim Processes() As Process
  Processes = _
    Diagnostics.Process.GetProcessesByName( _
    Diagnostics.Process.GetCurrentProcess.ProcessName)
  ' Activate the first instance
  AppActivate(Processes(0).Id)
  ' Exit the current instance
  Application.Exit()
End If
Top Tip: There's a little bug you may run into when using this code that turns the hair of most developers a funny shade of gray. If your application name is greater than fifteen characters, and running on either Windows NT or 2000, your code won't be able to tell whether a previous instance is running. Weird, but true. Solution: upgrade to XP or higher, or change your application name (Project > Properties).

Converting RTF to HTML

One amazingly common developer request is a method of converting the contents of a RichTextBox control to HTML. But, unless you're willing to spend hundreds on a third-party text editing control, you're out of luck. Even in VB.NET, Microsoft has chosen to remain ignorant to this much desired feature.

So, you need to do it yourself—and the following chunk of code I've put together should get you started. Just pass it a RichTextBox control as a parameter and it'll return a string of HTML, ready for you to perhaps save to a file.

It doesn't handle more complicated features, such as images or tables; however, it will easily cope with fonts, sizes, colors, bold, italic, and paragraphs. Of course, you're more than welcome to expand it to suit your needs exactly.

You can call this code, as so:

strHTML = ConvertToHtml(RichTextBox1)

And here's the actual ConvertToHTML function:

Public Function ConvertToHTML(ByVal Box As RichTextBox) _
               As String
   ' Takes a RichTextBox control and returns a
   ' simple HTML-formatted version of its contents
   Dim strHTML As String
   Dim strColour As String
   Dim blnBold As Boolean
   Dim blnItalic As Boolean
   Dim strFont As String
   Dim shtSize As Short
   Dim lngOriginalStart As Long
   Dim lngOriginalLength As Long
   Dim intCount As Integer
   ' If nothing in the box, exit
   If Box.Text.Length = 0 Then Exit Function
   ' Store original selections, then select first character
   lngOriginalStart = 0
   lngOriginalLength = Box.TextLength
   Box.Select(0, 1)
   ' Add HTML header
   strHTML = "<html>"
   ' Set up initial parameters
   strColour = Box.SelectionColor.ToKnownColor.ToString
   blnBold = Box.SelectionFont.Bold
   blnItalic = Box.SelectionFont.Italic
   strFont = Box.SelectionFont.FontFamily.Name
   shtSize = Box.SelectionFont.Size
   ' Include first 'style' parameters in the HTML
   strHTML += "<span style=""font-family: " & strFont & _
     "; font-size: " & shtSize & "pt; color: " _
                     & strColour & """>"
   ' Include bold tag, if required
   If blnBold = True Then
       strHTML += "<b>"
   End If
   ' Include italic tag, if required
   If blnItalic = True Then
       strHTML += "<i>"
   End If
   ' Finally, add our first character
   strHTML += Box.Text.Substring(0, 1) 
   ' Loop around all remaining characters
   For intCount = 2 To Box.Text.Length
       ' Select current character
       Box.Select(intCount - 1, 1)
       ' If this is a line break, add HTML tag
       If Box.Text.Substring(intCount - 1, 1) = _
              Convert.ToChar(10) Then
           strHTML += "<br>"
       End If
       ' Check/implement any changes in style
       If Box.SelectionColor.ToKnownColor.ToString <> _
          strColour _ Or Box.SelectionFont.FontFamily.Name _
          <> strFont Or _ Box.SelectionFont.Size <> shtSize _
          Then
           strHTML += "</span><span style=""font-family: " _
             & Box.SelectionFont.FontFamily.Name & _
             "; font-size: " & Box.SelectionFont.Size & _
             "pt; color: " & _
             Box.SelectionColor.ToKnownColor.ToString & """>"
       End If
       ' Check for bold changes
       If Box.SelectionFont.Bold <> blnBold Then
           If Box.SelectionFont.Bold = False Then
               strHTML += "</b>"
           Else
               strHTML += "<b>"
           End If
       End If
       ' Check for italic changes
       If Box.SelectionFont.Italic <> blnItalic Then
           If Box.SelectionFont.Italic = False Then
               strHTML += "</i>"
           Else
               strHTML += "<i>"
           End If
       End If
       ' Add the actual character
       strHTML += Mid(Box.Text, intCount, 1)
       ' Update variables with current style
       strColour = Box.SelectionColor.ToKnownColor.ToString
       blnBold = Box.SelectionFont.Bold
      blnItalic = Box.SelectionFont.Italic
       strFont = Box.SelectionFont.FontFamily.Name
       shtSize = Box.SelectionFont.Size
   Next
   ' Close off any open bold/italic tags
   If blnBold = True Then strHTML += ""
   If blnItalic = True Then strHTML += ""
   ' Terminate outstanding HTML tags
   strHTML += "</span></html>"
   ' Restore original RichTextBox selection
   Box.Select(lngOriginalStart, lngOriginalLength)
   ' Return HTML
   Return strHTML
End Function
Top Tip: Looking to turn HTML back into text? Check out my "Converting HTML to Text, Easily" tip in the "More .NET Secrets" chapter of my book, VB.NET and ASP.NET Secrets for a ready-to-run algorithm.

Our code doing its stuff: translating RTF into HTML

Drag and Drop from Windows Explorer

Dragging and dropping within your application is pretty simple stuff. Simply set a couple of properties and you're rocking: look up 'drag and drop, Windows Forms' in the Help Index for more information. But what if you want to drag and drop from another application, such as Windows Explorer?

One of the most commonly requested, yet infrequently answered Windows form questions is, "How can I let my users drag and drop files and folders directly into my applications?". Simple, just follow these three easy steps:

  1. Change the AllowDrop property of the control you want users to drop the files onto to True. This could be a ListBox control, a Panel control, or even your form itself.
  2. Add code to the DragOver event of the control, so the typical 'copy' icon is displayed when files are dragged over:
  3. ' As dragged over, check data is file drop
    If e.Data.GetDataPresent(DataFormats.FileDrop) Then
        ' Display the copy (or other) icon
        e.Effect = DragDropEffects.Copy
    End If
    
  4. Finally, add code to the DragDrop event of the control, to receive and process information about the dropped files:
  5. ' Check this is a file drop
    If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then
        ' Retrieve list of files and loop through string array
        Dim strFiles() As String = e.Data.GetData( _
                                   DataFormats.FileDrop)
        Dim intCount As Integer
        For intCount = 0 To strFiles.Length
            MessageBox.Show(strFiles(intCount))
        Next
    End If
    

And that's it! In three simple steps, your application is ready to interoperate with Windows Explorer or any other application supporting the standard Windows file drag and drop routines.

Of course, here we're simply displaying the dropped files or folders in a message box here; however, you could be doing something much more exciting: generating an MP3 play list; processing special work files; loading documents into your own mini word processor. The possibilities are endless.



Click here for a larger image.

Dragging and dropping from Windows Explorer

Capturing the Screen, Quick and Easy

When it comes to showing people how to capture the screen, most VB.NET authors I've seen tend to revert to the old-school method of working: using the API. There is, however, a better way.

The following function is called GetScreenCapture and returns an Image object. It captures the screen by running a series of "Print Screen" key presses, which puts a screen grab on the Clipboard, ready for my nifty little function to devour and return. My function accepts a FullScreen argument, too: Pass True to capture the whole screen, or False to capture just the active window.

Here's the code:

Public Function GetScreenCapture( _
   Optional ByVal FullScreen As Boolean = False) As Image
   ' Captures the current screen and returns as an Image
   ' object
   Dim objSK As SendKeys
   Dim imgCapture As Image
   If FullScreen = True Then
       ' Print Screen pressed twice here as some systems
       ' grab active window "accidentally" on first run
       objSK.SendWait("{PRTSC 2}")
   Else
       objSK.SendWait("%{PRTSC}")
   End If
   Dim objData As IDataObject = Clipboard.GetDataObject()
   Return objData.GetData(DataFormats.Bitmap)
End Function

And here are a couple of examples demonstrating how to use that Image object—firstly, saving it as a file; and secondly, using it to set the Image property of a PictureBox control:

GetScreenCapture(True).Save("c:\screengrab.bmp")
PictureBox1.Image = GetScreenCapture()

My sample application, capturing the active window (again and again)

Next Time

Coming up in part three of Windows Secrets, check out:

  • How to 'Reset' a Form
  • The Facts on Visual Inheritance
  • Secrets of Working with the System Tray
  • Best of All Worlds: Creating an Ultra-Thin Client

See you next time!

# # #

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date