Author Archive

Creating and deploying Managed COM add-ins with VB.NET 2005 – Part III

Creating and deploying Managed COM add-ins with VB.NET 2005 – Part III

This is the third post on the subject and You can find the earlier post at the following links:
Part I – Introduction
Part II – Connecting

For all code posted here I have intentionally tried to avoid a) the core .NET-approach and b) the use of classes. Instead I have tried to focus on clarity and to use a simple classic VB/VBA -approach.

The Notes Tool – Handle workbooks
With this post I will start to cover the tool itself which target on sending workbooks or worksheets as attachments to outgoing e-mails with Lotus Notes. The first option is to send workbooks as attachments and below is the form that provides end users with an interface to populate required parameters:

Notes Workbooks

The code
The following code is part of the above form where only the most vital parts are showed.

‘The following namesspaces are required for the code behind the form.
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Windows.Forms

When the form is initialized the following procedure populates some items of the form:

Private Sub frmwbook_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
            ‘Create the collection of items for the priority status.
           ‘I have not discovered any smooth way to align items in a combobox…
           Dim Priority() As String = _
                            New String() {”    Low”, ”    Normal”,  ”    High”}
            With Me.ComboBoxPriority
                ‘Populate the combobox with the collection.
               .Items.AddRange(Priority)
                ‘Select ‘Normal’ as default value.
               .SelectedIndex = 1
            End With
            ‘Title
           Me.Text = g_CONST_TITLE
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

Below is the code for adding workbooks and we also need to add the ‘OpenFileDialog’ control to the form:

Private Sub ButtonAttachFiles_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonAttachFiles.Click
        Try
            ‘Let the users select wanted Excel files
           ‘to be attached to the outgoing e-mail.
           With Me.OpenFileDialog_Workbooks
                .Title = “Select workbook(s) to send as attachment(s) to e-mail”
                .Multiselect = True
                .Filter = “Excel files (*.xls)|*.xls|Excel files (*.xls)|*.xls”
                If .ShowDialog() = Windows.Forms.DialogResult.OK Then
                    Me.ListBox_Files.Items.AddRange(.FileNames)
                End If
            End With
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

To remove workbooks the following procedure is used:

Private Sub ButtonRemoveFiles_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonRemoveFiles.Click
        Dim iCounter As Integer
        For iCounter = Me.ListBox_Files.SelectedItems.Count – 1 To 0 Step -1
            Me.ListBox_Files.Items.Remove(Me.ListBox_Files.SelectedItems(iCounter))
        Next iCounter
    End Sub

To add recipients the following procedure is used. A similar code is used to add the list of recipients for ‘Copy To’.

    Private Sub ButtonAddFromRangeSendTo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonAddFromRangeSendTo.Click
        Try
            ‘The RefEdit object is not available in .NET
           ‘so instead the Inputbox is used.
           ‘The Excel variables are declared in a standardmodule.
           g_xlRng = CType(g_xlApp.InputBox( _
           “Please select the range that contain the list of recipients as Copy To:”, _
                                 g_CONST_TITLE, , , , , ,   8), Excel.Range)
            g_xlcell = CType(g_xlRng.Cells, Excel.Range)
            Try
                ‘Add recipients to the list of Send To.
               If Not g_xlRng.Columns.Count > 1 Then
                    With Me.ListBox_SendTo
                        .Items.Clear()
                        For Each g_xlcell In g_xlRng
                            If Not (g_xlcell.Value) Is Nothing Then _
                                          .Items.Add(g_xlcell.Value)
                        Next g_xlcell
                    End With
                Else
                    MsgBox(“The list of recipients can only be in one column.”, _
                                      MsgBoxStyle.Information, g_CONST_TITLE)
                    Exit Sub
                End If
            Catch ex As Exception
                MessageBox.Show(ex.ToString, g_CONST_TITLE)
            End Try
        Catch ex As Exception
            ‘Leave empty – it takes care of the cancel for the inputbox.
       Finally
            ‘Release the objects.
           If Not g_xlcell Is Nothing Then g_xlcell = Nothing
            If Not g_xlRng Is Nothing Then g_xlRng = Nothing
        End Try
    End Sub

The following code is associated with the Send e-mail button:

