.

Entries Tagged in vba

I was tagged in: vba excel email

Friday, March 20, 2009

Love it or hate it, email is everywhere, so the demand for integrating email into simple applications can be pretty strong. I thought I'd share three simple methods by which you can send emails using VBA in any Microsoft office product. Thus allowing your users can annoy everyone with lovingly crafted emails at the push of a button.

 

I will outline two approaches to sending emails, advise as to best practice, and provide full code for implementation. Its all very simple, so all skill-levels should find it easy enough to follow (despite the horribly confusing articles on other websites).

The Two Approaches to Sending Email

The two approaches are: 1. Communicating directly with a mail server (such as Microsoft Exchange Server), or 2. using the API of a client application (such as Lotus Notes or Outlook).

Using the client API binds your code to the email application running on a user's machine. The danger of this is that if you move from Lotus Notes to Microsoft Outlook the emailing routine is no longer going to work!

The benefit of going directly to the server is that how you communicate with the server doesn't change regardless of whether you're using Microsoft Exchange, Google Apps, or Lotus Domino. However, some companies heavily lock-down their mail servers as a way to increase security, so this type of communication is not always an option (although it is in most cases if you ask the right person).

Clearly the ideal way to send an email is to communicate directly with the mail server. SMTP is the ideal protocol for doing this (Simple Mail Transfer Protocol), so that is what I'll show you.

For the sake of completeness I will also demonstrate how to send an email with both the Microsoft Outlook and IBM Lotus Notes APIs. Although let me stress again that these should NOT be used by default.

SMTP (The Best Way)

All windows distributions from Windows 2000 onwards include a COM API component called Collaboration Data Objects (CDO). This api wraps the underlying messaging API and allows us to very simply manipulate email objects.

Here is the code:

Public Sub EmailViaCDO()


Dim sentFrom        As String
Dim serverAddress   As String
Dim messageBody     As String
Dim sendTo          As String
Dim userName        As String
Dim password        As String
Dim subject         As String

'This stuff would normally be passed into the method as parameters
sentFrom = "matthew.rathbone@example.com"
serverAddress = "server.example.com"
sendTo = "example@email.com"
messageBody = "This is a test email"
subject = "message subject"

Dim message As New CDO.message
Dim config As New CDO.Configuration

'set up the configuration for the email server
config.Fields(cdoSendUsingMethod).value = cdoSendUsingPort
config.Fields(cdoSMTPServer).value = serverAddress
config.Fields(cdoSMTPUseSSL).value = False
config.Fields(cdoSMTPConnectionTimeout).value = 10


'Only use these if the server requires authentication
' config.Fields(cdoSMTPAuthenticate).Value = cdoBasic
' config.Fields(cdoSendUserName).value = userName
' config.Fields(cdoSendPassword).value = password
'---------------

'update the config before using it
config.Fields.Update



Set message.Configuration = config
message.To = sendTo
message.from = sentFrom
message.subject = subject
message.TextBody = messageBody
message.AddAttachment ("C:\attachment.txt")

'Away goes our message!
message.Send


End Sub

Microsoft Outlook

Because Outlook also has VBA, using outlook from any VBA-enabled application is actually very easy, see below:

Public Sub EmailViaOutlook()

' requires a reference to the Microsoft Outlook 8.0 Object Library

' creates and sends a new e-mail message with Outlook
Dim outlookFolder As Outlook.MAPIFolder
Dim recipient As Outlook.recipient
Dim mailItem As Outlook.mailItem

'this gets an existing outlook
Set outlookFolder = GetObject("", _
        "Outlook.Application").GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
    
    ' lets create a new email message
    Set mailItem = outlookFolder.Items.Add
    
    mailItem.subject = "this is the subject"
    mailItem.Body = "This is the message I'm sending!"
    mailItem.Attachments.Add "C:\attachment.txt"
    
    'SOME OPTIONAL STUFF
    mailItem.OriginatorDeliveryReportRequested = True ' delivery receipt
    mailItem.ReadReceiptRequested = True ' read receipt
    
    
    'simply add a recipient
    mailItem.recipients.Add "someoneelse@example.com"
    
    'or add one then set some properties
    Set recipient = mailItem.recipients.Add("someone@example.com")
    recipient.Type = olCC
    
    
    'Finally, send our email
    mailItem.Send
    
    'or save it for later
    'mailItem.Save
End Sub

Lotus Notes

After using SMTP and Outlook, using the lotus API is not quite as pretty. Lets be honest, its down-right horrible. Regardless of this, here is the code:


Sub SendMailViaLotusNotes()
   
    'Method:
    ' open a lotus notes session
    ' open the notes database
    ' use the db to create a new mail document
    ' assign the key properties to the mail document
    ' create a rich-text item for the mail body (this allows us to have nicer emails)
    ' write our email body
    ' send the document
   
   'Requires reference to: "Lotus Domino Objects"
   
    Dim dominoSession As New NotesSession
    Dim mailDatabase As NotesDatabase
    Dim newMemo As NotesDocument
    Dim richText As NotesRichTextItem
    Dim strAttachment As String
    dominoSession.Initialize ("")    'Prompts user for Password
    
    Set mailDatabase = dominoSession.GetDatabase("", "names.nsf")
    Set newMemo = mailDatabase.CreateDocument
   
   
    newMemo.AppendItemValue "Form", "Memo"
    newMemo.AppendItemValue "SendTo", "matthew.rathbone@example.co.uk"
    newMemo.AppendItemValue "Subject", "This is the subject"
    
    Set richText = newMemo.CreateRichTextItem("Body")
   
    richText.AppendText "This is my email text"
    
    newMemo.Send False

End Sub

There's probably a better way to do this using the lotus API, or at least I hope there is!

Hopefully these snippets of code have proven useful, feel free to use them in anyting you wish, although whenever possible please credit me with a link. If you have any questions, feel free to contact me.

0 Comments

I was tagged in: bloomberg vba developer

Tuesday, February 03, 2009


As the snappy title implies, the following items I consider to be useful pieces of information when working with Bloomberg.

1. Don't store any data retrieved via the Bloomberg Client Terminal API

Don't put it in a database, pass it around on excel sheets, use it as a data source for internal systems, or anything like this at all. Doing so will land you in a lot of trouble with Bloomberg for breaking your license agreement, something they take very seriously (can you say 'lawsuit'?)

2. Get end users to upgrade their aging terminal software to take advantage of Bloomberg's real-time Excel formulas.

If your users are still using spreadsheets filled with =BLP() formulas then a huge portion of CPU power on their machines is dedicated to continually refreshing 'static' data. Bloomberg had to use a series of macros and elaborate hacks to simulate real-time data feeds to excel before Microsoft included support for real-time data streaming ( =RTD() ).

Newer versions of Bloomberg software include the =BDP() function which is simply a nice wrapper for Excel's build-in data streaming functionality. Using these new formulas will significantly improve the performance of Excel, and the PC as a whole. Plus sheets with the legacy =BLP formula will still work if you are not going to be able to migrate them.

3. Get a Bloomberg Developer License

Bloomberg offers a special cut-down license for IT professionals who work a lot with the Bloomberg Client Terminal API. This provides you with a limited amount of data through the API and some basic terminal software functionality. It's far from the ideal development environment (I hit my daily data limit by about 11am normally), but it's good enough to make sure what you're doing actually works.

It costs around 1/3 as much as a 'real' terminal license, so you can save a lot of dough.

4. Really understand what fields you're looking at.

Get yourself on a bloomberg terminal, navigate to the main page of an instrument (use "GOOG EQUITY" for a good example) then type "FLDS". You can now search for any field you want and see what value is assigned to it for the current instrument.

If you don't have access to the terminal (hi to fellow developers with restricted licenses) just go to the bloomberg menu in excel and use the 'field search' functionality. It basically does the same thing, except you don't get instrument values, merely a text description of the field.

5. You can use the API for 2 or 3 Days after last logging-in to the Terminal

