tag:blogger.com,1999:blog-74576294489788281382008-06-16T19:01:40.236-04:00Code For Excel And Outlook BlogJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comBlogger49125tag:blogger.com,1999:blog-7457629448978828138.post-43755935079012028182008-06-13T21:15:00.002-04:002008-06-13T21:34:05.454-04:00This blog has expired!Greetings,<br /><br />Please visit my new blog located at<br /><br /><a href="http://www.codeforexcelandoutlook.com/blog/">Code For Excel And Outlook</a><br /><br />All of the existing blog posts from this blog are on the new site, so there is literally nothing here to read anymore. Please point your links to the blog listed above.<br /><br />In a few weeks I will be redirecting all incoming links to the new blog, so you shouldn't see this blog any more after that.<br /><br />Thx,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-33467487653772920832008-06-10T23:17:00.001-04:002008-06-10T23:23:03.998-04:00Wordpress move almost completeGreetings,<br /><br />The move to Wordpress is underway and almost complete, please bear with me as posts are moved and updated. It's pretty wonky right now. I should have this done in the next day or two.<br /><br />Thx,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-6761594317601517342008-06-08T23:01:00.002-04:002008-06-08T23:21:41.071-04:00Moving to WordpressSo I finally got enlightened and decided to move the blog to Wordpress. I'll be moving all of the posts over to the new blog located at<br /><br /><a href="http://www.codeforexcelandoutlook.com/blog/">http://www.codeforexcelandoutlook.com/blog/</a><br /><br />some time in the next few days. And I'll attempt to keep the Feedburner feed going as well. Right now of course the new blog is empty and completely uncustomized, because it's Sunday at 11pm, and I spent part of the 90 degree NYC afternoon on Sunrise Highway in Freeport with a flat tire (instead of at the beach), so it's time for bed.<br /><br />So enjoy the old blog for now, soon it will be much cooler (no pun intended).<br /><br />Bye for now,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-76222024409142547122008-05-30T08:58:00.013-04:002008-05-30T19:38:15.872-04:00Highlight And Move Multiple EmailsOkay so I said I would be writing some VBA code to export contacts and emails from Outlook to Excel, well, I lied, sort of. That code is still coming, but before I post it, here is a routine that lets you run VBA code on multiple messages at the same time. Most of my routines so far have been written to run on one email at a time: <br /><br /><a href="http://www.codeforexcelandoutlook.com/ResendMsg.html">Resend This Message</a><br /><a href="http://www.codeforexcelandoutlook.com/2008/05/save-incoming-attachments-choose-your.html">Save Incoming Attachments</a><br /><a href="http://www.codeforexcelandoutlook.com/2008/05/read-those-image-files-in-outlook.html">Read those image files in Outlook</a><br /><br />and so on.<br /><br />This macro is perfect for manual execution of a routine on multiple emails. In the example below, I select a few emails from my Inbox and then move them to another folder. You could easily adapt this macro to forward all the selected messages, save attachments from all of them, etc.<br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Sub</span> MoveToFolder()<br /><br /><span style="color:#330099">Dim</span> olMyFldr <span style="color:#330099">As</span> Outlook.MAPIFolder<br /><span style="color:#330099">Dim</span> MsgColl <span style="color:#330099">As Object</span><br /><span style="color:#330099">Dim</span> Msg <span style="color:#330099">As</span> Outlook.MailItem<br /><span style="color:#330099">Dim</span> objNS <span style="color:#330099">As</span> Outlook.NameSpace<br /><span style="color:#330099">Dim</span> i <span style="color:#330099">As Long</span><br /><br /><span style="color:#339933">' check if we have multiple items selected</span><br /><span style="color:#330099">On Error Resume Next</span><br /><span style="color:#330099">Select Case</span> TypeName(Application.ActiveWindow)<br /> <span style="color:#330099">Case</span> "Explorer"<br /> <span style="color:#339933">' a collection of selected items</span><br /> <span style="color:#330099">Set</span> MsgColl = ActiveExplorer.Selection<br /> <span style="color:#330099">Case</span> "Inspector"<br /> <span style="color:#339933">' only one item was selected</span><br /> <span style="color:#330099">Set</span> Msg = ActiveInspector.CurrentItem<br /><span style="color:#330099">End Select</span><br /><span style="color:#330099">On Error GoTo 0</span><br /><br /><span style="color:#330099">If</span> (MsgColl <span style="color:#330099">Is Nothing</span>) <span style="color:#330099">And</span> (Msg <span style="color:#330099">Is Nothing</span>) <span style="color:#330099">Then</span><br /> <span style="color:#330099">GoTo</span> ExitProc<br /><span style="color:#330099">End If</span><br /><br /><span style="color:#330099">Set</span> objNS = Outlook.GetNamespace("MAPI")<br /><span style="color:#330099">Set</span> olMyFldr = objNS.GetDefaultFolder(olFolderInbox).Folders("Completed")<br /><br /><span style="color:#339933">' now we can act on the msg collection,<br />' or on the individual msg we selected</span><br /><br /><span style="color:#330099">If Not</span> MsgColl <span style="color:#330099">Is Nothing Then</span><br /><span style="color:#339933">' we selected multiple items</span><br /> <span style="color:#330099">For</span> i = 1 <span style="color:#330099">To</span> MsgColl.Count<br /> <span style="color:#339933">' set an obj reference to each mail item so we can move it</span><br /> <span style="color:#330099">Set</span> Msg = MsgColl.Item(i)<br /> <span style="color:#FF0000">With Msg<br /> .UnRead = False<br /> .Move olMyFldr<br /> End With</span><br /> <span style="color:#330099">Next</span> i<br /><span style="color:#330099">ElseIf Not</span> Msg <span style="color:#330099">Is Nothing Then</span><br /> <span style="color:#FF0000">With Msg<br /> .UnRead = False<br /> .Move olMyFldr<br /> End With</span><br /><span style="color:#330099">End If</span><br /><br /><span style="color:#330099">ExitProc:</span><br /><span style="color:#330099">Set</span> Msg = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> MsgColl = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> olMyFldr = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> objNS = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">End Sub</span><br /></pre><br /><br />I highlighted in red the sections you would replace with your own code. The first<br />part (right after "Set Msg = MsgColl.Item(i)") is the one that loops through each <br />selected message and runs your code. So you can move, forward, copy, export, reply <br />with attachments, etc, each mail item you selected. The second one runs only if one <br />mail item is selected.<br /><br />In both cases, the object variable "Msg" is a reference to the current mail item. <br />That's what you will be manipulating.<br /><br />If you're saving attachments, for extra credit try adding the SelectFolder() Function<br />from the <a href="http://www.codeforexcelandoutlook.com/2008/05/save-incoming-attachments-choose-your.html">Save Incoming Attachments</a> post.<br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-78062594979306238532008-05-28T21:21:00.008-04:002008-05-28T22:02:41.218-04:00Open Any Email Attachment From OutlookI was inspired to write some VBA code that lets you open any attachment in its native application by a recent newsgroup post from <a href="http://www.outlookcode.com/">Sue Mosher</a>. The truth is I was bored, and it was easy to code because I simply reused code I had just written for the <a href="http://www.codeforexcelandoutlook.com/2008/05/save-incoming-attachments-choose-your.html">Save Incoming Attachments</a> post. Hopefully the value of a stock code library will now be apparent to you.<br /><br />This code uses the <a href="http://msdn.microsoft.com/en-us/library/a74hyyw0(VS.85).aspx">Windows Script Host Object Model</a> to let Windows choose what program to use to open an attachment. Actually, it uses whatever file associations that were created when the program was installed. For example, .doc files usually open in Microsoft Word (if you have it installed).<br /><br />So instead of instantiating the object model for every possible attachment type (impossible), this method opens any attachment (as long as Windows knows what program to use). I haven't tested this with unknown attachments, so if anyone would like to try and let me know what happens (hopefully the file association dialog box appears), I'd be glad to hear it.<br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Sub</span> OpenAttachmentInNativeApp()<br /><br /><span style="color:#339933">' based on code posted by Sue Mosher<br />' http://tinyurl.com/684zg4</span><br /><span style="color:#330099">Dim</span> myShell <span style="color:#330099">As Object</span><br /><span style="color:#330099">Dim</span> MyItem <span style="color:#330099">As</span> Outlook.MailItem<br /><span style="color:#330099">Dim</span> myAttachments <span style="color:#330099">As</span> Outlook.Attachments<br /><span style="color:#330099">Dim</span> i <span style="color:#330099">As Long</span><br /><span style="color:#330099">Dim</span> Att <span style="color:#330099">As String</span><br /><br /><span style="color:#330099">On Error Resume Next</span><br /><span style="color:#330099">Select Case</span> TypeName(Application.ActiveWindow)<br /> <span style="color:#330099">Case</span> "Explorer"<br /> <span style="color:#330099">Set</span> MyItem = ActiveExplorer.Selection.Item(1)<br /> <span style="color:#330099">Case</span> "Inspector"<br /> <span style="color:#330099">Set</span> MyItem = ActiveInspector.CurrentItem<br /> <span style="color:#330099">Case Else</span><br /><span style="color:#330099">End Select</span><br /><span style="color:#330099">On Error GoTo 0</span><br /> <br /><span style="color:#330099">If</span> MyItem <span style="color:#330099">Is Nothing Then</span><br /> <span style="color:#330099">GoTo</span> ExitProc<br /><span style="color:#330099">End If</span><br /><br /><span style="color:#330099">Set</span> myAttachments = MyItem.Attachments<br /><br /><span style="color:#330099">If</span> myAttachments.Count > 0 <span style="color:#330099">Then</span><br /> <span style="color:#330099">For</span> i = 1 <span style="color:#330099">To</span> myAttachments.Count<br /> Att = myAttachments.Item(i).DisplayName<br /> <br /> <span style="color:#339933">' delete just in case it exists from before</span><br /> <span style="color:#330099">On Error Resume Next</span><br /> Kill "C:\" & Att<br /> <span style="color:#330099">On Error GoTo 0</span><br /> <br /> myAttachments.Item(i).SaveAsFile "C:\" & Att<br /> <span style="color:#330099">Next</span> i<br /><span style="color:#330099">End If</span><br /><br /><span style="color:#339933">' Windows Script Host Object</span><br /><span style="color:#330099">Set</span> myShell = CreateObject("WScript.Shell")<br />myShell.Run "C:\" & Att<br /><br /><span style="color:#330099">ExitProc:</span><br /><span style="color:#330099">Set</span> myAttachments = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> MyItem = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> myShell = <span style="color:#330099">Nothing</span><br /><br /><span style="color:#330099">End Sub</span><br /></pre><br /><br />And here's a link to the newsgroup thread:<br /><br /><a href="http://groups.google.com/group/microsoft.public.outlook.program_vba/browse_thread/thread/b109c73283723196/88c787ed13a610ad?hl=en">Open an attachment in a new window using its native application</a><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-20234644438689915182008-05-27T21:58:00.006-04:002008-05-27T23:12:32.510-04:00XML Parsing FunctionIn keeping with my <a href="http://www.codeforexcelandoutlook.com/2008/02/website-parsingretrieval-using-xml.html">Website XML parsing post</a>, here is a short function that returns the body text from a webpage as a string, on which you can use other functions like Instr, Left$, Mid$, etc, to extract necessary data.<br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Function</span> URLText(sURL <span style="color:#330099">As String</span>) <span style="color:#330099">As String</span><br /><br /><span style="color:#339933">' check website.com using xml</span><br /><span style="color:#339933">' early bound</span><br /><span style="color:#330099">Dim</span> xSite <span style="color:#330099">As</span> XMLHTTP60<br /><br /><span style="color:#330099">Set</span> xSite = <span style="color:#330099">New</span> XMLHTTP60<br />xSite.Open "GET", sURL, <span style="color:#330099">False</span><br />xSite.Send<br /><br /><span style="color:#330099">Do Until</span> xSite.readyState = 4<br /><span style="color:#330099">Loop</span><br /><br />URLText = xSite.responseText<br /><br /><span style="color:#330099">End Function</span><br /></pre><br /><br />And it's as simple as that. You could even use it as a UDF. Here's a sample sub:<br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Sub</span> CheckMySite()<br /><span style="color:#330099">Dim</span> MyString <span style="color:#330099">As String</span><br /><span style="color:#330099">Dim</span> i <span style="color:#330099">As Long</span><br /><br />MyString = URLText("http://www.google.com")<br /><br /><span style="color:#330099">If</span> Instr(MyString, "Hello!") > 0 <span style="color:#330099">Then</span><br /> Cells(5,1).Value = Mid$(MyString, 1, 5)<br /><span style="color:#330099">End If</span><br /><br /><span style="color:#330099">End Sub</span><br /></pre><br /><br />This sub checks if the returned string contains the word "Hello" and if so, pulls the first five characters of the text and puts it in cell A5. It's just an arbitrary routine to show you what you can do with the XML response.<br /><br />For my next trick, I will be showing you a routine that takes a snapshot of your Outlook inbox and writes it to a spreadsheet. I'm also planning on demonstrating some code that exports Contacts from Outlook to Excel.<br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-10602425831738892822008-05-22T21:46:00.020-04:002008-05-27T21:51:44.511-04:00Save Incoming Attachments, Choose Your FolderHere's a sub and a function for Outlook that let's you save attachments from a selected or open email. It's similar to the <a href="http://email.about.com/od/outlooktips/qt/et121202.htm">File>Save Attachments menu option</a>, which lets you save all of the attachments from a particular email, or the <a href="http://msdn.microsoft.com/en-us/library/aa171234(office.11).aspx">FindControl Method</a>, which can be used to find and execute "Save Attachments". <br /><br />Now I realize that there is already a ton of code available that you can use to save attachments, but I found some code that uses the Shell application to let you pick the folder you want to use as the destination. So my purpose here is to demonstrate how to use this code in a simple routine.<br /><br />It's a great technique and, since it is a separate function, it is very portable to other subs where you want to let the user pick a folder on their hard drive or network drive as the destination for files you want to save or use in a routine. It simply returns the full path as a string. <br /><br />As you can see below, the String variable "SelectedFolder" is used to store the returned results from the SelectFolder() Function.<br /><br />As usual, we set an object reference to a Mail Item, then loop through the attachments collection of that mail item and save each one. Notice that the bulk of the work is done inside the If statement (but outside the loop) to avoid costly object references that might be useless if the email doesn't have attachments (for example, if you run this code on the wrong email by mistake).<br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Sub</span> GoThroughAttachments()<br /><span style="color:#330099">Dim</span> MyItem <span style="color:#330099">As</span> Outlook.MailItem<br /><span style="color:#330099">Dim</span> myAttachments <span style="color:#330099">As</span> Outlook.Attachments<br /><span style="color:#330099">Dim</span> i <span style="color:#330099">As Long</span><br /><span style="color:#330099">Dim</span> Att <span style="color:#330099">As String</span><br /><span style="color:#330099">Dim</span> SelectedFolder <span style="color:#330099">As String</span><br /><br /><span style="color:#330099">On Error Resume Next</span><br /><span style="color:#330099">Select Case</span> TypeName(Application.ActiveWindow)<br /> <span style="color:#330099">Case</span> "Explorer"<br /> <span style="color:#330099">Set</span> MyItem = ActiveExplorer.Selection.Item(1)<br /> <span style="color:#330099">Case</span> "Inspector"<br /> <span style="color:#330099">Set</span> MyItem = ActiveInspector.CurrentItem<br /> <span style="color:#330099">Case Else</span><br /><span style="color:#330099">End Select</span><br /><span style="color:#330099">On Error GoTo 0</span><br /> <br /><span style="color:#330099">If</span> MyItem <span style="color:#330099">Is Nothing Then</span><br /> <span style="color:#330099">GoTo</span> ExitProc<br /><span style="color:#330099">End If</span><br /><br /><span style="color:#330099">If</span> MyItem.Attachments.Count > 0 <span style="color:#330099">Then</span><br /> SelectedFolder = SelectFolder()<br /><br /> <span style="color:#330099">If</span> SelectedFolder <> "" <span style="color:#330099">Then</span> <span style="color:#339933">' user didn't press Cancel</span><br /><br /> <span style="color:#330099">Set</span> myAttachments = MyItem.Attachments<br /><br /> <span style="color:#330099">For</span> i = 1 <span style="color:#330099">To</span> myAttachments.Count<br /> Att = myAttachments.Item(i).DisplayName<br /> myAttachments.Item(i).SaveAsFile SelectedFolder & "\" & Att<br /> <span style="color:#330099">Next</span> i<br /> <span style="color:#330099">End If</span><br /><span style="color:#330099">End If</span><br /><br /><span style="color:#330099">ExitProc:</span><br /><span style="color:#330099">Set</span> myAttachments = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> MyItem = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">End Sub</span><br /></pre><br /><hr><br /><pre style="font-size:small"><br /><span style="color:#330099">Private Function</span> SelectFolder(<span style="color:#330099">Optional</span> i_RootFolder <span style="color:#330099">As String</span>) <span style="color:#330099">As String</span><br /><span style="color:#339933">' from http://vba-corner.livejournal.com/</span><br /><span style="color:#330099">Dim</span> myShell <span style="color:#330099">As Object</span><br /><span style="color:#330099">Dim</span> MyFolder <span style="color:#330099">As Object</span><br /><br /> <span style="color:#330099">Set</span> myShell = CreateObject("Shell.Application")<br /> <span style="color:#330099">If</span> i_RootFolder = "" <span style="color:#330099">Then</span><br /> <span style="color:#339933">'no root folder given, use default (which is Desktop)</span><br /> <span style="color:#330099">Set</span> MyFolder = myShell.BrowseForFolder(0, "Please select a folder:", 1)<br /> <span style="color:#330099">ElseIf Not</span> (i_RootFolder <span style="color:#330099">Like</span> "*[!0123456789]*") <span style="color:#330099">Then</span><br /> <span style="color:#339933">'number for special folder given</span><br /> <span style="color:#330099">Set</span> MyFolder = myShell.BrowseForFolder(0, _<br /> "Please select a folder:", 1, CInt(i_RootFolder))<br /> <span style="color:#330099">Else</span><br /> <span style="color:#339933">'path for root folder given</span><br /> <span style="color:#330099">Set</span> MyFolder = myShell.BrowseForFolder(0, _<br /> "Please select a folder:", 1, CStr(i_RootFolder))<br /> <span style="color:#330099">End If</span><br /> <span style="color:#330099">If Not</span> MyFolder <span style="color:#330099">Is Nothing Then</span><br /> SelectFolder = MyFolder.self.Path<br /> <span style="color:#330099">End If</span><br /><span style="color:#330099">End Function</span><br /></pre><br /><br />Notice that the SelectFolder() Function does not include the trailing slash at the end, so we need to add this when saving the file.<br /><br />If you wanted to simply use the same folder every time (for example, C:\MyFiles\), just comment out this line:<br /><br />SelectedFolder = SelectFolder()<br /><br />Remove the inner If-End-If statement (If SelectedFolder <> "" Then) and change this line:<br /><br />myAttachments.Item(i).SaveAsFile SelectedFolder & "\" & Att<br /><br />to this:<br /><br />myAttachments.Item(i).SaveAsFile "C:\MyFiles\" & Att<br /><br />But why would you want to do a thing like that, when the Shell automation is so much cooler?<br /><br />Click here to see how to <a href="http://www.codeforexcelandoutlook.com/ResendMsg.html">add this code to a toolbar button in Outlook</a>.<br /><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-41956338578337824222008-05-22T13:10:00.013-04:002008-05-30T09:10:39.445-04:00Read those image files in OutlookI recently discovered a new object library that seems pretty useful - the <a href="http://msdn.microsoft.com/en-us/library/aa167607(office.11).aspx">Microsoft Office Document Imaging Type Library</a>. From the MSDN site:<br /><br />The Microsoft® Office Document Imaging 2003 (MODI) object model makes it possible to develop custom applications for managing document images (such as scanned and faxed documents) and the recognizable text that they contain. <br /><br />(end quote)<br /><br />This object model is not available in Office 2002(XP).<br /><br />Continuing with the Outlook theme from my latest blog posts, I can already see the potential for automating Outlook by handling incoming emails, opening image file attachments, then filing, saving or forwarding them depending on the image content, or using Excel to browse through a folder and doing the same thing. I wrote a short sub that can show you how to read an image file that is sent to you via Outlook attachment.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.codeforexcelandoutlook.com/uploaded_images/MODILibrary-732906.JPG"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://www.codeforexcelandoutlook.com/uploaded_images/MODILibrary-732904.JPG" border="0" alt="" /></a><br />First you must set a reference to the Microsoft Office Document Imaging 11.0 Type Library. Here's mine on the left. And below is the code.<br /><br /><br /><br /><br /><br /><br /><br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Sub</span> ReadAttachment()<br /><br /><span style="color:#330099">Dim</span> MyItem <span style="color:#330099">As</span> Outlook.MailItem<br /><span style="color:#330099">Dim</span> MyAttach <span style="color:#330099">As</span> Outlook.Attachments<br /><span style="color:#330099">Dim</span> MyDoc <span style="color:#330099">As</span> MODI.Document<br /><span style="color:#330099">Dim</span> MyLayout <span style="color:#330099">As</span> MODI.Layout<br /><span style="color:#330099">Dim</span> Att <span style="color:#330099">As</span> String<br /><span style="color:#330099">Dim</span> strWords <span style="color:#330099">As</span> String<br /><span style="color:#330099">Dim</span> int <span style="color:#330099">As Long</span><br /><br /> <span style="color:#330099">On Error Resume Next</span><br /> <span style="color:#330099">Select Case</span> TypeName(Application.ActiveWindow)<br /> <span style="color:#330099">Case</span> "Explorer"<br /> <span style="color:#330099">Set</span> MyItem = ActiveExplorer.Selection.Item(1)<br /> <span style="color:#330099">Case</span> "Inspector"<br /> <span style="color:#330099">Set</span> MyItem = ActiveInspector.CurrentItem<br /> <span style="color:#330099">Case Else</span><br /> <span style="color:#330099">End Select</span><br /> <span style="color:#330099">On Error GoTo 0</span><br /> <br /> <span style="color:#330099">If</span> MyItem <span style="color:#330099">Is Nothing Then</span><br /> <span style="color:#330099">GoTo ExitProc</span><br /> <span style="color:#330099">End If</span><br /><br /></pre><br /><br /><p><br />This bit of code should be familiar, it is the stock code I always use to get a reference<br />to an item in a mail folder. Of course, the code assumes that you are acting on a mail item; to make sure, change "Dim MyItem As Outlook.MailItem" to <br />"Dim MyItem As Object" and then wrap the rest of the code below in a <br />"If MyItem.Class = olMail" statement. Or, just make sure you select or open a mail item before running this code.<br /></p><br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Set</span> MyAttach = MyItem.Attachments<br /><br /><span style="color:#330099">If</span> MyAttach.Count > 0 <span style="color:#330099">Then</span><br /><br /> Att = "C:\" & MyAttach.Item(1).DisplayName<br /> MyAttach.Item(1).SaveAsFile Att<br /> <br /> <span style="color:#330099">Set</span> MyDoc = <span style="color:#330099">New</span> MODI.Document<br /> <br /> MyDoc.create (Att)<br /><br /> MyDoc.images(0).OCR<br /> <br /> <span style="color:#330099">Set</span> MyLayout = MyDoc.images(0).Layout<br /> <br /> <span style="color:#330099">For</span> int = 0 <span style="color:#330099">To</span> (MyLayout.NumWords - 1)<br /> strWords = strWords & " " & MyLayout.Words(int).Text<br /> <span style="color:#330099">Next</span> int<br /> <br /> MsgBox strWords<br /> <br /><span style="color:#330099">Else</span><br /> <span style="color:#330099">GoTo ExitProc</span><br /><span style="color:#330099">End If</span><br /><br /><br />ExitProc:<br /><span style="color:#330099">Set</span> MyItem = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> MyAttach = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> MyDoc = <span style="color:#330099">Nothing</span><br /><span style="color:#330099">Set</span> MyLayout = <span style="color:#330099">Nothing</span><br /><br /><span style="color:#330099">On Error Resume Next</span><br /> Kill Att<br /><span style="color:#330099">On Error GoTo 0</span><br /><br /><span style="color:#330099">End Sub</span><br /></pre><br /><br />The rest of the code simply saves the attachment to a file on the hard drive, creates a new image document, then builds a string consisting of the readable characters in the image file. That string could be parsed to see if it contains something you are looking for, for example<br /><br /><pre style="font-size:small"><br /><span style="color:#330099">If</span> Instr(strWords, "My String") > 0 <span style="color:#330099">Then</span><br /><span style="color:#339933">' your code here</span><br /><span style="color:#330099">End If</span><br /></pre><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-68694894078311038172008-05-12T20:12:00.010-04:002008-05-15T21:18:45.902-04:00Outlook Automated File Request SystemHere is the finished code for the Outlook File Request System.<br /><br /><a href="http://www.codeforexcelandoutlook.com/FileServer.html">File Server Code</a><br /><br />This is event code which acts as an automated file server, putting files into the specified folder, and sending files back to the requestor, all via email. Once the code is installed, another user requests a file from you by using the following syntax in the Subject line:<br /><br />Subject: <span style="font-weight:bold;">FILEGET drive:path\filename</span><br /><br />Where 'drive' is is a valid drive letter, 'path' is the folder and 'filename' is the name of the file requested.<br /><br />For example,<br /><br />Subject: FILEGET E:\Files\MyFile.doc<br /><br />To send a file to another user's folder, subject should be:<br /><br />Subject: <span style="font-weight:bold;">FILEPUT D:\</span><br /><br />And there should be at least one attachment to the email. All attachments will be saved to the same folder.<br /><br />Note that for security reasons, I limited access to the C: drive, however if you set up a folder called 'Shared' on your desktop (Windows 2000/XP), you can place files there that you want to share, and others can request files from there. Of course if this isn't a concern for you, you can simply remove those restrictions.<br /><br />Due to object model restrictions, I decided to remove the feature that replies to the group (if applicable). For example, if you CC: five other people on your request, the code simply ignores the other recipients. Originally, I had it set up to reply to them all. However, accessing the Recipients collection of the mail item triggered the object model guard, which was contrary to the intent of the code which is to fully automate the request process. You'd have to sit there clicking 'OK' every time someone sent you a request!<br /><br />All of this is done via Outlook automation. Due to the blogging software I use (which I'll probably change soon) I cannot post the full code here. I will be demonstrating some of the techniques used to produce this code; click the link above to get the entire thing in the proper format.<br /><br />First, we initialize the event code using the following code which should be familiar to you by now, if you have browsed the <a href="http://www.codeforexcelandoutlook.com/Outlook.html">Outlook</a> page. This is stock code which should be part of your code library to be reused over and over. <br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Private WithEvents</span> Items <span style="color:#330099">As</span> Outlook.Items<br /><br /><span style="color:#330099">Private Sub</span> Application_Startup()<br /><br /><span style="color:#330099">Dim</span> objNS <span style="color:#330099">As</span> Outlook.NameSpace<br /> <span style="color:#330099">Set</span> objNS = GetNamespace("MAPI")<br /> <span style="color:#330099">Set</span> Items = objNS.GetDefaultFolder(olFolderInbox).Items<br /><span style="color:#330099">End Sub</span><br /></pre><br /><br />All of this code should be placed in ThisOutlookSession module in your Outlook VBE. Just press Alt-F11, double-click on ThisOutlookSession and paste in the above code. Remember, after you install (or edit) the code in this module, you have to restart Outlook for any changes to take effect. Also, any existing code you have seems to stop working until you save and restart Outlook. <br /><br />Here is the ItemAdd event code that is checking the Inbox for new mail items. We first set an object reference to the mail item that is passed as an argument. Then we determine the full path of the user's desktop folder, to figure out where the 'Shared' folder should sit. Keep in mind this will only work pre-Windows Vista. Then we check the subject line to see if it fits what we are looking for.<br /><br /><pre style="font-size:small"><br /><span style="color:#330099">Private Sub</span> Items_ItemAdd(<span style="color:#330099">ByVal</span> item <span style="color:#330099">As Object</span>)<br /><br /><span style="color:#330099">If</span> TypeName(item) = "MailItem" <span style="color:#330099">Then</span><br /> <span style="color:#330099">Dim</span> ToDo <span style="color:#330099">As String</span><br /> <span style="color:#330099">Dim</span> WhatAndWhere <span style="color:#330099">As String</span><br /> <span style="color:#330099">Dim</span> Msg <span style="color:#330099">As</span> Outlook.MailItem<br /> <span style="color:#330099">Dim</span> MsgAttach <span style="color:#330099">As</span> Outlook.Attachments<br /> <span style="color:#330099">Dim</span> MsgReply <span style="color:#330099">As</span> Outlook.MailItem<br /> <span style="color:#330099">Dim</span> SlashSign <span style="color:#330099">As Long</span><br /> <span style="color:#330099">Dim</span> sPath <span style="color:#330099">As String</span><br /> <span style="color:#330099">Dim</span> sFile <span style="color:#330099">As String</span><br /> <span style="color:#330099">Dim</span> fso <span style="color:#330099">As Object</span><br /> <span style="color:#330099">Dim</span> UserN <span style="color:#330099">As String</span><br /> <span style="color:#330099">Dim</span> DeskTopSharedFolder <span style="color:#330099">As String</span><br /> <span style="color:#330099">Dim</span> strHelpText <span style="color:#330099">As String</span><br /><br /><span style="color:#339933">' the mailitem is passed to the event code as an argument</span><br /><span style="color:#330099">Set</span> Msg = item<br /><br /><span style="color:#339933">' get current username so we can figure out the desktop folder name</span><br />UserN = Environ("username")<br />DeskTopSharedFolder = "C:\Documents And Settings\" & _<br />UserN & "\Desktop\Shared\"<br /><br /><span style="color:#330099">On Error Resume Next</span><br />ToDo = Left$(Msg.Subject, 7)<br />WhatAndWhere = Right$(Msg.Subject, Len(Msg.Subject) - 8)<br /><span style="color:#330099">On Error GoTo 0</span><br /></pre><br /><br />At this point we either have a FILEGET request or a FILEPUT request (or maybe neither). Then we cycle through every possible error condition (no attachments, malformed subject) and, if no errors occurred, call the sending sub which sends back the file requested (or saves the attachments to the specified folder).<br /><br />In the interest of modular programming, there are actually four separate subs which each do something different:<br /><br />1) The File Server Sub, acting as an intermediary sub which takes the validated user-input and passes it to the sending sub.<br /><br />2) The Sending Sub, which takes four arguments (two optional) and is responsible for sending out all emails.<br /><br />3) The Logging Sub, which (if you allow it) logs all file requests and sends to a CSV file, and<br /><br />4) A String Checking Sub which checks if one string is found within another and returns a Boolean value (True or False).<br /><br />Check out the full code here.<br /><br /><a href="http://www.codeforexcelandoutlook.com/FileServer.html">File Server Code</a><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-65735144623990622492008-05-10T11:37:00.006-04:002008-05-10T12:00:55.865-04:00Free VB/C#/C++ SoftwareIn keeping with the theme from my <a href="http://www.codeforexcelandoutlook.com/2008/05/vba-rant-1.html">last post</a>, I started looking for tutorials or software for other programming languages that might make an eventual transition to VSTO easier. I found some useful software from Microsoft that is actually free.<br /><br />Check out:<br /><a href="http://www.microsoft.com/express/download/">http://www.microsoft.com/express/download/</a><br /><br />You can download "lite" versions of VB 2008, C# 2008, C++ 2008, SQL Server 2005, as well as something called Visual Web Developer 2008.<br /><br />The one that looks most interesting to me is SQL Server, which I installed but have yet to try out. My plan is to use it to further understand the syntax and commands of SQL. I also installed VB Express, and sooner or later I'll get around to trying it.<br /><br />One of the blurbs that actually made me laugh said "Control your home lights using Visual Basic Express". I just use the Off switch.<br /><br />Unfortunately you need to install their <a href="http://www.microsoft.com/silverlight/">Silverlight</a> technology to properly view the page. Whatever happened to plain old HTML?<br /><br />They also offer a DVD image you can download and burn. Seems convenient, but why anyone would want to do this, I don't know.<br /><br />So check it out and let me know if you download or try any of them out.<br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-7290982861271968222008-05-07T23:17:00.006-04:002008-05-08T00:10:59.059-04:00VBA Rant #1I'm sure by now you are aware that Microsoft has been distancing itself from VBA.<br /><br />As of July 1, 2007, they are <a href="http://msdn.microsoft.com/en-us/isv/bb190538.aspx">no longer licensing VBA</a> (to new clients). For example, if you wrote a program today and wanted to integrate VBA in it, you are out of luck.<br /><br />And the new version of Office for Mac <a href="http://www.macwindows.com/office2008.html#021107b">will not support VBA at all</a>.<br /><br />They seem to be pushing their other technologies like <a href="http://msdn.microsoft.com/en-us/office/aa905533.aspx">VSTO</a> for automating Office programs.<br /><br />I feel I have to weigh in on this subject because it seems like Microsoft used VBA to lock users into using their software, and is now abandoning them.<br /><br />Now I realize VBA will still be around for many years. Hell, XLM macros are still working in Excel even after VBA was introduced 13 years ago to replace it. I still see newsgroup posts from people asking for help with macros in Excel 97 (11 years old!). But how long will Microsoft maintain backward compatibility with a language it is discouraging people from using?<br /><br />I have browsed other languages like .NET, C++, and realize just how familiar VBA is. Maybe it's "Grumpy Old Man Syndrome" setting in early; I can already hear myself saying things like "Back in my day, you could write a macro in 5 minutes to list all the files in a folder!"<br /><br />This is going to mean that, in general, code will start getting harder to find. VBA is the People's Code; simple to integrate and implement by almost anyone with a little experience. In contrast, you would almost have to be a <em><strong>professional developer</strong></em> to get code working in another language to interact with Office. <br /><br />"Visual Studio Tools for Applications makes it easier to write reliable, robust, and secure customizations by providing managed extensibility for both COM and .NET applications." [From <a href="http://msdn.microsoft.com/en-us/vsx2008/products/bb933739.aspx">VSTO</a> Site]<br /><br />It reminds me of the <a href="http://www.unitedmedia.com/comics/dilbert/games/career/bin/ms.cgi">Mission Statement Generator</a> from Dilbert's website.<br /><br />Will VBA eventually be deprecated? Will people still be coding in VBA 20 years from now? Or am I just completely off it and worrying about nothing? I will accept any suggestions for what programming language I should start learning.<br /><br /><br />--JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-82269101295175498712008-05-03T00:04:00.003-04:002008-05-03T00:35:46.115-04:00Excel training class and Outlook file request system updatesI've been mentioning the Excel training class for some time now, finally the curriculum is coming together and I finally got off my lazy butt and have almost completed the handouts and sample worksheets. I am hoping with fingers crossed to have this finally completed by the end of next week. Then I have to start taking public speaking classes to learn how to present this material in a way that won't put people to sleep. For practice, try explaining to someone an INDEX/MATCH array in a way that makes it sound fun!<br /><br />In other news, the file request code I have been working on for Outlook is coming along quite nicely. It consists of three subs in a standard module, and the event code which would be placed in ThisOutlookSession. It's designed for business users (AKA "office drones like me") with network shares, who have better things to do than act as a human file server pushing files around all day. Let your lazy co-workers do it themselves! It would make you a hero while at the same time give you less work to do! Here are some of the features:<br /><br />Request from, or submit files to, another user's computer or network share<br /><br />C: drive is blocked, but you can create a folder on your desktop called "Shared" and place files in there that you want others to have access to (or place files in)<br /><br />Friendly error messages in case of malformed requests (i.e. invalid path, no attachments).<br /><br />Requestor can CC: others, and the code will send the requested file (along with confirmation email), to each of the recipients of the original message. However, ugly error messages are sent back to the original requestor only.<br /><br />It also includes a built-in Help system, via the event code where users get an email back with instructions on how to request or send files to a folder. The instructions are also included at the bottom of every confirmation email.<br /><br />All file sends and requests are logged to a .CSV file, the location and filename of which you can change as needed. The filename is passed as an argument to the function, so for example, you could update the code to write to different log files depending on whether someone was sending a file, or requesting a file. However the code as it stands will distinguish between the two when logging the request. Errors are also logged.<br /><br />It's almost like a Kazaa or Limewire type setup where you have a shared folder and you trade files with other users, only in this case it's via email. And (hopefully, in your case) it's legal.<br /><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-30716141955923864512008-04-28T21:30:00.004-04:002008-04-28T21:41:47.079-04:00Internet Explorer Automation Object Library - Update for Excel 2007One of the most popular pages on this site shows code for <a href="http://www.codeforexcelandoutlook.com/AutomateInetExplorer.html">automating Internet Explorer</a>. However I have only tested the code in Excel XP/2003. The purpose of this post is to credit a gentleman named Durand Sinclair who, using Excel 2007, pointed out to me that the name of the IE object library in Excel 2007 is actually called "Microsoft Browser Helper" (click Tools>References in the VBE). Once you select the checkbox, exit the dialog box and re-enter it, the name changes to "Microsoft Internet Controls".<br /><br />If anyone else would like to verify this behavior in Excel 2007 and let me know, I would be grateful to hear it.<br /><br />Thanks Durand!<br /><br />--JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-2754718533661076652008-04-28T21:16:00.003-04:002008-04-28T21:43:38.050-04:00Contribute to this site!It's not what you think.<br /><br />I'm asking for contributors to the VBA search engine! <br /><br />If you know of a website with VBA samples, or think you have what it takes to identify good websites with code, I'd like to know about it. <br /><br />Visit the <a href="http://tinyurl.com/43kgod">VBA Search Engine Homepage</a> and click "Volunteer to contribute". Send me a message (<a href="http://www.codeforexcelandoutlook.com/Contact.html">click here</a>) and let me know you are going to do so.<br /><br />You'll need a Google account to contribute to the search engine. An added bonus is you can add the search box to your Google homepage, so you can search whenever you want, and (if my eyes don't deceive me) you can also add the search engine code to your own blog or website!<br /><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-9306734959336958302008-04-27T10:03:00.006-04:002008-04-28T06:46:59.046-04:00Event Code for Forwarding Selected Text to Another Email AddressHere is the event code I promised for forwarding emails to another email address. It does exactly the same thing as the previous code, but since it is event code, once you place it in a class module and restart Outlook, it runs automatically without any need for you to run macros by hand.<br /><br />Start by pasting the following into the ThisOutlookSession module:<br /><br /><pre style="font-size:small; color:#000000"><br /><br /><SPAN style="color:#330099">Private WithEvents</span> Items <SPAN style="color:#330099">As</span> Outlook.Items<br /><br /><br /><SPAN style="color:#330099">Private Sub</span> Application_Startup()<br /><SPAN style="color:#330099">Dim</span> objNS <SPAN style="color:#330099">As</span> Outlook.NameSpace<br /> <SPAN style="color:#330099">Set</span> objNS = GetNamespace("MAPI")<br /> <SPAN style="color:#330099">Set</span> Items = objNS.GetDefaultFolder _<br /> (olFolderInbox).Items<br /><SPAN style="color:#330099">End Sub</span><br /></pre><br /><br />This code will set up the event handler. If you already have an Application_Startup event, simply copy and paste the inner code into it. Of course you'll want to check that you aren't duplicating any code; Option Explicit and a quick Debug>Compile will check for that.<br /><br />The ItemAdd event will check any newly added items to the Inbox, and, if they meet the criteria we specify, a new mail item is created (via the Forward method) and sent to the email address of our choice. Then the original message is marked as read and neatly tucked away. Here is the complete code:<br /><br /><br /><pre style="font-size:small; color:#000000"><br /><SPAN style="color:#330099">Private WithEvents</span> Items <SPAN style="color:#330099">As</span> Outlook.Items<br /><br /><br /><SPAN style="color:#330099">Private Sub</span> Application_Startup()<br /><SPAN style="color:#330099">Dim</span> objNS <SPAN style="color:#330099">As</span> Outlook.NameSpace<br /><SPAN style="color:#330099">Set</span> objNS = GetNamespace("MAPI")<br /><SPAN style="color:#330099">Set</span> Items = objNS.GetDefaultFolder _<br /> (olFolderInbox).Items<br /><SPAN style="color:#330099">End Sub</span><br /><br /><br /><SPAN style="color:#330099">Private Sub</span> Items_ItemAdd(<SPAN style="color:#330099">ByVal</span> item <SPAN style="color:#330099">As Object</span>)<br /><br /><SPAN style="color:#330099">If</span> item.Class = olMail <SPAN style="color:#330099">Then</span><br /> <SPAN style="color:#330099">If</span> Left$(item.Subject, 16) = _<br /> "String to search" <SPAN style="color:#330099">Then</span><br /> <SPAN style="color:#330099">Dim</span> Msg <SPAN style="color:#330099">As</span> Outlook.MailItem<br /> <SPAN style="color:#330099">Dim</span> NewForward <SPAN style="color:#330099">As</span> Outlook.MailItem<br /> <SPAN style="color:#330099">Dim</span> MyFolder <SPAN style="color:#330099">As</span> Outlook.MAPIFolder<br /> <SPAN style="color:#330099">Dim</span> olApp <SPAN style="color:#330099">As</span> Outlook.Application<br /> <SPAN style="color:#330099">Dim</span> olNS <SPAN style="color:#330099">As</span> Outlook.NameSpace<br /><br /> <SPAN style="color:#330099">Set</span> Msg = item<br /> <SPAN style="color:#330099">Set</span> NewForward = Msg.Forward<br /> <SPAN style="color:#330099">Set</span> olApp = Outlook.Application<br /> <SPAN style="color:#330099">Set</span> olNS = olApp.GetNamespace("MAPI")<br /> <SPAN style="color:#330099">Set</span> MyFolder = olNS.GetDefaultFolder _<br /> (olFolderInbox).Folders("Archive")<br /><br /> <SPAN style="color:#330099">With</span> NewForward<br /> .Subject = _<br /> Right(Msg.Subject, Len(Msg.Subject) _<br /> - InStrRev(Msg.Subject, " "))<br /> .To = "myemail@mobiledevice.com"<br /> .HTMLBody = ""<br /> .Send<br /> <SPAN style="color:#330099">End With</span><br /><br /> <SPAN style="color:#330099">With</span> Msg<br /> .UnRead = <SPAN style="color:#330099">False</span><br /> .FlagStatus = olNoFlag<br /> .Move MyFolder<br /> <SPAN style="color:#330099">End With</span><br /> <SPAN style="color:#330099">End If</span><br /><SPAN style="color:#330099">End If</span><br /><br />ExitProc:<br /><SPAN style="color:#330099">Set</span> NewForward = <SPAN style="color:#330099">Nothing</span><br /><SPAN style="color:#330099">Set</span> Msg = <SPAN style="color:#330099">Nothing</span><br /><SPAN style="color:#330099">Set</span> olApp = <SPAN style="color:#330099">Nothing</span><br /><SPAN style="color:#330099">Set</span> olNS = <SPAN style="color:#330099">Nothing</span><br /><SPAN style="color:#330099">Set</span> MyFolder = <SPAN style="color:#330099">Nothing</span><br /><SPAN style="color:#330099">End Sub</span><br /></pre><br /><br />Paste this into the ThisOutlookSession module, save and restart Outlook to get the code to start working.<br /><br />I chose some arbitrary criteria (the first 16 characters of the Subject Line), you would need to customize this for your needs.JPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-55639679723538015542008-04-26T22:07:00.013-04:002008-04-26T23:08:54.831-04:00Custom CSS tags for displaying well-formed VBA codeSo you might be wondering, what does VBA have to do with a web technology like CSS? If you are like me and you hand-code your website, you might find it difficult to display VBA code properly. Unfortunately, I can't seem to locate a copy of <a href="http://www.dicks-blog.com/archives/2004/05/14/vba-to-html/">zHTML</a>, and the <a href="http://www.mrexcel.com/vbaddin.shtml">other VBA-to-HTML converters I tried</a> just don't seem to satisfy.<br /><br />Since my website is formatted using CSS, I did a bit of digging and found I could <a href="http://www.netmechanic.com/news/vol7/css_no7.htm">create my own HTML tags</a>. I was already using the PRE and TEXTAREA tags to format snippets of VBA code, but this technique allows you to create custom tags that make it simple to roll your own webpages. So I went ahead and wrote some CSS to format the four most commonly posted types of VBA code: Normal, Selection, Comment and Keyword Text. Here it is:<br /><br />.vba<br />{ color: #000000;<br /> background: #FFFFFF;<br /> padding: 10px 10px 10px 10px;<br /> font-size: 100%<br />}<br />.selected<br />{ color: #FFFFFF;<br /> background: #330099;<br /> }<br />.comment<br />{ color: #339933;<br /> background: #FFFFFF;<br />}<br />.keyword<br />{ color: #330099;<br /> background: #FFFFFF;<br />}<br /><br />Paste the above code into the .css file that defines your site's layout. You can fiddle with the background color to make it suit your site better. Now you can wrap your VBA code in tags like this:<br /><pre style="font-size:small"><br /><pre class="vba"><br /><span class="keyword">Sub</span> fixformulas()<br /><span class="comment">'<br />' if you have some formulas with a ' or some other<br />' character in the beginning<br />'</span><br /><span class="keyword">Dim</span> cell<br /><span class="keyword">As</span> Excel.Range<br /><span class="keyword">For Each</span> cell <br /><span class="keyword">In </span> Selection<br /> cell = "=" & Right(cell, Len(cell) - 1)<br /><span class="keyword">Next</span> cell<br /><span class="keyword">End Sub</span><br /></pre><br /></pre><br /><br />And it will display like this:<br /><br /><pre style="font-size:small"><br /><SPAN style="color:#330099">Sub</span> fixformulas()<br /><SPAN style="color:#339933">'<br />' if you have some formulas with a ' or some other <br />' character in the beginning<br />'</span><br /><SPAN style="color:#330099">Dim</span> cell <SPAN style="color:#330099">As </span> Excel.Range<br /><SPAN style="color:#330099">For Each</span> cell <SPAN style="color:#330099">In</span> Selection<br /> cell = "=" & Right(cell, Len(cell) - 1)<br /><SPAN style="color:#330099">Next</span> cell<br /><SPAN style="color:#330099">End Sub</span><br /></pre><br /><br /><p></p><br />The PRE tag wraps the area in the "vba" tag, which is the default black-on-white<br />text used to display most VBA code (if you haven't fiddled with the default settings in the VBE). So any code that isn't wrapped in a span tag will automatically take on the default color, which is the intuitive way the VBE does it. <br /><br />Instead of using the deprecated FONT tags or trying to guess the hex values for colors every time you want to use them, you can use friendly words like "keyword" or "comment" in your SPAN tags and the code will be colored accordingly. The PRE tag will also make sure the code is indented properly!<br /><br />Eventually I'll convert all the existing code to this format, and all future code posted on the blog and the website will be displayed using these custom made CSS class tags.<br /><br />(ps- the Outlook event code I promised last week is coming up in the next day or two. I was away this week so I have a lot of catching up to do.)<br /><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-9678537803728413252008-04-16T22:22:00.016-04:002008-04-17T12:20:04.217-04:00Forwarding Selected Text to Another Email AddressGreetings,<br /><br />I would like to share some code I wrote last month for a user who visited my website and asked for a macro that would look for specific text in the subject of an email and forward it to another email address (in this case, an email for a mobile device). I created two versions: a Sub procedure that could be run on demand, and Event code that would automatically (in the "hands off" spirit) forward a specially crafted email.<br /><br />In this post I will show the macro you would assign to a toolbar button. If you want to add this (or any other) macro to your Outlook toolbar, check out "How to assign a macro to a toolbar button" on <a href="http://www.codeforexcelandoutlook.com/ResendMsg.html">this page</a>. In the next post I will follow up with the Event code.<br /><br />The toolbar code should be placed in a standard module in your Outlook VB Project.<br /><br /><br /><a href="http://www.codeforexcelandoutlook.com/uploaded_images/toolbarcode1-741666.JPG"><img style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 396px; CURSOR: hand; HEIGHT: 267px" height="267" alt="" src="http://www.codeforexcelandoutlook.com/uploaded_images/toolbarcode1-741662.JPG" width="456" border="0" /></a><span style="font-size:180%;">F</span>irst we check what type of window we are looking at by checking the ActiveWindow Property of the Application object; if it is an Explorer, that means we don't have any emails open, so we set an object reference to the first selected item. If it is an Inspector, we have an email or other item open for viewing, so we set an object reference to it. Of course, if there is no selected item, or no open item, the code fails with an error because we can't run it.<br /><br /><br /><pre><br /><span style="font-size:85%;color:#660000;">Sub FwdMailText()</span><br /><span style="font-size:85%;color:#660000;">Dim objItem As Object</span><br /><span style="font-size:85%;color:#660000;">Dim Msg As Outlook.MailItem</span><br /><span style="font-size:85%;color:#660000;">Dim NewForward As Outlook.MailItem</span><br /><span style="font-size:85%;color:#660000;">Dim MyFolder As Outlook.MAPIFolder</span><br /><span style="font-size:85%;color:#660000;">Dim olApp As Outlook.Application</span><br /><span style="font-size:85%;color:#660000;">Dim olNS As Outlook.NameSpace</span><br /><br /><span style="font-size:85%;color:#660000;">On Error Resume Next</span><br /><span style="font-size:85%;color:#660000;">Select Case TypeName(Application.ActiveWindow)</span><br /><span style="font-size:85%;color:#660000;"> Case "Explorer"</span><br /><span style="font-size:85%;color:#660000;"> Set objItem = _</span><br /><span style="font-size:85%;color:#660000;"> Application.ActiveExplorer.Selection.item(1)</span><br /><span style="font-size:85%;color:#660000;"> Case "Inspector"</span><br /><span style="font-size:85%;color:#660000;"> Set objItem = _</span><br /><span style="font-size:85%;color:#660000;"> Application.ActiveInspector.CurrentItem</span><br /><span style="font-size:85%;color:#660000;">End Select</span><br /><span style="font-size:85%;color:#660000;">On Error GoTo 0</span><br /><br /><span style="font-size:85%;color:#660000;">If objItem Is Nothing Then</span><br /><span style="font-size:85%;color:#660000;"> MsgBox "Nothing selected!", _</span><br /><span style="font-size:85%;color:#660000;"> vbExclamation</span><br /><span style="font-size:85%;color:#660000;"> Goto ExitProc</span><br /><span style="font-size:85%;color:#660000;">End If</span><br /><span style="font-family:Courier New;font-size:85%;color:#660000;"></span></pre><br /><br /><br /><br />If we made it this far, we check if our object reference is to a MailItem<br /> by checking the Class Property for the olMail constant. If it is indeed a MailItem, we set a friendly object reference "Msg" to it. I like to use string variables that easily identify what the variable represents; similar to <a href="http://www.byteshift.de/msg/hungarian-notation-doug-klunder">Hungarian notation</a>. That way I can spend more time worrying about what the code should do and less time guessing what each variable does every time I look at it. Fortunately, "Msg" is one of those non-reserved keywords that make it obvious.<br /><br /><pre><br /><span style="font-size:85%;color:#660000;">If objItem.Class = olMail Then</span><br /><span style="font-size:85%;color:#660000;">Set Msg = objItem</span><br /><span style="font-size:85%;color:#660000;">Else</span><br /><span style="font-size:85%;color:#660000;"> MsgBox "No message selected!", _</span><br /><span style="font-size:85%;color:#660000;"> vbExclamation</span><br /><span style="font-size:85%;color:#660000;"> GoTo ExitProc</span><br /><span style="font-size:85%;color:#660000;">End If</span><br /><br /><span style="font-size:85%;color:#660000;">Set olApp = Outlook.Application</span><br /><span style="font-size:85%;color:#660000;">Set olNS = olApp.GetNamespace("MAPI")</span><br /><span style="font-size:85%;color:#660000;">Set MyFolder = olNS.GetDefaultFolder(olFolderInbox)._</span><br /><span style="font-size:85%;color:#660000;">Folders("Archive")</span><br /><span style="font-size:85%;color:#660000;"></span><span style="font-family:Courier New;"></span></pre><br /><br />At this point we execute the Forward Method of the MailItem object, <br />which creates a new email message based on the original, and returns an object reference to the about-to-be-forwarded MailItem. We set up the Subject: and To: fields, and use the Subject: from the original MailItem to create the Body of the forwarded item.<br /><br />After sending the message, we move the original email to the folder called "Archive" which is one level below the default Inbox (see object reference for "MyFolder").<br /><br /><pre><br /><span style="font-size:85%;color:#660000;">Set NewForward = Msg.Forward</span><br /><span style="font-size:85%;color:#660000;">With NewForward</span><br /><span style="font-size:85%;color:#660000;"> .Subject = "Information You Requested"</span><br /><span style="font-size:85%;color:#660000;"> .To = "</span><a href="mailto:myemail@mobiledevice.com"><span style="font-size:85%;color:#660000;">myemail@mobiledevice.com</span></a><span style="font-size:85%;color:#660000;">"</span><br /><span style="font-size:85%;color:#660000;"> .Body = Right(Msg.Subject, _</span><br /></span><span style="font-size:85%;color:#660000;"> Len(Msg.Subject) - InStrRev(Msg.Subject, " "))</span><br /><span style="font-size:85%;color:#660000;"> .Send</span><br /><span style="font-size:85%;color:#660000;">End With</span><br /><br /><span style="font-size:85%;color:#660000;">With Msg</span><br /><span style="font-size:85%;color:#660000;"> .UnRead = False</span><br /><span style="font-size:85%;color:#660000;"> .FlagStatus = olNoFlag</span><br /><span style="font-size:85%;color:#660000;"> .Move MyFolder</span><br /><span style="font-size:85%;color:#660000;">End With</span><br /><br /><span style="font-size:85%;color:#660000;">ExitProc:</span><br /><span style="font-size:85%;color:#660000;">Set NewForward = Nothing</span><br /><span style="font-size:85%;color:#660000;">Set Msg = Nothing</span><br /><span style="font-size:85%;color:#660000;">Set objItem = Nothing</span><br /><span style="font-size:85%;color:#660000;">End Sub</span><br /></pre><br /><br />Here is the code in its entirety:<br /><br /><pre><br /><span style="font-size:85%;color:#660000;">Sub FwdMailText()</span><br /><span style="font-size:85%;color:#660000;">Dim objItem As Object<br />Dim Msg As Outlook.MailItem<br />Dim NewForward As Outlook.MailItem<br />Dim MyFolder As Outlook.MAPIFolder<br />Dim olApp As Outlook.Application<br />Dim olNS As Outlook.NameSpace</span><br /><br /><span style="font-size:85%;color:#660000;">On Error Resume Next<br />Select Case TypeName(Application.ActiveWindow)<br /> Case "Explorer"<br /> Set objItem = _<br /> Application.ActiveExplorer.Selection.item(1)<br /> Case "Inspector"<br /> Set objItem = _<br /> Application.ActiveInspector.CurrentItem<br />End Select<br />On Error GoTo 0</span><br /><br /><span style="font-size:85%;color:#660000;">If objItem Is Nothing Then<br /> MsgBox "Nothing selected!", _<br /> vbExclamation<br /> Goto ExitProc<br />End If</span><br /><span style="font-size:85%;color:#660000;"></span><br /><span style="font-size:85%;color:#660000;">If objItem.Class = olMail Then<br /> Set Msg = objItem<br />Else<br /> MsgBox "No message selected!", _<br /> vbExclamation<br /> GoTo ExitProc<br />End If</span><br /><br /><span style="font-size:85%;color:#660000;">Set olApp = Outlook.Application<br />Set olNS = olApp.GetNamespace("MAPI")<br />Set MyFolder = olNS.GetDefaultFolder(olFolderInbox)._</span><br /><span style="font-size:85%;color:#660000;">Folders("Archive")</span><br /><span style="font-size:85%;color:#660000;">Set NewForward = Msg.Forward</span><br /><br /><br /><span style="font-size:85%;color:#660000;">With NewForward<br /> .Subject = "Information You Requested"<br /> .To = "</span><a href="mailto:myemail@mobiledevice.com"><span style="font-size:85%;color:#660000;">myemail@mobiledevice.com</span></a><span style="font-size:85%;color:#660000;">"<br /> .Body = Right(Msg.Subject, _<br />Len(Msg.Subject) - InStrRev(Msg.Subject, " "))<br /> .Send<br />End With</span><br /><br /><span style="font-size:85%;color:#660000;">With Msg<br /> .UnRead = False<br /> .FlagStatus = olNoFlag<br /> .Move MyFolder<br />End With</span><br /><br /><span style="font-size:85%;color:#660000;">ExitProc:<br />Set NewForward = Nothing<br />Set Msg = Nothing<br />Set objItem = Nothing<br />End Sub</span><br /></pre><br /><p><br />For the Body property, I chose to include the text from the subject line (everything starting from the left all the way up to the first space) of the original item, but you can include anything you want. If you wanted to include the original message body in the forward, try this:<br /></p><br /><br /><span style="font-size:85%;color:#660000;">.Body = Msg.Body</span><br /><br />If you are curious about the properties and methods of the MailItem object, you can enter a new line right below "With NewForward" and type a period "." You should get a dropdown list of everything you can do with a MailItem, courtesy of <a href="http://msdn2.microsoft.com/en-us/library/hcw1s69b(VS.71).aspx">Intellisense</a>. Once you select one, you can press F1 for assistance and sample code. This is a great way to learn about the properties of an object; just declare an object of a specific type, then start typing "<em>objectname.</em>" and you get that list. Just be sure you go to the Options in the VB Editor in Outlook (press Alt-F11, then go to Tools>Options) and on the Editor tab, check all the boxes in the "Code Settings" frame.<br /><br /><p>Enjoy,</p><p>JP<a href="http://www.codeforexcelandoutlook.com/uploaded_images/toolbarcode1-738173.JPG"></a></p>JPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-42959837162716286232008-04-14T13:49:00.008-04:002008-04-14T17:02:33.635-04:00Hands Off That Email Attachment!About halfway down the <a href="http://www.codeforexcelandoutlook.com/Outlook.html">Outlook</a> page, there is some VBA code for opening an Excel workbook attached to an email, running a macro on it, then cleaning up and moving the email to another folder.<br /><br />Here is some more sample code to make your macro even more intelligent. This code opens the attachment, then scans through the spreadsheet looking for an error condition. If the error condition is met, an email is generated to another mailbox, as an alert, and the email is left in the Inbox to be looked at by a human. If the error condition isn't met, there's no reason to look at the email, so it gets marked as read and moved to an archive folder.<br /><br />If you are like me, then your time is valuable. You don't want to spend time looking at emails that you don't need to work on. This code lets me focus on high-value activities while using Outlook's built-in capabilities to ignore the spreadsheets that don't need personal attention.<br /><br />First you want to open ThisOutlookSession and paste this event code:<br /><br /><span style="font-family:trebuchet ms;"><span style="font-size:85%;"><span style="font-family:trebuchet ms;color:#990000;">Private WithEvents QueueInbox As Outlook.Items<br />Dim bWasPosted As Boolean</span> </span><br /></span><br />Really you can use anything in place of "QueueInbox", but I use something that will relate to the task so I can easily identify what the code is doing. The boolean variable is put in the global section because we are using it in one procedure (the mail sending sub) and checking the value in another sub.<br /><br />Now you need to tell Outlook to monitor your chosen Inbox for new items. This code placed in the Application_Startup event will do that.<br /><br /><span style="font-family:verdana;font-size:78%;color:#990000;"></span><br /><span style="font-size:85%;"><span style="font-family:trebuchet ms;color:#990000;">Set QueueInbox = objNS.Folders("Mailbox - My Mailbox Name").Folders("Inbox").Items</span><br /></span><br /><br />Replace "My Mailbox Name" with the name of the mailbox you want to check. For example, if I were running this on my own Inbox, the code would be<br /><br /><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;">Set QueueInbox = objNS.Folders("Mailbox - Jimmy Pena").Folders("Inbox").Items</span><br /><br /><br />If you don't have an Application_Startup event, just put "<span style="color:#990000;">Private Sub Application_Startup()</span>" right above the Set statement, and "<span style="color:#990000;">End Sub</span>" right below it.<br /><br />Now on to the real work. When a new item is added to the Inbox we selected, it saves and opens the attachment, checks to make sure everything is OK, and if so, moves the email to an archive folder. Don't forget to set a reference to the Excel object library (see binding page for assistance).<br /><br />Of course I make some assumptions here, which you might want to change. For example, the emails we are checking have a known sender and subject, which was pre-arranged. Also, they always have one .xls attachment. If you can agree on a system like this, you'll be able to use Outlook code to automate some pretty boring processes.<br /><br /><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;">Private Sub QueueInbox_ItemAdd(ByVal Item As Object)<br /><br />Dim objNS As Outlook.NameSpace<br />Dim ArchiveFolder As Outlook.MAPIFolder<br />Dim Msg As Outlook.MailItem<br />Dim myAttachments As Outlook.Attachments<br />Const attPath As String = "C:\"<br />Dim colACount As Long<br />Dim colGCount As Long<br />Dim cell As Excel.Range<br />Dim MyBook As Excel.Workbook<br />Dim MySheet As Excel.Worksheet<br />Dim colARange As Excel.Range<br />Dim colGRange As Excel.Range<br />Dim bBadCount As Boolean<br /><br />bWasPosted = False<br />bBadCount = False<br /><br />Set objNS = GetNamespace("MAPI") </span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"><span style="color:#009900;">' the archive folder we are moving emails to</span><br />Set ArchiveFolder = objNS.Folders("Mailbox - My Mailbox Name")._</span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"> Folders("Inbox").Folders("Archive")<br /><br /></span><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"></span><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"><span style="color:#009900;">' check to make sure we are looking at a mailitem</span><br />If TypeOf Item Is Outlook.MailItem Then<br /> If (Item.SenderName = "MySender@somewhere.com") And _</span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"> (Item.Subject = "Attachment You Requested") Then<br /><span style="color:#009900;"> ' obj ref to msg<br /></span> Set Msg = Item<br /><span style="color:#009900;"> ' get attachment</span><br /> Set myAttachments = Msg.Attachments<br /> Att = myAttachments.Item(1).DisplayName<br /> myAttachments.Item(1).SaveAsFile attPath & Att<br /><br /><span style="color:#009900;"> ' open workbook and check for errors</span><br /> Set XLApp = New Excel.Application<br /> Set MyBook = XLApp.Workbooks.Open(attPath & Att)<br /> Set MySheet = MyBook.Sheets(1) </span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"><br /><span style="color:#009900;"> ' check count of columns A & G to make sure they match</span> </span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#009900;"> ' at this point you could do anything you want to the workbook, as if you</span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"><span style="color:#009900;"> ' were in the Excel VBE</span><br /> Set colARange = MySheet.Range("A2:A5000")<br /> Set colGRange = MySheet.Range("G2:G5000")<br /><br /> colACount = colARange.SpecialCells(xlCellTypeConstants).Count<br /> colGCount = colGRange.SpecialCells(xlCellTypeConstants).Count<br /><br /> If colACount <> colGCount Then </span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"><span style="color:#009900;"> ' we found an error!</span><br /> MyBook.Close False </span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"> <span style="color:#009900;">' call other macro and pass email to it as an argument,</span></span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"><span style="color:#009900;"> ' so we can use some properties of the current mailitem</span><br /> Call PostMsg(Msg)<br /> bBadCount = True<br /> End If<br /></span><span style="font-family:trebuchet ms;font-size:85%;color:#009900;"></span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#009900;">' bBadCount is a boolean variable checking if the match count</span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#009900;">' caused an error, we skip further checks if that is the case</span><br /><span style="font-family:Trebuchet MS;font-size:85%;color:#009900;">' because we only need one error</span><br /><span style="font-family:trebuchet ms;font-size:85%;color:#990000;"><br /> If bBadCount = False Then<br /> <span style="color:#009900;">' the count matched, but maybe we have invalid values<br /></span> For Each cell In colGRange.SpecialCells(xlCellTypeConstants, 2)<br /> If (cell.Value = "#N/A") Then<br /> MyBook.Close False<br /> Call PostMsg(Msg)<br /> End If<br /> Next cell<br /> End If<br /><br /><span style="color:#009900;">' at this point, if PostMsg was called,</span><br /><span style="color:#009900;">' bWasPosted would be True</span><br /><br /> If bWasPosted = False Then<br /><span style="color:#009900;"> ' we didn't post a msg to MyInbox, so there must be </span><br /><span style="color:#009900;"> ' nothing wrong with the attachment, so we can move it </span><br /> With Msg<br /> .UnRead = False<br /> .Move ArchiveFolder<br /> End With<br /> End If<br /> End If<br />End If<br /><br />ExitProc:<br />On Error Resume Next<br />XLApp.DisplayAlerts = False<br />XLApp.Workbooks.Close<br />XLApp.DisplayAlerts = True<br />Kill attPath & Att<br />XLApp.Quit<br />On Error GoTo 0<br />Set ArchiveFolder = Nothing<br />Set objNS = Nothing<br /><br />End Sub<br /><br /><br />Sub PostMsg(Msg As Outlook.MailItem)<br /><span style="color:#009900;">'<br />' sub that actually puts the email in the inbox<br />'</span><br />Dim NotifyMsg As Outlook.MailItem<br />Dim MyFolder As Outlook.MAPIFolder<br />Dim objNS As Outlook.NameSpace<br />Dim strMsg As String<br /><br />Set objNS = GetNamespace("MAPI")<br />Set MyFolder = objNS.Folders("Mailbox - Jimmy Pena").Folders("Inbox")<br /><br />Set NotifyMsg = MyFolder.Items.Add(olMailItem)<br /><br />With NotifyMsg<br />.Subject = "Invalid Attachment Received"<br />.Importance = olImportanceHigh<br />.To = "jpena@myemail.com"<br />strMsg = "The following message was received by Queue Inbox on " & Msg.ReceivedTime & ":"<br />strMsg = strMsg & vbCr & vbCr & Msg.Body<br />strMsg = strMsg & vbCr & vbCr & "This is an automatically generated message."<br />.Body = strMsg<br />.UnRead = True<br />End With<br /><br />bWasPosted = True<br /><br />NotifyMsg.Send<br /><br />End Sub </span><br /></span><br /><br />After implementing this code, you'll see that it checks incoming mail items for the ones with the appropriate sender and subject, browses through the attachment for errors, and sends an email to your Inbox of choice if an error is found. If no error is found, it quietly marks the email as read and moves it to another folder.<br /><br />Now, hands off!<br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-13213267654970135592008-04-08T16:24:00.005-04:002008-04-08T16:49:19.452-04:00Updated blog and new pagesAs you may have noticed, I decided to update the blog, because it was getting hard to navigate. The color scheme was just bringing me down, so I spent about 4-5 hours changing it. That might seem like a lot of time, but I'm a perfectionist so once I start working I don't stop until it's perfect. I guess it's just the programmer in me.<br /><br />Speaking of which, I added two new pages to the site: one with a <a href="http://www.codeforexcelandoutlook.com/LatLong.html">great circle distance UDF</a> and another with some samples for using the <a href="http://www.codeforexcelandoutlook.com/varType.html">varType() function</a>.<br /><br />I am also working on a set of Outlook macros/event code to use as a file put/request system. Once added to your Outlook, other people would send you emails with a specially formatted subject; your system would respond by sending the requested file as an attachment, or putting the received attachments into the folder specified by the sender.<br /><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-4448129766491310432008-04-07T12:07:00.004-04:002008-04-08T17:01:50.503-04:00UDF to return page headers/footers textHere's a series of short UDFs that will return the page headers and footers for the active worksheet.<br /><br /><br /><span style="color:#990000;">Function GetLeftHeader()</span><br /><span style="color:#990000;"> GetLeftHeader = ActiveSheet.PageSetup.LeftHeader </span><br /><span style="color:#990000;">End Function</span><br /><br /><span style="color:#990000;"></span><br /><span style="color:#990000;">Function GetCenterHeader()</span><br /><span style="color:#990000;"> GetCenterHeader = ActiveSheet.PageSetup.CenterHeader<br /></span><span style="color:#990000;">End Function </span><br /><span style="color:#990000;"></span><br /><br /><span style="color:#990000;">Function GetRightHeader() </span><br /><span style="color:#990000;"> GetRightHeader = ActiveSheet.PageSetup.RightHeader </span><br /><span style="color:#990000;">End Function </span><br /><span style="color:#990000;"></span><br /><br /><span style="color:#990000;">Function GetLeftFooter() </span><br /><span style="color:#990000;"> GetLeftFooter = ActiveSheet.PageSetup.LeftFooter </span><br /><span style="color:#990000;">End Function </span><br /><span style="color:#990000;"></span><br /><br /><span style="color:#990000;">Function GetCenterFooter() </span><br /><span style="color:#990000;"> GetCenterFooter = ActiveSheet.PageSetup.CenterFooter </span><br /><span style="color:#990000;">End Function </span><br /><br /><span style="color:#990000;"></span><br /><span style="color:#990000;">Function GetRightFooter() </span><br /><span style="color:#990000;"> GetRightFooter = ActiveSheet.PageSetup.RightFooter </span><br /><span style="color:#990000;">End Function</span><br /><br />To use: Just put the function name in the cell, prefixed by an equal sign. For example, to get the left header text in cell A1:<br /><span style="color:#ff9900;"></span><br /><span style="color:#990000;">=GetLeftHeader()</span><br /><br />If you use any of these functions in a workbook other than the one where the code resides (ex: your PERSONAL.XLS workbook), you may have to prefix the code like this:<br /><br /><br /><span style="color:#990000;">=PERSONAL.XLS!GetLeftHeader()</span><br /><br />You can also use them in VBA code to get the associated property and take appropriate action, for example:<br /><br /><span style="color:#990000;">Sub TestMe()</span><br /><span style="color:#990000;">Dim strMyHeader As String<br /></span><br /><span style="color:#990000;">strMyHeader = GetLeftHeader<br /></span><br /><span style="color:#990000;">If strMyHeader <> "My Company Name" Then</span><br /><span style="color:#990000;"> ActiveSheet.PageSetup.LeftHeader = "Company Name"</span><br /><span style="color:#990000;">Else</span><br /><span style="color:#990000;"> MsgBox strMyHeader & " is your company's name."</span><br /><span style="color:#990000;">End If</span><br /><br /><span style="color:#990000;">End Sub<br /></span><br /><br /><br />HTH,<br /><br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-6542009463907016572008-04-07T11:51:00.003-04:002008-04-07T12:07:06.034-04:00Rows to Repeat at TopIf you want to programmatically set the "Rows to Repeat At Top" option on the Sheet tab in Excel's Page Setup dialog box, here are two ways to do it.<br /><br />If you already know what range you want, you could use this code:<br /><br /><span style="color:#ffcc00;">ActiveSheet.PageSetup.PrintTitleRows = "$1:$1"</span><br /><br />This would set row 1 (which would ideally be a list of column headers) to print at the top of every page.<br /><br />To set this option based on a user selection:<br /><br /><span style="color:#ffcc00;">ActiveSheet.PageSetup.PrintTitleRows = Selection.Areas(1).Address</span><br /><br />This code assumes that you have selected at least one entire row, i.e. select rows 1 through 4 then use the code above to set "Rows to repeat at top" to $1:$4.<br /><br /><br />HTH,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-84335230437486665192008-04-04T14:49:00.001-04:002008-04-04T14:57:22.823-04:00Excel User ConferenceI was browsing <a href="http://peltiertech.com/WordPress/">Jon Peltier's blog</a> and found a link to the <a href="http://www.exceluserconference.com/">Excel User Conference</a>. It being held in Atlantic City which is only a couple hours' drive from my house, so I will be attending. And as soon as I save the money to pay the attendance fees, I'll be able to say that with 100% confidence.<br /><br />If you are in the area and are reading this blog, you should try to attend. Check out the link to the conference to see the topics and presenters.<br /><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-25731947905093638352008-04-03T16:30:00.003-04:002008-04-03T16:37:20.422-04:00Training class updateThe Advanced Excel class tutorial is almost finished. I still have to write the section on 'Macros'. I'm considering just cutting and pasting from the web, because I'm not sure I have the strength to write something from the ground up. Or it might just be a brief introduction with some simple examples -- you can't teach macro writing in a 3 hour class. I've been writing them semi-regularly for the last three years and only in the last three months have I been doing it on an almost daily basis.<br /><br />Speaking of which, some of the code I wrote way back then is atrocious, but it got the job done. Even to this day it is still being used in my organization and saves countless man-hours of tedious manual work.<br /><br />Like I said a few months ago, I will post the sample workbooks and the written tutorial once it's done. I'm not a technical writer, but I like the way it seems to be coming together. I had to figure out how to sync up the workbooks with the written text to make it all flow together like course material should. Not easy! But I think I managed to pull it off, and it's definitely reusable if anyone wants to re-use it.<br /><br /><br />Keep thinking,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-41699729985657929962008-04-01T22:29:00.005-04:002008-04-01T22:43:58.892-04:00Quickly Clear Conditional FormattingHere is a simple sub that deletes conditional formatting from a selection. The code does some prelim checking to see that it is actually acting on a range, and it mimics Excel's usual behavior (like a good VBA procedure should, if I may say so) by acting on the entire worksheet if you only select a single cell. However I recommend just selecting the range before you run the code.<br /><br /><span style="color:#ffcc00;">Sub Clear_Cond_Formatting()<br />Dim rng As Excel.Range<br /></span><br /><span style="color:#ffcc00;">If TypeName(Selection) <> "Range" Then Exit Sub</span><br /><span style="color:#ffcc00;">If TypeName(Selection.Parent) = "Chart" Then Exit Sub</span><br /><span style="color:#ffcc00;">If TypeName(Selection.Parent.Parent) = "Chart" Then Exit Sub</span><br /><br /><span style="color:#ffcc00;">Select Case Selection.Cells.count</span><br /><span style="color:#ffcc00;"> Case 1</span><br /><span style="color:#ffcc00;"> Set rng = Cells</span><br /><span style="color:#ffcc00;"> Case Else</span><br /><span style="color:#ffcc00;"> Set rng = Selection</span><br /><span style="color:#ffcc00;">End Select</span><br /><br /><span style="color:#ffcc00;">On Error Resume Next</span><br /><span style="color:#ffcc00;">rng.FormatConditions.Delete</span><br /><span style="color:#ffcc00;">On Error GoTo 0<br />End Sub</span><br /><br /><br />Enjoy,<br />JPJPhttp://www.blogger.com/profile/06464959334594594876noreply@blogger.comtag:blogger.com,1999:blog-7457629448978828138.post-42434252865426797022008-04-01T08:45:00.004-04:002008-04-01T22:28:59.296-04:00Simple Word macro/button to print out a formHappy April Fool's Day!<br /><br />Here is a simple macro in MS Word that you can use to print out a document to the default printer.<br /><ul><li>Go to View>Toolbars>Control Toolbox to display the Control Toolbox.</li><li>Click the "Command Button" icon to insert a command button in your document. You can drag it anywhere you like and resize as needed.</li><li>Double click the button to view the code window. You should be taken right inside an auto-created Click event that looks like this:</li></ul><p><span style="color:#ffcc00;">Private Sub CommandButton1_Click()<br /></span></p><p><span style="color:#ffcc00;">End Sub</span></p><ul><li>Paste the following code in between those lines:</li></ul><p><span style="color:#ffcc00;">ActiveDocument.PrintOut</span></p><ul><li>Press F4 to view the Properties window for the command button and change the "Caption" property to something like "Print" or something else useful.</li><li>Press Alt-Q to close the VB Editor and return to MS Word.</li><li>On the Control Toolbox, click "Exit Design Mode". You can close the toolbar if you wish.</li></ul><p>Test it out by pressing the button! It will send your document to the default printer. Keep in mind the button is displayed on the document so it will be printed as well.</p><p></p><p>Enjoy,</p><p>JP</p>JPhttp://www.blogge