Private Sub ButtonSendEmail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSendEmail.Click
        ‘Check that all entries are done before continuing the process.
       If Me.ListBox_Files.Items.Count = 0 Then
            MsgBox(“Please add at least one Excel file to be sent with the e-mail.”, _
            MsgBoxStyle.Information, g_CONST_TITLE)
            Me.ButtonAttachFiles.Focus()
            Exit Sub
        ElseIf Len(Me.TextBox_Subject.Text) = 0 Then
            MsgBox(“Please enter a subject.”, MsgBoxStyle.Information, g_CONST_TITLE)
            Me.TextBox_Subject.Focus()
            Exit Sub
        ElseIf Me.ListBox_SendTo.Items.Count = 0 Then
            MsgBox(“Please add at least one reciepent to send the e-mail to.”,  _
            MsgBoxStyle.Information, g_CONST_TITLE)
            Me.ButtonAddFromRangeSendTo.Focus()
            Exit Sub
        ElseIf Len(Me.TextBox_Message.Text) = 0 Then
            MsgBox(“Please add a comment to the e-mail.”, _
            MsgBoxStyle.Information, g_CONST_TITLE)
            Me.TextBox_Message.Focus()
            Exit Sub
        End If
        Try
            ‘Retrieve the subject for the e-mail.
           Dim stSubject As String = Me.TextBox_Subject.Text
            ‘Retrieve the message of the e-mail.
           Dim stMsg As String = Me.TextBox_Message.Text
            ‘Retrieve the priority of the e-mail.
           Dim stPriority As String = LTrim(Me.ComboBoxPriority.Text)
            ‘Grab the list of workbooks.
           Dim oFiles(Me.ListBox_Files.Items.Count – 1) As Object
            Me.ListBox_Files.Items.CopyTo(oFiles, 0)
            ‘Grab the list of recipients of Send To.
           Dim oSendTo(Me.ListBox_SendTo.Items.Count – 1) As Object
            Me.ListBox_SendTo.Items.CopyTo(oSendTo, 0)
            ‘Grab the list of recipients of Copy To.
           Dim oCopyTo(Me.ListBox_CopyTo.Items.Count – 1) As Object
            Me.ListBox_CopyTo.Items.CopyTo(oCopyTo, 0)
            ‘Create and send the e-mail, calls a function in a standardmodule.
           If Create_Email_Notes( _
            stPriority, stSubject, oSendTo, oCopyTo, stMsg, False, , oFiles) _
            = True Then
            MessageBox.Show(“The e-mail was successfully created and has been sent.”, _
                g_CONST_TITLE, MessageBoxButtons.OK)
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, g_CONST_TITLE)
        Finally
            Me.Close()
        End Try
    End Sub

By adding a LinkLabel control to the form we can add a Web-style link to the form.

In the next post I will cover the solution for worksheets in detail.

Kind regards,
Dennis

Creating and deploying Managed COM add-ins with VB.NET 2005 – Part II

Creating and deploying Managed COM add-ins with VB.NET 2005 – Part II
This is the second post about the subject and please see the previously post at the following URL: Part1 – Introduction
For all code posted here I have intentionally tried to avoid a) the core .NET-approach and b) the use of classes. Instead I have tried to focus on clarity and to use a simple classic VB/VBA -approach.

What is the Shared add-in?
In my opinion the following quote defines the Shared add-in a good way:
“The Extensibility Wizard creates a Visual Basic .NET class library project along with a Connect class that implements the IDTExtensibility2 interface. The skeleton code that implements the empty members of IDTExtensibility is also generated. This project has references to Extensibility and Office assemblies. The build settings of the project have Register for COM Interop selected. Along with the class library project, the wizard generates a setup project that you can use to deploy the COM add-in on other computers.” – See How To Build an Office COM Add-in by Using Visual Basic .NET

