The first thing one should address in an article about converting Office VBA applications to VB6 is “WHY?”

Why would someone bother in the year 2011 to convert one decade-old technology to another decade-old technology?

The answer is this: many businesses are still using these technologies. Especially large firms find it takes many years to switch to the latest and greatest.

Some of my clients still use Office 2003 or even Office 2000.

And I’m not talking only about small companies who perhaps don’t know any better or who are on tight budgets. I’m talking about large multinationals, the largest companies in the world.

The next question is: why convert from Office VBA to VB6?

The answers:

  • To create a free-standing application executable, one which doesn’t use a Word document or template directly to house the code. Granted, there are other ways to do this, but using VB6 may be one of the simplest.
  • To take advantage of the speed advantage by using a compiled language like VB6 versus a semi-compiled/interpreted language like Office VBA.
  • To have your code run in a more stable environment – VB6 versus Office VBA.

While we won’t go into a detailed technical how-to here, we will address the feasibility.

The answer is: yes, it is feasible to convert Office VBA applications to VB6 applications.

The language syntaxes are virtually identical.

Here are a few pointers:

  • You must physically move the code. There are easy ways to do this.
  • You must set proper References to the Office libraries that are usually set by default within the Office VBA environment.
  • You must account for the differences between the Application object in Office VBA and the App object in VB6. They have little in common.
  • Generally, you may find it best to use full object qualification in your code. For example, I routinely use Word.Document as an object type in my Word VBA code rather than simply Document. This does tend to make things a bit easier when converting to VB6. If you do this, you can be sure you’re referring to the correct object type. The same object type may exist in different libraries. I also use Word.Application rather than simply Application.
  • With a bit of diligence and a cool head, you can successfully convert your Office VBA applications to VB6 applications.

Please feel free to contact us here at Soundside more information. And happy coding!

 

I needed a function that would conveniently return me a Range that contained the top of the next page in a Word document.

The following does the trick:

Function TopOfNextPage(rng As Word.Range) As Word.Range
    Set TopOfNextPage = rng.Duplicate.GoTo(What:=wdGoToPage, Which:=wdGoToNext)
End Function 

Notice it does not disturb the original Range. It accomplishes this by use of the Range.Duplicate function, which I find very handy sometimes when I don’t want to disturb my original Range.

Notice the returned Range is collapsed to the top of the page.

 

Here’s a handy little function that tells you if the end of a Range in Word VBA lies on the last page of the document:

Function IsLastPage(rng As Word.Range) As Boolean
     IsLastPage = CBool(rng.Information(wdActiveEndPageNumber) = rng.Information(wdNumberOfPagesInDocument))
End Function 

The Range.Information function is very useful. Check it out!

We hope it comes in handy.

 

I wanted a function in Word VBA that would add a Field to a Range’s Fields collection and automatically extend the Range to include the added field.

This mimics the behavior of the Range.InsertAfter function and similar functions.

It allows you to keep adding text, fields, and other items to a Word document sequentially.

The function I created is called InsertFieldAfter. Its parameters mimic the parameters to the Fields.Add function.

The Range you pass in is extended to include the newly added Field. The new Range is also returned as the function return value for convenience.

The text of the function and related support functions is below, followed by an example of how to use the function.

' Expand the Range to include the added field and return it. Public Function InsertFieldAfter( _
             ByRef Range As Word.Range, _
             ByVal FieldType As WdFieldType, _
             ByVal Text As String, _
             Optional ByVal PreserveFormatting As Boolean = False _
         ) As Word.Range
     On Error GoTo handler
     Dim StartPos As Long, EndPos As Long
     StartPos = Range.Start
     Range.Collapse Direction:=wdCollapseEnd
     EndPos = Range.Fields.Add( _
             Range:=Range, _
             Type:=FieldType, _
             Text:=Text, _
             PreserveFormatting:=PreserveFormatting) _
         .Result.End + 1
     Range.SetRange StartPos, EndPos
     Set InsertFieldAfter = Range
     Exit Function
handler:
     ' handle any run-time error here
End Function 

Here’s a code snippet showing an example of its use:

With myRange
     .InsertAfter "Here is a field: "
     InsertFieldAfter Range:=myRange, FieldType:=wdFieldEmpty, Text:="REF Field1"
     .InsertAfter vbCrLf & "Here is another field: "
     InsertFieldAfter Range:=myRange, FieldType:=wdFieldEmpty, Text:="REF Field2"
     .InsertAfter vbCrLf
End With 

Happy coding!

 

Dynamic UserForms in VBA

by David Horowitz

Did you know that you can add and remove controls from a UserForm (also known as custom dialog boxes) at run-time? This means that you can change your UserForms based on certain conditions that exist during the operation of your VBA project—you’re not limited to the design of the UserForm that you created in the VBE designer!

To illustrate the technique, we’ll create a Word VBA Template which will prompt the user for the number of cars they own. (It allows for up to 20—hopefully that will be enough for most of us!) It will then display the correct number of textboxes to allow the user to enter the make of each car. When the user is done, the list of cars will be added to the document.

The key thing here we want to illustrate is the part where the dialog box will actually change to display the correct number of textboxes (with accompanying labels).

The primary method that accomplishes this task is Form.Controls.Add. (You can look it up in VBA Help.) Its syntax is like this:

Set ctl = Me.Controls.Add(ControlClass, Name, Visible)

For our purposes, ControlClass can have one of the following values:

"Forms.CheckBox.1"
"Forms.ComboBox.1"
"Forms.CommandButton.1"
"Forms.Frame.1"
"Forms.Image.1"
"Forms.Label.1"
"Forms.ListBox.1"
"Forms.MultiPage.1"
"Forms.OptionButton.1"
"Forms.ScrollBar.1"
"Forms.SpinButton.1"
"Forms.TabStrip.1"
"Forms.TextBox.1"
"Forms.ToggleButton.1"

These are text strings, so you must enclose them in quotes.

You can optionally specify the name of the new control using the Name parameter, for example, “TextBox7”, “txtFirstName”, “lblPrompt”, or “chkChicago”, whatever’s appropriate for your use.

Finally, you can choose to make the new control invisible by specifying False for the Visible parameter. The default is for Visible to be True.

So, for example, let’s say you would like to add a new label to your form. The form is named frmMyForm, and the new label should have the name “lblPrompt”. The method call would look like:

Dim myLabel as Label
Set myLabel = frmMyForm.Controls.Add _
    ("Forms.Label.1", "lblPrompt")

Don’t get confused about myLabel and lblPrompt. myLabel is an Object variable in VBA which is now set to refer to the control on the form by the name of “lblPrompt”.

Once you add a control to a form, you will certainly need to set some properties on the control, at least things like Top, Left, Width and Height. You can do this right after creation if you want, using, in our example, myLabel:

With myLabel
    .Left = 10
    .Top = 10
    .Width = 30
    .Caption = "Enter your name:"
End With

We’ve let the Height property default to whatever VBA sets for it initially.

Now later on in your code, if you want to refer to the newly added control, but you no longer have the myLabel reference, you can either use:

frmMyForm.Controls("lblPrompt”)

or

frmMyForm!lblPrompt

You cannot use the other syntax to refer to a control:

frmMyform.lblPrompt

when the control has been created dynamically using Controls.Add.

The example which accompanies this article, Dynamic UserForms Demo.dot, is a Word template which illustrates the techniques we’ve just describes in greater detail and in actual usage. You can download a copy of this template demo by clicking: HERE.

When you open this template, the Document_New method will call ShowCarsDialog, which will call the frmCars.Show method. frmCars has a label (lblNumCars) and textbox (txtNumCars), which prompt you to enter the number of cars you have. When you click on the Show Cars button (cmdShowCars), you will see a number of labels and textboxes equal to the number of cars you entered, allowing you to enter a make for each car. Then, when you click the Done button (cmdDone), all the car makes you entered will be inserted into the document and the dialog form (frmCars) will be unloaded.

If you want to change the number of cars again before you press Done, you can do that and when you click on Show Cars, the number of car labels and textboxes will change again to accommodate. So you can Add and Remove cars from the list before you click Done.

When you look at the code, you will see that each car make has a label and a textbox called lblCarN and txtCarN, where N is the number of the car. Each label is added to the form using this line of code:

Set theLabel = Me.Controls.Add _
    ("Forms.Label.1", "lblCar" & CurrentNumberOfCars)

Each textbox is added to the form using this line of code:

Set theTextBox = Me.Controls.Add _
    ("Forms.TextBox.1", "txtCar" & CurrentNumberOfCars)

After creating each control, we set a number of properties on it. We set each label’s caption using this line of code:

theLabel.Caption = "Car #" & CurrentNumberOfCars & ":"

You can see we even set the Accelerator property on each label to the number of the car using this line of code:

theLabel.Accelerator = CurrentNumberOfCars

If you tell the dialog box to remove some cars, the following lines of code are used:

Me.Controls.Remove "lblCar" & CurrentNumberOfCars
Me.Controls.Remove "txtCar" & CurrentNumberOfCars

In this article, we’ve learned how to use Form.Controls.Add to add controls to a form’s Controls collection at run-time. We then set properties on the control to make it look and function the way we want. We also learned how to dynamically remove a control from a form’s Controls collection using Form.Controls.Remove.

Now you can experiment with adding and removing controls to your forms whenever you need them. You will find many uses for this technique once you’ve learned how to do it.


This article originally appeared in Vol 3, Issue 2 of TechTrax.

Need further help getting your VBA code working right? Contact us or check out TechTrax’s free VBA support groups. See these links for details: http://groups.yahoo.com/group/Word_VBA/ and/or http://groups.yahoo.com/group/ExcelVBA/.

 

Did You Forget Something?

Or, How to Get Outlook To Remind You to Insert a Forgotten Attachment

by David Horowitz

Introduction

Your boss wants that report by the end of the day. It’s five minutes to five, and you’ve just put on the finishing touches. You draft an email to the boss, saying, “As per your request, please see the attached report.” But in your haste, you forget to attach the report, and you hit Send! How foolish do you feel? Now you have to send a second email that says something like, “Oops! Here’s the attachment.” I’m not going to ask if this has ever happened to you, but how many times this has happened to you. Maybe if you’re using Exchange Server, you can Recall and/or Resend the message before the boss sees it. Otherwise, you’re stuck sending that “Oops” message. Not that you should be too embarrassed, because it does happen to everyone, but wouldn’t it be great if you can avoid having it happen to you, and learn some Outlook VBA programming along the way? Let’s get started! 

Getting to the Outlook VBE

From within Outlook, select Tools / Macro / Visual Basic Editor, or simply hit Alt-F11. Simple, eh? 

When you first enter the VBE, you’ll be looking at the default project, which is called VbaProject.OTM. You should see something that looks like the figure below. Please note we’ll be using Outlook 2002/XP for this article. There may be some (hopefully) slight differences in other versions of Outlook. 

 

Figure 1 – Visual Basic Editor showing Project1 (VbaProject.OTM) with ThisOutlookSession module opened.

Locating VbaProject.OTM and the APPDATA Environment Variable

Not that you necessarily need to know this, but the VbaProject.OTM file is located in the Application Data\Microsoft\Outlook folder within the user’s profile folder. On my machine, the entire path is “C:\Windows\Profiles\David\Application Data\Microsoft\Outlook\VbaProject.OTM”. On others it may be “C:\Documents and Settings\\Application Data\Microsoft\Outlook\VbaProject.OTM”. To locate the “Application Data” folder for the current user, you can refer to the APPDATA environment variable. You can do this from a Command Prompt, or even from within Windows Explorer. In the Command Prompt, you can type: 

  • ECHO %APPDATA% to see the folder location.
  • CD %APPDATA% to change directories to the folder location.
  • DIR "%APPDATA%" to see the list of files in the folder. Notice the DIR command requires the use of quotation marks here because the APPDATA variable most likely contains embedded spaces.

Within Windows Explorer, you can simply go to the Address Bar, using either the mouse or by hitting Alt-D, and then typing %APPDATA% as the address and pressing Enter or clicking Go

There are lots of potentially useful environment variables. You can go to the Command Prompt and type the command SET to see all the environment variables. You can also see the environment variables in System Properties, which you can get to by right-clicking on My Computer and selecting Properties, or from within the Control Panel

Once in System Properties, select the Advanced tab, then click on the Environment Variables button towards the bottom. There you’ll see a bunch of environment variables. However, there are even more displayed in the Command Prompt when you issue the SET command. 

Perhaps some sharp reader could explain why you don’t see the complete list of variables in the System Properties window. Perhaps the extra ones you see using the SET command are ones that are set by the system and that the user cannot be allowed to change. Anyone? 

 

Figure 2 – The System Properties Control Panel applet with the Advanced tab displayed.

Getting to the ThisOutlookSession Module

If you haven’t added any code yet, the VbaProject.OTM project will contain a single standard module called ThisOutlookSession. This is where our code will go. If you don’t see ThisOutlookSession immediately, click on the plus sign to the left of “Microsoft Outlook Objects” under “Project1 (VbaProject.OTM)”, and then double-click on ThisOutlookSession. See figure 1 above. 

The Application Object Event Handlers

In the ThisOutlookSession module, you can add general Subs and Functions, and you can also add event handlers for the Application object. 

There are several interesting events that you can write handlers for here. To see them, click where it says “(General)” above the code window and select “Application” from the drop-down list. Immediately, the VBE will create a skeleton for the Application.ItemSend event for you. This happens to be the event we’re interested in, and we’ll come back to it shortly. However, you can pull down the list of events in the drop-down to the right of the drop-down you just used. It should currently read “Application_ItemSend”. You can use the Application_Startup and Application_Quit events to execute code upon Outlook startup and exit. You can use the Application_NewMail event to execute code upon the receipt of new mail. (Surprising, right?) We’ll stick to the Application_ItemSend event in this article. 

 

Figure 3 – ThisOutlookSession code window showing the Application_ItemSend skeleton and the list of Application events.

Application_ItemSend Event Handler

When you hit Send after composing an email message, Outlook does several things. For example, it runs the spell checker (if the “Always check spelling before sending” option is checked in the Spelling tab of the Tools / Options command). Then it attempts to resolve the recipient names. If any of your recipient names are ambiguous, it will prompt you to select the correct contact. After all that is completed, it will trigger an Application.ItemSend event to give you an opportunity to process the message. 

Here’s the Application_ItemSend event handler skeleton: 

Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)

