Windows Mobile 5.0 comes with a Web Browser (v6 is due out any day now). It runs on Pocket PCs and SmartPhones. That browser only allows one web page to show at a time: to show another page, you have to navigate away from the current page. I created a web browser for my first SmartPhone over a year ago that allows you to open multiple web pages.
If you have Visual Studio 2008 (or 2005), you can do it too, with the few hundred lines of code below.
This sample WebBrowser features:
Start VS 2008 (or 2005). Choose File->New->Project->Visual Basic->Smart Device Project->Ok.
(You can also run this same sample as a standard VB Windows Form application to see it running on your PC. File->New->Project->Visual Basic->Windows->Windows Forms Application. You can actually have 2 projects in one solution: one for the SmartPhone, one for your PC, both sharing the same code: PhoneBrowser.vb. Then you can right click on the desired project and Set As Startup Project. Be careful of having 2 copies of the code: One copy actually references the Compact .Net Framework, and is in a different project type).
In the wizard that shows, choose Target Platform: Windows Mobile 5.0 Smartphone SDK, and Templates: Device Application
In Solution Explorer, Delete Form1, then add a new Class called "PhoneBrowser.vb"
Paste the code below.
In Project Properties, choose Application->Startup Object: PhoneBrowser
Hit F5 to build and run the program. A dialog comes up: choose either smart phone emulator. The first time, it takes a few seconds to deploy the .Net Framework 3.5.
Notes: use Tools->Device Emulation Manager to hook up the emulator to your network, so it can browse web sites. Right click on the emulator you chose and choose "Cradle" to attach the emulator electronically to your PC (like putting the phone into a cradle that's attached via cable). Otherwise you'll get "Your Internet connection is not configured properly. Please verify your settings in Data Connections"
Install Microsoft ActiveSync 4.5, run it, and choose File->Connection Settings->Connect to sync the emulator to the PC. This is not required, but will allow you to have your emulator connect to the web while it's cradled.
You can change the Output File folder where the application is stored: Project->Properties->Devices->Output File Folder. It defaults to %CSIDL_PROGRAM_FILES%\SmartDeviceProject1
The sample doesn't show History: if you figure that out, let me know. Otherwise, I may just create a SQL Server CE database and store the links in there….
If you're using VS 2005, you'll get several VB compile errors that you can fix due to new features in VB.Net 2008
The F1,F2 buttons on your keyboard map to the left and right soft keys of the phone.
To deploy on a real SmartPhone, connect via ActiveSync and choose Project->Properties->Devices->Target Device: Windows Mobile 5.0 Smartphone Device, then hit F5. You'll get some confirmation dialogs on your phone.
You can use Linq on your SmartPhone in VS 2008: if you get an error creating a simple query, Project->Properties: add a reference to c:\Program Files\Microsoft.Net\SDK\CompactFramework\V3.5\WindowsCE\System.Core.dll, and import System.Core and System.Xml
You may have to unlock your phone: http://blogs.conchango.com/stuartpreston/archive/2005/11/10/2376.aspx
See also:
Customize your Windows Mobile SmartPhone home screen and Start Menu
How to: Use the WebBrowser Control in the .NET Compact Framework
Smartphone Development and the .NET Compact Framework
Windows Mobile 5.0 Application Security
Windows Mobile-based Smartphone Applications Deployment Demystified
Device Security Manager Powertoy for Windows Mobile 5.0
Remove double spaces from pasted code samples in blog
Visual Studio->Tools menu->Device Security Manager
Lots of goodies under Start Menu->Visual Studio 2008->Remote Tools, like Remote Registry Editor, Remote Process Viewer, Remote File Viewer
Start of Code
Public Class PhoneBrowser
Inherits Form
#If Smartphone = True Then 'auto set: Project->Properties->Compile->Advanced Compile Options->Custom Constants
Dim fSmartPhone = True
#Else
Dim fSmartPhone = False
#End If
Friend WithEvents WebBrowserCtrl As System.Windows.Forms.WebBrowser
Shared oBrowserForms As New System.Collections.Generic.List(Of PhoneBrowser)
Private Sub PhoneBrowser_Load() Handles MyBase.Load
Me.WebBrowserCtrl = New Windows.Forms.WebBrowser
Me.WebBrowserCtrl.Dock = DockStyle.Fill
Me.WebBrowserCtrl.DocumentText = "<html>Custom Web Browser for Smartphone by Calvin Hsia</html>" ' put your name here
Me.Controls.Add(Me.WebBrowserCtrl)
Me.Text = "PhoneBrowser"
If fSmartPhone Then
Me.WindowState = FormWindowState.Maximized
Else
Me.Size = New Size(1280, 1024)
End If
oBrowserForms.Add(Me) ' add ourselves to the collection
If oBrowserForms.Count = 1 Then ' if it's the first instance
Me.WebBrowserCtrl.Navigate(New System.Uri("http://www.msn.com"))
'ShowFavorites()
If Not fSmartPhone Then
ShowMenu()
End Sub
Private Sub PhoneBrowser_FormClosing(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Closing
For i = 1 To oBrowserForms.Count
If oBrowserForms.Item(i - 1) Is Me Then ' remove ourselves from the list
oBrowserForms.RemoveAt(i - 1)
Exit For
Next
Private Sub PhoneBrowser_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
If e.KeyCode = System.Windows.Forms.Keys.F1 OrElse _
e.KeyCode = System.Windows.Forms.Keys.F2 Then
If e.KeyCode = Keys.Back Then
If WebBrowserCtrl.CanGoBack Then
WebBrowserCtrl.GoBack()
Sub ShowMenu()
Me.Menu = New MainMenu
Dim mItem As MyMenuItem
Dim mItemBar As MyMenuItem 'the 2 softkeys
Dim mItemNav As MyMenuItem
If Me.WebBrowserCtrl.ReadyState <> WebBrowserReadyState.Complete Then
mItemBar = New MyMenuItem("Stop Request", Me.Menu.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItemBar = New MyMenuItem("Favorites", Me.Menu.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItemBar = New MyMenuItem("Menu", Me.Menu.MenuItems)
mItem = New MyMenuItem("Address Bar", mItemBar.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItem = New MyMenuItem("Add to Favorites", mItemBar.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItemNav = New MyMenuItem("Navigate", mItemBar.MenuItems)
mItem = New MyMenuItem("Favorites", mItemNav.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItem = New MyMenuItem("Go Forward", mItemNav.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItem.Enabled = Me.WebBrowserCtrl.CanGoForward
mItem = New MyMenuItem("Go Back", mItemNav.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItem.Enabled = Me.WebBrowserCtrl.CanGoBack
mItem = New MyMenuItem("Cancel Menu", mItemBar.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItem = New MyMenuItem("Refresh", mItemBar.MenuItems, AddressOf Me.BrowserMenuItem_Click) ' keep in pos 5
mItem = New MyMenuItem("New Window", mItemBar.MenuItems, AddressOf Me.BrowserMenuItem_Click)
mItem = New MyMenuItem("Switch Windows", mItemBar.MenuItems)
If oBrowserForms.Count = 1 Then
mItem.Enabled = False
If Not oBrowserForms(i - 1) Is Me Then ' don't add ourself
Dim mText As String
Dim oUri = oBrowserForms(i - 1).WebBrowserCtrl.Url
If oUri Is Nothing Then
mText = "Form " + i.ToString
If oUri.ToString.ToLower.StartsWith("http://") Then
mText = oUri.ToString.Substring(7)
mText = oUri.ToString
Dim MenuItemBrowserInstance = New MyMenuItem(mText, mItem.MenuItems, AddressOf MenuItemNewFormHandler_Click)
MenuItemBrowserInstance.oBrowser = oBrowserForms(i - 1)
mItem = New MyMenuItem("Exit", mItemBar.MenuItems, AddressOf Me.BrowserMenuItem_Click)
Sub BrowserMenuItem_Click(ByVal o As MyMenuItem, ByVal e As System.EventArgs)
Me.Menu = Nothing ' make menu disappear
Select Case o.Text
Case "Stop Request"
Me.WebBrowserCtrl.Stop()
ShowMenu() ' refresh menu
Case "Favorites"
ShowFavorites()
Case "Address Bar"
Dim oAddrBarForm = New FormAddressBar(Me)
If oAddrBarForm.ShowDialog() = Windows.Forms.DialogResult.OK Then
Try
Me.WebBrowserCtrl.Navigate(New System.Uri(oAddrBarForm.Result))
Catch ex As Exception
MsgBox(oAddrBarForm.Result, MsgBoxStyle.OkOnly, "Invalid URL")
End Try
Case "Add to Favorites"
ShowAddFavoriteForm(Me, o.Text)
Case "Go Forward"
Me.WebBrowserCtrl.GoForward()
Case "Go Back"
Me.WebBrowserCtrl.GoBack()
Case "Refresh"
Me.WebBrowserCtrl.Refresh()
Case "Cancel Menu"
'do nothing
Case "New Window"
Dim NewWindow = New PhoneBrowser
Dim cUrl = ""
If Not Me.WebBrowserCtrl.Url Is Nothing Then
cUrl = Me.WebBrowserCtrl.Url.ToString
NewWindow.Show()
NewWindow.WebBrowserCtrl.Navigate(New System.Uri(cUrl)) ' new instance goes to same page
Case "Exit"
Me.Close()
Case Else
MsgBox("Menu item " + o.Text + " not handled")
End Select
Sub ShowFavorites()
Dim oFavForms As New FormFavorites(Me)
If oFavForms.ShowDialog() = Windows.Forms.DialogResult.OK AndAlso oFavForms.Result.Length > 0 Then
Me.WebBrowserCtrl.Navigate(New System.Uri(oFavForms.Result))
MsgBox(oFavForms.Result, MsgBoxStyle.OkOnly, "Error in URL")
Shared Sub ShowAddFavoriteForm(ByVal oPhoneBrowser As PhoneBrowser, _
ByVal cTitle As String, _
Optional ByVal cName As String = "", _
Optional ByVal cUrlSpecific As String = "", _
Optional ByVal cOrigFileName As String = "")
'SmartPhone webbrowser doesn't have Document property
Dim cHost = cName
Dim cUrl = cUrlSpecific
If Not oPhoneBrowser.WebBrowserCtrl.Url Is Nothing AndAlso cTitle <> "Edit" Then
cHost = oPhoneBrowser.WebBrowserCtrl.Url.Host
cUrl = oPhoneBrowser.WebBrowserCtrl.Url.ToString
Dim oAddFav As New FormAddToFavorites(cHost, cUrl, cTitle, cOrigFileName)
If oAddFav.ShowDialog = Windows.Forms.DialogResult.OK Then
Sub MenuItemNewFormHandler_Click(ByVal o As MyMenuItem, ByVal e As System.EventArgs)
Me.Menu = Nothing
o.oBrowser.Show()
Class MyMenuItem ' same as MenuItem, except a place to put a reference to the instance
Inherits MenuItem
Public oBrowser As PhoneBrowser
Sub New(ByVal cText As String, ByRef mi As MenuItemCollection, _
Optional ByVal handler As System.EventHandler = Nothing)
Me.Text = cText
mi.Add(Me)
If Not handler Is Nothing Then
AddHandler Me.Click, handler
End Class
Private Sub WebBrowserCtrl_DocumentCompleted(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowserCtrl.DocumentCompleted
Me.Text = Me.WebBrowserCtrl.Url.ToString
Shared Function GetFavoritesFolder() As String 'called from outside the class, so "shared"
GetFavoritesFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Favorites)
GetFavoritesFolder = "\Windows\Favorites"
End Function
Class FormAddressBar
Inherits Windows.Forms.Form
Dim WithEvents txtAddr As New TextBox
Dim WithEvents lvAddr As New ListView
Public Result As String = ""
Dim IsListBoxChanging As Boolean = False
Dim oPhoneBrowser As PhoneBrowser
Sub New(ByVal oPhoneBrowser As PhoneBrowser)
Me.oPhoneBrowser = PhoneBrowser
Dim MenuMain As Menu
Dim MItem As MyMenuItem
MenuMain = New MainMenu
MItem = New MyMenuItem("Go", MenuMain.MenuItems, AddressOf AddrBarMenuItem_Click)
MItem = New MyMenuItem("Cancel", MenuMain.MenuItems, AddressOf AddrBarMenuItem_Click)
Me.Menu = MenuMain
If Not PhoneBrowser.WebBrowserCtrl.Url Is Nothing Then
txtAddr.Text = PhoneBrowser.WebBrowserCtrl.Url.ToString
txtAddr.Left = 10
txtAddr.Width = 300
txtAddr.Visible = True
Me.Controls.Add(txtAddr)
txtAddr.SelectionStart = txtAddr.Text.Length ' put cursor at end
lvAddr.View = View.List
lvAddr.Visible = True
lvAddr.Top = 30
lvAddr.Width = 300
Me.Controls.Add(Me.lvAddr)
RefreshListbox()
Sub AddrBarMenuItem_Click(ByVal o As MyMenuItem, ByVal e As System.EventArgs)
Case "Go"
GoAddrBar()
Me.DialogResult = Windows.Forms.DialogResult.OK
Me.Result = IIf(Me.txtAddr.Text.StartsWith("http://"), "", "http://") + Me.txtAddr.Text
Case "Cancel"
Me.DialogResult = Windows.Forms.DialogResult.Cancel
Sub RefreshListbox()
Me.lvAddr.Items.Clear()
lvAddr.Items.Add(New MyListViewItem(Me.txtAddr.Text + ".com"))
lvAddr.Items.Add(New MyListViewItem(Me.txtAddr.Text + ".org"))
Private Sub txtAddr_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtAddr.TextChanged
If Not IsListBoxChanging Then
Private Sub lvAddr_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lvAddr.Click
Private Sub lvAddr_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles lvAddr.KeyDown
Select Case e.KeyCode
Case Keys.Up
If lvAddr.Items(0).Selected Then
lvAddr.Items(0).Selected = False
Me.txtAddr.Focus()
Case Keys.Down
If lvAddr.Items(lvAddr.Items.Count - 1).Selected Then
lvAddr.Items(lvAddr.Items.Count - 1).Selected = False
Case Keys.Enter
Sub GoAddrBar()
Private Sub lvAddr_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lvAddr.SelectedIndexChanged
If Me.lvAddr.SelectedIndices.Count = 1 Then
IsListBoxChanging = True
Me.txtAddr.Text = Me.lvAddr.Items(Me.lvAddr.SelectedIndices.Item(0)).Text
IsListBoxChanging = False
Public Class FormFavorites
Dim WithEvents ListView As Windows.Forms.ListView
Me.oPhoneBrowser = oPhoneBrowser
Me.ListView = New Windows.Forms.ListView
Me.ListView.Dock = DockStyle.Fill
Me.ListView.View = View.List
FillFavList(GetFavoritesFolder())
mItemBar = New MyMenuItem("Go", Me.Menu.MenuItems, AddressOf Me.FavMenuItem_Click)
mItem = New MyMenuItem("Address Bar", mItemBar.MenuItems, AddressOf Me.FavMenuItem_Click)
mItem = New MyMenuItem("Add Favorite", mItemBar.MenuItems, AddressOf Me.FavMenuItem_Click)
mItem = New MyMenuItem("Add Folder", mItemBar.MenuItems, AddressOf Me.FavMenuItem_Click)
mItem = New MyMenuItem("Edit", mItemBar.MenuItems, AddressOf Me.FavMenuItem_Click)
mItem = New MyMenuItem("Delete", mItemBar.MenuItems, AddressOf Me.FavMenuItem_Click)
mItem = New MyMenuItem("Cancel", mItemBar.MenuItems, AddressOf Me.FavMenuItem_Click)
Me.ListView.Visible = 1
Me.Controls.Add(Me.ListView)
Sub FillFavList(ByVal BaseFolder As String) 'todo: add icons
Me.ListView.Clear()
Dim FavoriteFiles = From FileName In IO.Directory.GetFiles(BaseFolder) Order By FileName
Dim FavoriteFolders = From FolderName In IO.Directory.GetDirectories(BaseFolder) Order By FolderName
'Dim FavoriteFolders = IO.Directory.GetDirectories(BaseFolder)
'Dim FavoriteFiles = IO.Directory.GetFiles(BaseFolder)
'System.Array.Sort(FavoriteFolders) 'ListView.Sort not available
'System.Array.Sort(FavoriteFiles) ' could use Linq
For Each File In FavoriteFiles
Dim FavTxt = File.Substring(BaseFolder.Length + 1).Replace(".url", "")
Me.ListView.Items.Add(New MyListViewItem(FavTxt, File))
For Each FolderName In FavoriteFolders
Dim FavTxt = "Folder: " + FolderName.Substring(BaseFolder.Length + 1)
Me.ListView.Items.Add(New MyListViewItem(FavTxt, FolderName, True))
If GetFavoritesFolder() <> BaseFolder Then
Me.ListView.Items.Add(New MyListViewItem("..[Parent]", System.IO.Path.GetDirectoryName(BaseFolder), True))
If Me.ListView.Items.Count > 0 Then ' if there are any
Me.ListView.Items(0).Selected = True ' select 1st one
Sub FavMenuItem_Click(ByVal o As MenuItem, ByVal e As System.EventArgs)
GoFavorite()
Dim oAddrBarForm = New FormAddressBar(oPhoneBrowser)
Me.Result = oAddrBarForm.Result
Case "Add Favorite"
ShowAddFavoriteForm(oPhoneBrowser, o.Text)
FillFavList(GetFavoritesFolder) ' refresh list
Case "Add Folder"
Dim oAddNewFolder = New FormAddNewFavFolder
If oAddNewFolder.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim cNewFolder = GetFavoritesFolder() + IO.Path.DirectorySeparatorChar + oAddNewFolder.txtName.Text
IO.Directory.CreateDirectory(cNewFolder)
MsgBox(cNewFolder, MsgBoxStyle.OkOnly, "Error Creating Folder")
Case "Edit"
Dim nIndex = Me.ListView.SelectedIndices.Item(0)
Dim lvItem = CType(Me.ListView.Items(nIndex), MyListViewItem)
If Not lvItem.fFolder Then
ShowAddFavoriteForm(Me.oPhoneBrowser, o.Text, lvItem.Text, GetUrlFromFavoriteFile(lvItem.Tag), lvItem.Tag)
Case "Delete"
If lvItem.fFolder Then
IO.Directory.Delete(lvItem.Tag)
IO.File.Delete(lvItem.Tag)
MsgBox(lvItem.Tag, MsgBoxStyle.OkOnly, "Error Deleting Folder")
Function GetUrlFromFavoriteFile(ByVal cFile As String)
'[InternetShortcut]
'URL=http://mobile.msn.com/pocketpc
Dim fHandle = System.IO.File.OpenText(cFile)
Do While Not fHandle.EndOfStream
Dim cLine = fHandle.ReadLine
If cLine.StartsWith("URL=") Then
cUrl = cLine.Substring(4)
Exit Do
Loop
fHandle.Close()
Return cUrl
Sub GoFavorite()
If Me.ListView.SelectedIndices.Count = 1 Then
FillFavList(lvItem.Tag)
Result = GetUrlFromFavoriteFile(lvItem.Tag)
Private Sub ListView_Click1(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListView.Click
Private Sub ListView_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ListView.KeyDown
If e.KeyCode = Keys.Enter Then
Class FormAddNewFavFolder
Dim lblName As New Label
Public txtName As New TextBox
Sub New()
AddCtrl(Me, lblName, 0, "Name:")
AddCtrl(Me, txtName, 30, "")
Me.Text = "Add Folder to Favorites"
Dim mItem = New MyMenuItem("Add", Me.Menu.MenuItems, AddressOf AddFolderMenuItemClick)
mItem = New MyMenuItem("Cancel", Me.Menu.MenuItems, AddressOf AddFolderMenuItemClick)
Sub AddFolderMenuItemClick(ByVal o As MyMenuItem, ByVal e As System.EventArgs)
Case "Add"
If Me.txtName.Text.Length > 0 Then
End Class 'FormAddNewFavFolder
End Class 'FormFavorites
Shared Function AddCtrl(ByVal oForm As Form, ByVal oCtrl As Windows.Forms.Control, ByVal nTop As Integer, ByVal cText As String) As Control
oCtrl.Top = nTop
oCtrl.Left = 10
oCtrl.Width = 300
oCtrl.Text = cText
oCtrl.Visible = True
oForm.Controls.Add(oCtrl)
Return oCtrl
Class FormAddToFavorites
Dim txtName As New TextBox
Dim lblAddr As New Label
Dim txtAddr As New TextBox
Dim lblFolder As New Label
Dim cboFolder As New ComboBox
Dim cOrigFileName As String = ""
Sub New(ByVal FavTitle As String, ByVal cUrl As String, ByVal cTitle As String, _
ByVal cOrigFileName As String)
Me.cOrigFileName = cOrigFileName
AddCtrl(Me, txtName, 30, FavTitle)
AddCtrl(Me, lblAddr, 60, "Address(URL):")
AddCtrl(Me, txtAddr, 90, cUrl)
AddCtrl(Me, lblFolder, 120, "Folder:")
cboFolder.Items.Add("Favorites")
Me.Text = cTitle
Dim FavoriteFolder = GetFavoritesFolder()
Dim FavoriteSubFolders = IO.Directory.GetDirectories(FavoriteFolder)
For Each FolderName In FavoriteSubFolders
cboFolder.Items.Add(FolderName.Substring(FavoriteFolder.Length + 1))
AddCtrl(Me, cboFolder, 150, "Favorites")
txtAddr.SelectionStart = cUrl.Length
Dim mItem = New MyMenuItem("Done", Me.Menu.MenuItems, AddressOf AddFavMenuItemClick)
mItem = New MyMenuItem("Cancel", Me.Menu.MenuItems, AddressOf AddFavMenuItemClick)
Sub AddFavMenuItemClick(ByVal o As MyMenuItem, ByVal e As System.EventArgs)
Case "Done"
If cOrigFileName.Length > 0 Then
IO.File.Delete(cOrigFileName)
Dim cPath = GetFavoritesFolder()
If cboFolder.Text <> "Favorites" Then ' only 1 level deep supported
cPath += IO.Path.DirectorySeparatorChar + cboFolder.Text
cPath += IO.Path.DirectorySeparatorChar + Me.txtName.Text + ".url"
Dim fs = IO.File.CreateText(cPath)
fs.WriteLine("[InternetShortcut]")
fs.WriteLine("URL=" + Me.txtAddr.Text)
fs.Close()
Class MyListViewItem
Inherits ListViewItem
Public fFolder As Boolean
Sub New(ByVal cItem As String, Optional ByVal oTag As Object = Nothing, Optional ByVal IsFolder As Boolean = False)
Me.Tag = oTag
Me.Text = cItem
fFolder = IsFolder
End of Code