The wizard also provide a step to determine the loadbehavior where load on startup of Excel is the default value, i e the value of 3 (1 = Connect + 2 = Bootload (Load on Excel startup).

Debug configuration
Before starting to debug we must make sure that we use Excel by changing the default setting of ‘Start external program’ under the Debug Tab and point to the Excel.exe file. The easiest way to do it is to right click on ‘My project’ in the Solution Explorer windows and then select the Debug tab.

The code for connection to Excel and creating the commandbar
Below is the code in the ‘Connect’-class module where only the vital parts are showed:

‘Make sure that all the wanted references have been set up before doing the imports.
Imports Excel = Microsoft.Office.Interop.Excel ‘To access Excel’s objects.
Imports Office = Microsoft.Office.Core ‘To access Office’s objects.
Imports System.Windows.Forms ‘To access the MessageBox.
Imports Extensibility ‘The IDTExtensibility2 interface.
Imports System.Runtime.InteropServices ‘Defines the GuidAttribute and ProgIdAttribute and to release objects.

<guidattribute (“D5BD9535-51A5-444E-BB23-B83F93C4FB30″), ProgIdAttribute(“NotesTool.Connect”)> _
Public Class Connect

    Implements Extensibility.IDTExtensibility2
    Private Const CONST_TAG As String = “Lotus E-Mail”
    Private Const CONST_PARA_WBOOK As String = “Book”
    Private Const CONST_PARA_WSHEET As String = “Sheet”
    Private Const CONST_PARA_HELP As String = “Help”
    Private Const CONST_PARA_ABOUT As String = “About”
    Private oLotusCommandBar As Office.CommandBar
    Private oBtn As Office.CommandBarButton
    ‘To handle the variable’s click event.
   Private WithEvents cbLotusBtn As Office.CommandBarButton

    Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection
        Try
            ‘Remove the temporarily custom commandbar.    
           If Not (oLotusCommandBar Is Nothing) Then oLotusCommandBar.Delete()
        Catch ex As Exception
            MessageBox.Show(ex.ToString, g_CONST_TITLE)
        Finally
           ‘Place variables to be handled by the Garbage Collector (GC).    
           oLotusCommandBar = Nothing
            cbLotusBtn = Nothing
            g_xlcell = Nothing
            g_xlRng = Nothing
            g_xlwsSheet = Nothing
            g_xlwbBook = Nothing
            g_xlApp = Nothing
         End Try
    End Sub

    Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
        Try
            ‘Make sure that the temporarily custom commandbar does not exist.
           If Not (oLotusCommandBar Is Nothing) Then oLotusCommandBar.Delete()
            ‘Cast the main object – declared in a standard module.
           xlApp = CType(application, Excel.Application)
            ‘Create the temporarily commandbar.
           oLotusCommandBar = CType(xlApp.CommandBars.Add(Name:=CONST_TITLE, _
                                                    Position:=Office.MsoBarPosition.msoBarTop, _
                                                    Temporary:=True), Office.CommandBar)
            With oLotusCommandBar
                ‘Add a new button.
               oBtn = CType(.Controls.Add( _
                                            Office.MsoControlType.msoControlButton), _
                                            Office.CommandBarButton)
                ‘Add values to the created new button.
               With oBtn
                    .BeginGroup = True
                    .Caption = “Send Workbooks”
                    .FaceId = 1086
                    .Parameter = CONST_PARA_WBOOK
                    .Style = Office.MsoButtonStyle.msoButtonIconAndCaption
                    .Tag = CONST_TAG
                    .TooltipText = “Send selected workbooks as attachments.”
                End With
                ‘Add an additional new button.
               oBtn = CType(.Controls.Add( _
                                            Office.MsoControlType.msoControlButton), _
                                            Office.CommandBarButton)
                ‘Add values to the created new button.
               With oBtn
                    .BeginGroup = True
                    .Caption = “Send Worksheets”
                    .FaceId = 8
                    .Parameter = CONST_PARA_WSHEET
                    .Style = Office.MsoButtonStyle.msoButtonIconAndCaption
                    .Tag = CONST_TAG
                    .TooltipText = “Send selected worksheets as attachments.”
                End With
                ‘Add an additional new button.
               oBtn = CType(.Controls.Add( _
                                   Office.MsoControlType.msoControlButton), _
                                   Office.CommandBarButton)
                ‘Add values to the created new button.
               With oBtn
                    .BeginGroup = True
                    .FaceId = 984
                    .Caption = “Help”
                    .Parameter = CONST_PARA_HELP
                    .Style = Office.MsoButtonStyle.msoButtonIconAndCaption
                    .Tag = CONST_TAG
                    .TooltipText = “View the help for the tool.”
                End With
                ‘Add an additional new button.
               oBtn = CType(.Controls.Add( _
                                   Office.MsoControlType.msoControlButton), _
                                   Office.CommandBarButton)
                ‘Add values to the created new button.
               With oBtn
                    .BeginGroup = True
                    .FaceId = 611
                    .Caption = “About”
                    .Parameter = CONST_PARA_ABOUT
                    .Style = Office.MsoButtonStyle.msoButtonIconAndCaption
                    .Tag = CONST_TAG
                    .TooltipText = “About the tool.”
                End With
                ‘Make the commandbar visible.
               .Visible = True
            End With
            ‘Set the WithEvents to hook the created buttons, i e all buttons use the same Click event.
           cbLotusBtn = oBtn
        Catch ex As Exception
            MessageBox.Show(ex.ToString, g_CONST_TITLE)
        Finally
            ‘Release object.
           If Not (oBtn Is Nothing) Then oBtn = Nothing
        End Try
    End Sub

    Private Sub cbLotusBtn_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, ByRef CancelDefault As Boolean) Handles cbLotusBtn.Click
        Try
            ‘Find out which button the user clicked on.
           Select Case Ctrl.Parameter
                Case CONST_PARA_WBOOK
                    Dim frmwbook As New frmwbook
                    ‘By using the method ShowDialog instead of Show makes the
                   ‘form part of the active window.
                   frmwbook.ShowDialog()
                    If Not (frmwbook Is Nothing) Then frmwbook = Nothing
                Case CONST_PARA_WSHEET
                    Dim frmwsheet As New frmwsheet
                    frmwsheet.ShowDialog()
                    If Not (frmwsheet Is Nothing) Then frmwsheet = Nothing
                Case CONST_PARA_HELP
                    Try
                        Show_Help()
                    Catch ex As Exception
                        MessageBox.Show(ex.ToString, g_CONST_TITLE)
                    End Try
                Case CONST_PARA_ABOUT
                    Dim frmabout As New frmAbout
                    frmabout.ShowDialog()
                    If Not (frmabout Is Nothing) Then frmabout = Nothing
            End Select
        Catch ex As Exception
            MessageBox.Show(ex.ToString, g_CONST_TITLE)
        End Try
    End Sub