End Sub

You can see it sends you a reference to the Item being sent, which should hopefully be a MailItem. You are also sent a parameter called Cancel. If you want to cancel the sending of the Item, then set Cancel to True before you exit the event handler. So, as an example, if you wanted to disable the sending of all email, you could write the event handler like this: 

Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
    Cancel = True
End Sub

Checking for a Missing Attachment

We’ll check for certain words in the Subject and Body of the user’s email message, such as “attached” or “enclosed”. If any of those words are in the email message, but no attachments were specified, then we’ll alert the user that they may have forgotten an attachment and ask them if they would like to specify one now. If they want to, then we’ll execute the Insert / File… command so they can specify the attachment. 

Here’s the code: 

Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
    If Item.Class <> olMail Then Exit Sub
    If Item.Attachments.Count > 0 Then Exit Sub
    If Not SearchForAttachWords(Item.Subject & ":" & Item.Body) Then Exit Sub
    If UserWantsToAttach Then
        ExecuteInsertFileCommand
    End If
End Sub

Let’s take it line by line. 

  • First we check to make sure the Item Class is olMail, basically making sure the Item is a MailItem, as opposed to a ContactItem or PostItem or whatever. This step is probably not necessary, because ItemSend is typically only called when sending a MailItem, but it never hurts to be sure, if only to avoid a possible runtime error.
  • Then we check to see if there are already any attachments specified. If there are, then we certainly don’t need to do anything, so we exit.
  • Next we call a function which searches for certain key words in the Subject and Body of the message. If the words are not found, then we’ll exit.
  • Finally, if we’ve gotten this far, then the Item IS a MailItem, there are no attachments yet, and one of the key words was found, so we now ask the user if they would like an eleventh-hour reprieve to specify an attachment. If they do, then we execute the Insert / File… command so they can specify the attachment.

Checking for Certain Key Words

Here’s the code for the SearchForAttachWords Function: 

Function SearchForAttachWords(ByVal s As String) As Boolean
    Dim v As Variant
    For Each v In Array("attach", "enclos")
        If InStr(1, s, v, vbTextCompare) <> 0 Then
            SearchForAttachWords = True
            Exit Function
        End If
    Next
End Function