So you closed your bloomberg Terminal window? Never mind, you can still get data via the API! This data connection stays active until a few days have passed or you log on somewhere else (if you've got an anywhere license).

This means you don't have to have a Bloomberg loaded to use bloomberg-enriched Excel sheets or applications using the API, saving memory, desktop space, and processing power.

6. The bloomberg buttons map to the function keys

Don't put up with a clunky Bloomberg Keyboard if you don't have to, as a developer you can just use your regular keyboard and ask Bloomberg to send you some keyboard stickers. These stickers go around your keys to show you the special bloomberg keys.

0 Comments

I was tagged in: bloomberg vba excel real-time

Wednesday, December 03, 2008

The RTD / BDP functions provide real-time data from bloomberg directly to an excel sheet. However if you're subscribing to fields which Bloomberg hasn't designated to be 'real-time enabled' you have to manually refresh bloomberg data for it to have any effect.


Let's look at an example

 

FUT_CTD_PX (Cheapest to deliver price) is a static FIELD for a real-time VALUE. IE, if you check in the BB terminal this value will be constantly changing, but excel sees it as a static field.

To get the CTD price for a future we can use the following formula:

=BDP("SOME FUTURE'S TICKER", "FUT_CTD_PX")

This field will never update, it will stay static with it's initial value. If the spreadsheet has been open for 5 days, it's the price from 5 days ago which will be displayed.

Microsoft's RTD server model is event driven, in that the data-source notifies the RTD server when a new value is available and that value is picked up by a spreadsheet when excel calls it's RTD.RefreshData method (which it does every 2 seconds by default). In our example, Bloomberg's data-source never notifies the RTD server of a change in value for any of it's STATIC fields, and they therefore remain the same indefinitely.

This also explains why calling RTD.RefreshData from VBA code has no effect, as the RTD server has no new value to pass forwards.

Solutions

The only REAL solution is for Bloomberg to provide such key fields as real-time. Static fields should be reserved for values which do not change on a regular basis, such as instrument name, maturity date, ISIN, and so forth.

As a manual solution, Bloomberg does provide a Excel menu containing data-refresh commands. Clicking 'refresh entire workbook' will eventually update all static values (it can take up to 10 seconds), but only for the =BDP formula. If you're using =RTD you'll have to re-open your workbook or delete and re-type the formulas.

"Can I do this Programatically?" I hear you cry.... Why yes you can!

It's not a graceful solution by any means but you can use one of the following to activate the respective bloomberg command:

Application.Run ("bloombergui.xla!RefreshData") [Default]

Application.Run ("bloombergui.xla!RefreshCurrentSelection")

Application.Run ("bloombergui.xla!RefreshEntireWorksheet")

Application.Run ("bloombergui.xla!RefreshEntireWorkbook")

Application.Run ("bloombergui.xla!RefreshAllWorkbooks")

be sure to wrap any use of these in good error checking to avoid Excel getting mad at the user.


Summary

It's important to be aware that some bloomberg fields are not real-time. If you're using one of these fields for a key calculation you'll have to make sure that you manually refresh regularly, or that you have integrated a crude automation into your code.

0 Comments

I was tagged in: vba ioc dependency injection csharp

Monday, November 10, 2008

Regardless of how much time Microsoft invests into developing Visual Studio Tools for Office there’s still going to be a market for VBA, but that doesn’t mean we have to compromise our methodologies or best practices.

Dependency injection in VBA is not only possible, but it’s not as much work to implement as you might think. Sure VB6’s system for Interface implementation leaves a lot to be desired, and it’s a whole lot less flexible than modern languages, but you can still add a massive amount of flexibility and control to your code through a little thought and planning.

There are a few key things we need for a basic IoC implementation.

1. Interfaces for key dependencies that we want to ‘inject’ (for example a data-repository)
2. A centralized way to change what concrete object is mapped to that interface by default
3. A way to inject that concrete object upon creation of a dependant object (as VBA does not allow you to pass parameters on construction)

Let’s address how to do each of these things in turn:

Interfaces

Interfaces in VBA are created by making a class and populating it with stub methods and properties which don’t do anything, that’s it. You don’t have to declare it as an interface, but it would probably make sense to prefix the name with an ‘I’.
For example, here’s an interface for IDataSource:


Option Explicit
Public Function GetOrders(customerID As String) As collection
End Function
Public Function GetAllOrders() As collection

End Function

Easy!

And here’s a basic example implementation of that interface:

Option Explicit
Implements IDatasource
Public Function IDatasource_GetOrders(customerID As String) As collection
	Dim returnCollection As New collection

	returnCollection.Add ("Item1")
	'Collection logic here
	Set IDatasource_GetOrders = returnCollection
End Function

Public Function IDatasource_GetAllOrders() As collection
	Dim returnCollection As New collection

	returnCollection.Add ("Item1")
	returnCollection.Add ("Item2")
	'Collection logic here
	Set IDatasource_GetAllOrders = returnCollection

End Function


Object Mapping

Because we don’t have use of Unity, Spring.net, or any other IoC framework, the simplest thing to do is to completely dedicate a module to the job of being an ‘object provider’

Because VBA doesn’t need to be compiled, it’s almost as easy as using a configuration file as you can change it on the fly without having to recompile and redeploy.

Additionally, if you want to externalize the assignment of concrete objects to a configuration file, you can just extend this basic object.

Here is an example of a simple object provider:

Option Explicit
'set your bindings here
Private mDataSource As New SqlDataSource
Public Property Get DataSource() As IDatasource
Set DataSource = mDataSource
End Property

All you have to do is chage the type of the private members to switch the default concrete class.

Dependency Injection

VBA doesn’t allow us to have non-default class constructors, which means we cannot construct objects like below:

Dim dataService as new OrderService(SqlRepository)


Instead we simple have to be a little more creative with our objects, I tend to add a method called Initialize which takes a IDataRepository class. If you haven’t initialized the class, no methods that rely on this private member will work, which acts as a failsafe:

Dim repository as IOrderRepository
Dim dataService as new ObjectService
Set repository = ObjectProvider.OrderRepository
dataService.Initialize repository

 

Summary

Coding VBA can be frustrating and confusing when one is used to more elegant languages and frameworks, but that doesn’t mean it’s impossible to import modern programming strategies and methodologies.

Using inversion of control in any framework promotes code reuse, separates concerns, and makes for more manageable maintenance going forwards. Working with an outdated framework does not mean one has to write code like it’s 1995.
 

0 Comments

I was tagged in: vsto vba excel

Tuesday, September 16, 2008

Range.Offset[a, b].value , when using VBA is a great way to add values to adjacent cells without having to actually select every cell you write to (which is very slow as it requires the UI). When I started using VSTO I could only find the Offset method attached to the strongly typed Named_Range object.


Luckily, it does exist for a regular range, except the method is called get_Offset (obviously).


So there you have it. Sounds simple, but this has been frustrating me for a couple of weeks now.


rangeObject.get_Offset[1, 2];
 

0 Comments

Page: 1 2 

Copyright Matthew Rathbone 2008 © : about me : contact