End Class

How to get the XP Windows styles for controls?
Despite the fact that I’m consider this to be ‘whistle & bells’ I respect customers who ask for it as it’s to be considered as a de facto standard. In classic VB (see Ivan Moala’s nice sample) and in VB.NET 2002/2003 the standard solution is to use a manifest. With VB.NET 2005 MSFT added a method to the Application object, which seems to not work with managed COM add-ins. My workaround is to use the Application object of the System.Windows.Forms namespace, which seems to work well. The following snippet code should be added to the OnConnection event and in the ‘Try’ part:

            System.Windows.Forms.Application.EnableVisualStyles()
            System.Windows.Forms.Application.DoEvents()

The created commandbar
The following image shows the commandbar after the above code has been executed:

Notes Tool

Comments: Compared with classic VB the above code does not differ so much.

Comments and suggestion on improvements are as usual most welcome. In the next post we will take a closer look on the Notes Tool.

Kind regards,
Dennis

Creating and deploying Managed COM add-ins with VB.NET 2005 – Part I

Creating and deploying Managed COM add-ins with VB.NET 2005 – Part I

I thought it would be of common interest to take a closer look into what VB.NET 2005 can offer when it comes to creating and deploying COM add-ins for Excel.

The evaluation will be in view of the following aspects:
- Creating a managed COM add-in
- Deploying a managed COM add-in

In order to create a useful tool I decided to challenge how to work with the Domino object class by using early binding to control Lotus Notes. The tool itself will make it possible to attach workbooks or worksheets to outgoing e-mails with Lotus Notes.

What does ‘Managed’ stand for?
All solutions that require the Common Language Runtime (CLR – part of the .NET Framework) are considered managed, which include all solutions developed with any tool in the Visual Studio.NET suite and with Visual Studio Tools for Office System (VSTO). Solutions developed with classic VB 6.0 and Excel’s VBA are unmanaged solutions.

Since Excel per se is an unmanaged environment we are, from a strictly technical point of view, about to create a managed solution which is supposed to be implemented on an unmanaged platform.

Anyway, for those of You who want to know more about the CLR the following URL provides a good introduction: The Common Language Runtime

Required tools and configuration
In order to create the COM add-in the following tools are required:

- Microsoft .NET Framework 2.0 and later *)
- The professional version of MS Visual Basic.NET 2005 and later in order to use the Shared Add-in template.
(Edit: It’s also available in the standard edition of VB.NET 2005. I don’t know if this template is available or not in the Express edition. It can be done without the template but that is beyond the scope of this post.)
- The Primary Interop Assemblies (PIA) for Microsoft Office 2003 *)
- Microsoft Excel 2003 and later *)
- Lotus Notes 7.01 and later in order to use the sample tool *)

*) Also required on the target computers in order to get the COM add-in to function properly.

Two important settings in VB.NET are:
Option Explicit On (Status by default)
Option Strict On (Not by default which force explicit narrowing conversions and also force early binding)

Comments:
Compared with classic VB we have a quite large overhead to deal with on the client’s machine due to the requirements. In order to install the PIA for Office 2003 it requires that the .NET Framework is installed first. The .NET Framework is not shipped with Windows XP or with any previously versions. All in all, it will in general require an installation of both of them on the targeting computers.

Option Strict On is the recommended setting to which I agree with.

Unlike with classic VB we can only specify one Excel version the add-in should work with due to the involvement of the PIA (and implicit the existence of the .NET Framework). So if we want to develop an add-in for version 2002 and 2003 of Excel we actually need to develop two similar solutions where we use the version specific PIA in each solution. The same should be valid when it comes to Excel 2000 although there exist no official PIA for this version.

I recently raised a question about this issue at David Gainer’s blog and received an answer that MSFT will make it possible to develop add-ins that work with 2003 and forward.

Of course, this is a seriously limitation for managed add-ins as COM add-ins per se should not be version specific in the first place.

Update Your .NET copy
Before doing anything else it’s recommended that You download and install the following fix:
Add-ins, smart documents, or smart tags that you create by using Microsoft Visual Studio 2005 do not run in Office

When the project has been created make sure You add the fix to the prerequisites list as the following picture shows:

KB908002

This is easiest done by right clicking on the SetUp project in the Solution Explorer Window and then select the menu option ‘Properties’.

In the next post we will take a closer look into the code to connect to Excel and create the custom commandbar .

Kind regards,
Dennis

Office as A Development platform

In an upcoming article in MSDN Magazine (August 2006) Andrew Whitechapel and Jon Peltonen discuss Office as a development platform from a broad perspective.

What You Need To Know About Using Office As A Development Platform

From my point of view it’s welcoming to take part of a ‘roadmap’ for Office as a development platform although we may not necessarily agree with all the content of it.

However, it’s regretful to take part of articles, books etc from MSFT where VBA, since the introduction of .NET/VSTO, is considered to be a non-professional tool…

Anyway, I hope that You find the article useful.

Kind regards,
Dennis

Measure & Evaluate The Quality of The Data

Measure & Evaluate The Quality of The Data

In view of the emergency trend to retrieve data from ERP systems and other similar central systems into Excel it has become important to discuss the quality of the retrieved data. Since all data is part of one or more decision processes the quality has an impact on the outputs of these processes.

From my point of view there exists a general dilemma with ERP systems and the process of registration the data, especially when it’s done manually. If the registration is dictating then some of the data may not be valid but since it’s required it’s filled in. If the registration is not dictating, i e users are allowed to leave fields empty, then some data will be left out.

When measuring the quality for data from a dictating system it’s very difficult to locate the less obviously errors (they can be inside a predefined range of values but still be wrong) while it’s much easier when data is left out.

In my experience most corporates ERP are dictating when it comes to order data, production data and staff data. For sales data they prefer less dictating reporting but on the other hand relies on that the data is revised and updated on regular basis to reflect the ongoing changes.

For me the purpose for measuring and evaluating the quality of the retrieved data is two folded:

-By presenting the quality of the data to the decision makers they get a better understanding of the viewed data and can better evaluate the performance indicators.

-By continuously measure the data quality focus can be set to improve it and in the long run it becomes a better input in the decision processes.

Of course, it’s always a trade off between what can be done or desirable and the costs involved.

In my experience it seems that we only need basic indicators for the quality as these kind of indicators can be viewed and understand throughout corporates.

How do You measure and evaluate the quality of retrieved data from ERP systems as well as from other central sources?

Kind regards,
Dennis

Ps: Before anyone asks for a case study I’m not able to provide any. Not even with the most simplified approach, as it would violate the present NDAs.

Web based services

Tushar Mehta brings up some interesting aspects on web based services in the Goggle spreadsheet post. Below is his post on the subject:

Over the past 3 years or so, every chance I’ve had I’ve asked people in MS to create a “web based Office-like product” that blurs the lines between existing apps. Instead it would consist of functional components, each of which could be used independent of the others or in conjunction — imagine if you will a OneNote “writing pad” where the “things” you put in wherever you want would be components from today’s overall Office suite — XL, Word, Outlook, PowerPoint, FrontPage, what-have-you.

Of course, since I never had a chance to talk with senior MS managers, it was obvious I was “whistling in the wind.”

When OfficeLive came along I briefly fantasized that someone in MS management had been thinking along the same lines as me. Unfortunately, OfficeLive seems to be another attempt to push SharePoint Services based products.

Now, maybe Google will deliver. I don’t want Writely and Google Desktop and GSheet and GMail and G Calendar and Google’s video site and…and…and… What I want is something way “outside the box.” Imagine a clean slate site where the stuff I can include are functional components: an InMail section here, an IM section there, a hidden reminders “window” that will “pop up” when needed, a ticker to keep an eye on the stock market (and maybe a “quick access to my brokerage to execute a trade” feature), a tiny space to watch streaming news channel (or even a regular TV channel), a space where I can work on a document — a document that contains text organized as I want, numbers in some tabular fashion in that area, a charting module that lets me create the kinds of charts I want (in one discussion with MS, I referred to it as “a police sketch artist for charts”), overall quality that approaches what one sees in magazines…the possibilities are endless…and, of course, all in an collaborative environment.

No, it won’t be free. And, no, I don’t have to buy everything all at once. If I don’t do magazine quality charts, I don’t buy that license. If I don’t do active stock trading, I don’t need the “rapid-access-to-broker” module.

But, what a world it would be!

I would welcome a workable business model that gives us the freedom to subscribe on online web services on demand and for which we pay for when used. Of course, it should include storage options that we can accept and trust in.

When I first heard about Office Live I also thought it would be something like web based Office System but a quick look made me disappointed as it was not even close to it.

MSFT is, as usual nowadays, ‘late to supper’. Their major concern is to please the present and future shareholders and increase the ROI on present platforms. Their upcoming focus will be on DSS, i e Decision Support Systems (the buzzword today is Business Intelligence, BI) . Later this year we will see their contribution to BI, Performancepoint Server (Analysis Service, Balance Scorecard, and a new tool called Biz #).

Google seems to put all their project to some endless beta-status, which may reflect the issue Google seems to have when it comes to find business model(s).

Perhaps a small and new company can push the well established vendors in the right direction with some powerful solution(s)? After all, competition gives us the best situation in the long run.

Another note is that the general opinion seems to be that everything on the Internet should be free. Perhaps it should be true for home users but certainly not for business users!

BTW, when You say ‘Out of the box’ the reply should be ‘What box?’ (OK, I picked that up from Bullen’s et al book) ;)

Kind regards,
Dennis

Tools to use with Excel

Tools to use with Excel

When MSFT release a beta of an upcoming version of Excel (like the present one for Excel 2007) many developers & users would like to test it but don’t have access to softwares like vmWare (which I use) and Virtual PC (which other may use). One option is to use Altiris Software Virtualization Solution (SVS), which create virtualized layers that can be used to test softwares with. Two versions exist, one free for strictly personal use and one for commercial use. It require Windows 2000 SP-4 and later. It’s strongly recommended to take part of and carefully read the documentation of the software.

My favourite tool to create screenshots with is SnagiT. However, this is a commercial software and therefore may not be available for everyone. So when You are testing the beta of Excel 2007 and get some weird errors on the screen You would like to report to MSFT then one option is to use Screenshot Captor which is a free tool. It’s highly recommended to read the online help.

Speaking about Excel 2007, don’t even think to run it with a screen resolution of 800×600. The best resolution would be 1280 x 1024 or higher due to the excellent UI.

Kind regards,
Dennis

Commercial use of SQL Server 2005 Express Edition?

Hi all,

It seems that SQL Server 2005 Express Edition now can be used for commercial purposes. The following link to a recent post SQL Server Express EULA at MSDN Forums seems to confirm it and apparently it’s applicable from SP1 and forward.

With all the respect for MDBs (so called ‘Access-databases’) but this major change in the EULA will make it very interesting to replace present MDBs with SQL Server 2005 EE. What’s Your opinion about it?