You can see we’re searching for the text strings “attach” and “enclos”. You can add others if you wish. The text search doesn’t care whether it’s matching whole words or not, so we’ll find “attach” just as easily as “attached” or “attachment”, or even “attaché” for that matter. Similarly, we’re searching for “enclos” so we can find “enclose”, “enclosed”, and even “enclosure”. 

The use of vbTextCompare makes the search case-insensitive. 

Seeing If the User Wants to Correct His or Her Potential Mistake

We don’t want to be presumptuous. That’s why we won’t definitively decide the user made a mistake. Rather, we’ll suggest to them that perhaps they meant to include an attachment. Much more subtle. 

Function UserWantsToAttach() As Boolean
    If MsgBox("It appears you may have forgotten to specify an attachment." _
            & vbCrLf & vbCrLf & _
            "Would you like to do this now?", _
            vbQuestion + vbYesNo) _
            = vbYes Then
        UserWantsToAttach = True
    End If
End Function

Executing the Insert / File… Command Programmatically

The way to execute a MenuBar or CommandBar command in an Office application is to refer to the correct Control within the correct CommandBar and invoke the Execute method, like this: 

Sub ExecuteInsertFileCommand()
    Application.ActiveInspector.CommandBars("Standard").Controls("&File...").Execute
End Sub

Tying It All Together

After you enter these four subs and functions into the ThisOutlookSession module, be sure to save the project. Then you can use Alt-Q to quit the VBE and return to Outlook. Start sending some mail and see what happens. You may want to experiment by sending to yourself so you don’t annoy everyone in your contact list! 

Wrap Up

In this article, we’ve demonstrated: 

  • Using the APPDATA environment variable.
  • Using the SET command from the Command Prompt.
  • Using Alt-D to access the Address Bar in Windows Explorer or Internet Explorer.
  • Creating event handlers for the Application object in the ThisOutlookSession module.
  • Using the MailItem Class, Attachments.Count, Subject and Body properties.
  • Using the VBA Array function to create an array of variants on-the-fly.
  • Using the VBA InStr function to search for strings contained within other strings.
  • Executing Office commands programmatically using the CommandBars collection.

Please let us know what interesting uses you find for this information. You can send Feedback through the magazine or feel free to drop me a line

– Dave


This article originally appeared in Vol 3, Issue 8 of TechTrax.
Contact us if we can assist you.

Click to rate this article.

 

Using SelfCert to Create Digital Certificates in a Network Environment

by David Horowitz

In this article, I’ll discuss how to use SelfCert.exe to generate your own digital certificates (or signatures) to sign your in-house VBA template projects. Then I’ll explain how to install these templates on other machines which are set to High (or Medium) Macro Security. I’ll also provide links to useful Microsoft Knowledge Base articles. These instructions have been tested on Word 2002 (XP) and probably work similarly with Word 2000.

Scenario

You’re an in-house IT person, or perhaps a small developer. Your company (or client) needs to have Macro Security set to High (or at least Medium) to provide some sense of protection against macro viruses. You want to deploy some templates in Word with custom macros. Because of the macro security feature, you need to have your code signed with a digital certificate. You don’t want to purchase a digital certificate from a certificate authority just so you can deploy some templates with macros. You know you can use SelfCert.exe to generate your own certificate. It works fine on your development machine, but you’ve been having trouble deploying the templates onto other machines on the network. This article describes how to do it.

A few clarifications are in order. For one, even if you have an email antivirus system installed, leaving Macro Security set to High, or at least Medium, is a good idea. With it set to Medium, every time your user attempts to load a template which hasn’t been verified, she will get a dialog box asking if she wants to Enable Macros. Inconvenient, to say the least. If Macro Security is set to High, if you haven’t verified the certificate, your user won’t even be allowed to enable the macros.

One problem with certificates generated with SelfCert is they can be forged. However, the forger would need to have specific knowledge about your in-house certificate. This would mean they would either have to have a big grudge against your company or client, or be someone in-house with a degree of technical sophistication. Under many circumstances, this is not a real risk. However, under these circumstances, you may wish to consider purchasing a verified code-signing digital signature from a Certificate Authority (CA). See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/rootcertprog.asp for Microsoft’s list of Certificate Authorities.

Let’s Do It

The basic procedure is:

  • Create your template with custom macros or code
  • Locate or install SelfCert.exe on your development machine.
  • Generate your own digital certificate using SelfCert.exe.
  • Sign your template with this new digital certificate
  • Copy the template to its desired location
  • Install the certificate on each machine

Let’s now look at each step in detail.

Create your Template with Custom Macros or Code

I’ll assume you know how to do this.

Locate or Install SelfCert.exe on Your Development Machine

SelfCert.exe is installed as part of Office XP—look in C:\Program Files\Microsoft Office\Office10. In Office 2000, it’s an optional component you can install—use Control Panel/Add/Remove Programs/Microsoft Office/Add or Remove Features/Update Features/Office Tools/Digital Signatures for VBA Projects. See the To Install the SelfCert Tool section of Microsoft Knowledge Base article Q206637 – OFF2000: Overview of Digital Certificates or the Creating a Test Certificate section of Q217221 – OFF2000: Using SelfCert to Create a Digital Certificate for VBA Projects for more info.

Generate Your Own Digital Certificate Using SelfCert.exe

To create your certificate, simply run SelfCert from wherever it is and enter the name you want to give the certificate. That’s it. The name can be your company’s name, or it can be something like "<Company Name> Internal", or whatever seems appropriate to you. See the To Create a Test Certificate section of Q206637 – OFF2000: Overview of Digital Certificates or the Creating a Test Certificate section of Q217221 – OFF2000: Using SelfCert to Create a Digital Certificate for VBA Projects for more info.

Sign Your Template with This New Digital Certificate

To sign your template, go into the Visual Basic Editor (Alt/F11 from Word), select the template project you wish to sign, select Tools/Digital Signature, select Choose, choose the certificate from the list, and click OK twice. Refer to the screen snapshots below. See the Adding a Digital Signature to a Macro Project section of Q307731 – HOW TO: Add a Digital Signature to a Custom Macro Project in an Office XP Program for more info.
 
Figure 1—The Digital Signature dialog box showing the user clicking the Choose button.

Figure 2—The Select Certificate dialog box showing the user selecting the certificate and clicking the OK button.

Copy the Template to its Desired Location

In a network environment, this may be to the Workgroup templates location. In Word, look in Tools/Options/File Locations. I’ll leave this part up to you.

Install the Certificate on Each Machine

This is the tough part that Dian Chapman and I collaborated on. And they said it couldn’t be done! I was unable to find any documentation on this procedure on the Web. The procedure is non-intuitive because you’re trying to trust a non-authenticated digital signature. You’ll want to do this procedure yourself (rather than having users do it) to make sure it’s done right. As you’ll see, it’s not really hard to do.

  1. Open a document based on the template in Word, using File/New/New from Template/General Templates. You will get the Macro Security dialog box.
  2. The dialog box will mention the name of the certificate. Click Details.

    Figure 3—The Security Warning dialog box showing the user clicking the Details button.
  3. Click on View Certificate.
  4. Click on Install Certificate.

    Figure 4—The Certificate dialog box showing the user clicking the Install Certificate button.
  5. A wizard will appear. Click Next twice and Finish.
  6. A dialog box may appear to ask if you are sure you want to Add the certificate. Click Yes.
  7. Click OK twice to get back to the dialog box shown during step 1.
  8. Check the Always trust macros from this publisher checkbox.
  9. Click Enable Macros.

That’s it!

Special thanks go to Dian Chapman for her assistance with this article.


References

For a good overall description of most of the process:
5-Minute Security Advisor—Signing Office Objects
http://www.microsoft.com/technet/treeview/default.asp?url=/technet/columns/security/5min/5min-402.asp

For an overview of digital certificates, a description of the different Macro Security levels, information about how to obtain a signature, and instructions for using SelfCert:.
Microsoft Knowledge Base Article – Q206637
OFF2000: Overview of Digital Certificates
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q206637

For a brief description of how to use SelfCert:
Microsoft Knowledge Base Article – Q217221
OFF2000: Using SelfCert to Create a Digital Certificate for VBA Projects
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q217221

For a brief description of how to sign your code:
Microsoft Knowledge Base Article – Q307731
HOW TO: Add a Digital Signature to a Custom Macro Project in an Office XP Program
http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q307731

For Microsoft’s list of Certificate Authorities:
Microsoft Root Certificate Program Members
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/rootcertprog.asp


© 2011 Soundside Software Suffusion theme by Sayontan Sinha