Startpage: SQL Server 2005 Express Edition

Kind regards,
Dennis

Excel & PDFCreator Take II

Hi all,

Ale recently posted in a comment in Excel & PDFCreator where he informed about another free utility, pdftk tool and below is an example on how we can control it via VBA:

Option Explicit
‘ AleV 20060516

‘ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
‘ API CALLS: Wait for a Process to Terminate
‘ http://www.thescarms.com/vbasic/wait.asp
‘ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Const SYNCHRONIZE = &H100000
Const INFINITE = &HFFFF
 ‘Wait forever
Const WAIT_OBJECT_0 = 0
 ‘The state of the specified object is signaled
Const WAIT_TIMEOUT = &H102
‘The time-out interval elapsed & the object’s state
‘is nonsignaled.

Private Declare Function OpenProcess Lib “kernel32″ (ByVal dwDesiredAccess As Long, _
            ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Private Declare Function WaitForSingleObject Lib “kernel32″ (ByVal hHandle As Long, _
            ByVal dwMilliseconds As Long) As Long

Private Declare Function CloseHandle Lib “kernel32″ (ByVal hObject As Long) As Long

Sub mergePdf(PdfDir As String, outdir As String)
    ‘ PdfDir: where the single pdf files are saved
   ‘ outdir: output folder
   
   
    Dim cmdApp As String
       
    Dim lPid As Long, lHnd As Long, lRet As Long
    cmdApp = “C:inpdftkpdftk.exe “ & PdfDir & “*.pdf cat output “ & _
    outdir & “” & Format(Now(), “yyyymmddhhmmss”) & “_MERGED_REPORT.pdf”
    lPid = Shell(cmdApp, vbNormalFocus)
    If lPid <> 0 Then
        ‘Get a handle to the shelled process.
       lHnd = OpenProcess(SYNCHRONIZE, 0, lPid)
        ‘If successful, wait for the application to end and close the handle.
       If lHnd <> 0 Then
                lRet = WaitForSingleObject(lHnd, INFINITE)
                CloseHandle (lHnd)
        End If
End If

End Sub

Sub ExampleMergePDF()
    With ThisWorkbook.Worksheets(“cp”)
        mergePdf .Range(“PDFdir”).Value, .Range(“outdir”).Value
    End With
    MsgBox “done!”
End Sub

I hope that there soon will be a solution to allow code examples to be posted in the comments without being corrupted.

Anyway, thanks for the input :)

Kind regards,
Dennis

Add and remove shortcuts in the Open & Save As dialogs

Add and remove shortcuts in the Open & Save As dialogs

Creating and removing customized shortcuts can either be done manually or via code. When we make any change(s) it will affect all Office programs.

Manually
If we want to do it manually we need to open the Regeditor and locate the following key in Windows registry:

HKEY_CURRENT_USERSoftwareMicrosoftOfficeVersionnumberCommonOpen FindPlacesUserDefinedPlaces

The ‘Versionnumber’ refers to 9.0, 10.0, 11.0 and later.

- Under this key we create a new subkey and name it (for instance Daily Dose)
- For the new subkey we add two string values:
‘Name’ and with the value for the name to be showed in the dialogs (for instance Daily Dose)
‘Path’ and with the value of the pathway to be available in the dialogs (for instance c:Daily Dose)

The following image shows the settings in the registry:


(The screenshot is from my Swedish Windows XP)

Another important subkey is ‘Places’ which contain the string value ‘ItemSize’. It control if the shortcuts will be showed as compressed (value 0) or not (value 1). If we have many shortcuts it can be suitable to ‘compact’ them in the dialogs. The ‘ItemSize’ can be located at the following place in Windows registry:

HKEY_CURRENT_USERSoftwareMicrosoftOfficeVersionnumberCommonOpen FindPlaces

Via code
The below solutions use the RegObj.dll and for more information about Regobj please see Add-ins – Working with Windows registry

Option Explicit
Option Private Module

‘A reference to the Registration Manipulation Classes must be set.

Dim m_regRootKey As RegKey
Dim m_regMainKey As RegKey
Dim m_stSubRoot As String
Dim m_stSubPlace As String

Sub Add_ShortCut_Office()
If Add_ShortCut(“11.0″, “XL-Dennis”, “My storage”, “c:XL-Dennis”, 0) Then
    MsgBox “The shortcut has successfully been added to the list.”, vbInformation
Else
    MsgBox “The shortcut already exist in Windows Registry.”, vbInformation
End If
End Sub

Sub Remove_ShortCut_Office()
If Remove_ShortCut(“11.0″, “XL-Dennis”, 1) Then
    MsgBox “The shortcut has successfully been removed.”, vbInformation
Else
    MsgBox “The shortcut does not exist in Windows Registry.”, vbInformation
End If
End Sub

Function Add_ShortCut(ByVal stXLVersion, _
                                                   ByVal stMainKey As String, _
                                                   ByVal stName As String, _
                                                   ByVal stPath As String, _
                                                   ByVal lnSize As Long) As Boolean

On Error GoTo Error_Handling

‘Registry path to set the size of the shortcuts in the dialogs.
m_stSubPlace = “SoftwareMicrosoftOffice” & stXLVersion & _
                                  “CommonOpen FindPlaces”

‘Registry path to add user defined places.
m_stSubRoot = “SoftwareMicrosoftOffice” & stXLVersion & _
                                 “CommonOpen FindPlacesUserDefinedPlaces”

‘Set the rootkey.
Set m_regRootKey = RegKeyFromHKey(HKEY_CURRENT_USER)

‘Parse the subkey.
Set m_regMainKey = m_regRootKey.ParseKeyName(m_stSubRoot)

With m_regMainKey
    .SubKeys.Add stMainKey ‘Create the subkey.
   With .SubKeys(stMainKey)
        ‘Add the shortcuts which are string values.
       .Values.Add “Name”, stName, RegValueType.rvString
        .Values.Add “Path”, stPath, RegValueType.rvString
    End With
End With

‘Parse the subkey.
Set m_regMainKey = m_regRootKey.ParseKeyName(m_stSubPlace)

‘It seems that there only exist two workable values, 0 and 1
‘where 0 represent the compacted status and 1 the standard.
If lnSize > 1 Then
    lnSize = 1
ElseIf lnSize < 0 Then
    lnSize = 0
End If

If m_regMainKey.Values(“ItemSize”).Value <> lnSize Then
    m_regMainKey.Values(“ItemSize”).Value = lnSize
End If

Add_ShortCut = True

ExitHere:
‘Release objects from memory.
Set m_regRootKey = Nothing
Set m_regMainKey = Nothing
Exit Function

Error_Handling:
    ‘Error 35004 indicates that the shortcut entry already exist.
   If Err.Number = 35004 Then Add_ShortCut = False
    Resume ExitHere
End Function

Function Remove_ShortCut(ByVal stXLVersion, _
                                                           ByVal stMainKey As String, _
                                                           ByVal lnSize As Long) As Boolean

On Error GoTo Error_Handling

m_stSubPlace = “SoftwareMicrosoftOffice” & stXLVersion & _
                                  “CommonOpen FindPlaces”

m_stSubRoot = “SoftwareMicrosoftOffice” & stXLVersion & _
                                 “CommonOpen FindPlacesUserDefinedPlaces”

Set m_regRootKey = RegKeyFromHKey(HKEY_CURRENT_USER)

Set m_regMainKey = m_regRootKey.ParseKeyName(m_stSubRoot)

m_regMainKey.SubKeys.Remove stMainKey

Set m_regMainKey = m_regRootKey.ParseKeyName(m_stSubPlace)

If lnSize > 1 Then
    lnSize = 1
ElseIf lnSize < 0 Then
    lnSize = 0
End If

If m_regMainKey.Values(“ItemSize”).Value <> lnSize Then
    m_regMainKey.Values(“ItemSize”).Value = lnSize
End If

Remove_ShortCut = True
   
ExitHere:
Set m_regRootKey = Nothing
Set m_regMainKey = Nothing
Exit Function

Error_Handling:
    ‘Error 35006 indicates that the shortcut entry does not exist.
   If Err.Number = 35006 Then Remove_ShortCut = False
    Resume ExitHere
End Function

The following picture shows the Open Dialog when we have added a shortcut (via the above code) and also have compressed the list:

Shortcuts

For privacy I have removed all info in the dialog

The above is applicable for Excel 2000 and later.

Kind regards,
Dennis

Important: Whenever You are working with the Windows registry make sure You first make a backup of the registry.