Creating new appointment & setting its properties

  • Thread starter Thread starter dim4x4
  • Start date Start date
D

dim4x4

Hello everybody!

This is my first message here and first macro I'm trying to do in
Outlook (I did some for Excel before, albeit with macro recorder =)

Basically, I'm creating a new appointment (the code was borrowed from a

message from this group or some forum). Below is part of the code and 2

things I'm struggling to do.

With objAppointment
.Subject = "Call "
.Start = ' PROBLEM 1: Here I want to put a time of a current
selection in a daily view of the calendar (don't know how to do it)
.Duration = 5
.ReminderMinutesBeforeStart = 0
.Save
.Display
End With

PROBLEM 2: When appointment is created and opened I was the cursor to
be in a subject line after the word "Call ", so that I can finish
typing the subject, eg. "Call Bill Gates" =)

Would appreciate any advise. Thank you!
 
Forget about #2, you can't control the cursor position except by using
SendKeys and that can be very buggy and depending on where the cursor starts
out can be unpredictable.

If one item is selected in the current view of the calendar then use this
for #1:

Dim datStart As Date

datStart = Application.ActiveExplorer.Selection.Item(1).Start
 
Hey Ken I responded to someone before about the cursor position but I never
tried it myself. What's wrong with sending the EM_SETSEL message to the
RichEdit control? Should be fairly straightforward.

(One hour later...) Okay please excuse my horredous VBA/Win32. It's been so
long since I've done this. The code below will set the cursor position of
the body control or text box of any standard Outlook item. This started out
as a 10 minute thing but then I realized that guy wanted to set the position
in the subject so I had to change some things around.

-------------------------------------------
Option Explicit

Private Declare Function SendMessage Lib "User32.dll" Alias "SendMessageA"
(ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam
As Long) As Long
Private Declare Function GetForegroundWindow Lib "User32.dll" () As Long
Private Declare Function FindWindowEx Lib "User32.dll" Alias "FindWindowExA"
(ByVal hwndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As
String, ByVal lpszWindow As String) As Long
Private Declare Function EnumChildWindows Lib "User32.dll" (ByVal hwndParent
As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean
Private Declare Function GetClassName Lib "User32.dll" Alias "GetClassNameA"
(ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long)
As Long
Private Declare Function SetFocusAPI Lib "User32.dll" Alias "SetFocus"
(ByVal hwnd As Long) As Long
Private Declare Function GetWindowTextAPI Lib "User32.dll" Alias
"GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As
Long) As Long
Private Declare Function GetWindowTextLength Lib "User32.dll" Alias
"GetWindowTextLengthA" (ByVal hwnd As Long) As Long

Private Const CLASS_SUBJECT = "RichEdit20WPT"
Private Const CLASS_BODY = "RichEdit20W"
Private Const CLASS_WINDOW = "rctrl_renwnd32"

Private Const DEFAULT_SUBJECT = "To whom it may concern"
Private Const DEFAULT_BODY = "When in the course of human events..."

Private Const EM_SETSEL = &HB1

Private Const FINDMODE_BYCLASS = 0
Private Const FINDMODE_BYTEXT = 1

Private hwndRichEdit As Long

' Used internally
Private expectedText As String
Private currentFindMode As Long

''' <summary>
''' Demo entry method
''' </summary>
Public Sub CreateTestItem()

Dim app As AppointmentItem
Set app = Application.CreateItem(olAppointmentItem)

app.Subject = DEFAULT_SUBJECT
app.Body = DEFAULT_BODY

app.Display

DoEvents

'SetBodyCursorPos 5
SetTextBoxCursorPos DEFAULT_SUBJECT, 5

End Sub

''' <summary>
''' Sets the cursor position in a given text box by finding the text box
that has the specied
''' text and sets the focus to it.
''' </summary>
Public Sub SetTextBoxCursorPos(ByVal subjectText As String, ByVal pos As
Long)
SetPositionInternal subjectText, FINDMODE_BYTEXT, pos
End Sub

''' <summary>
''' Sets the cursor position in the body by finding the body (no text is
needed because only one
''' body control is on the form) and sets focus to it.
''' </summary>
Public Sub SetBodyCursorPos(ByVal pos As Long)
SetPositionInternal "", FINDMODE_BYCLASS, pos
End Sub


''' <summary>
''' Sets the cursor position of a text box or the body field. Called
internally by the two
''' public methods SetBodyCursorPos and SetTextBoxCursorPos.
'' </summary>
Private Sub SetPositionInternal(ByVal text As String, ByVal findMode As
Long, ByVal pos As Long)

' Get the foreground window which should be appointmentitem
Dim hwnd As Long
hwnd = GetForegroundWindow()

' Make sure it's the appointment window
Dim hwnd2 As Long
hwnd2 = FindWindowEx(0, 0, CLASS_WINDOW, vbNullString)

If hwnd = hwnd2 Then

' Store the text that they're searching for in a private variable
expectedText = text
' Likewise store the find mode. Would have passed this to
enumchildwindows
' but since i'm storing expectedText, I'll do this too. I hate VB
currentFindMode = findMode

' Find the rich edit box on the page
EnumChildWindows hwnd, AddressOf EnumWindowProc, 0

If hwndRichEdit <> 0 Then
SetFocusAPI hwndRichEdit
SendMessage hwndRichEdit, EM_SETSEL, pos, pos
End If

End If

End Sub

''' <summary>
''' Callback function invoked by Windows for every child window enumerated.
''' </summary>
Private Function EnumWindowProc(ByVal hwnd As Long, ByVal lParam As Long) As
Boolean

Dim returnValue As Boolean
returnValue = True

Dim className As String
Dim length As Long

className = Space(100)
length = GetClassName(hwnd, className, Len(className) - 1)
If length > 0 Then

' FINDMODE_BYTEXT means they are looking for a single-line textbox
that
' has the specified text. Because there are multiple single-line
text box class
' instances on the form, we need the expected text to match it to
get the right hwnd
If currentFindMode = FINDMODE_BYTEXT Then
If Left(className, length) = CLASS_SUBJECT And
GetWindowText(hwnd) = DEFAULT_SUBJECT Then
hwndRichEdit = hwnd
returnValue = False
End If
' FINDMODE_BYCLASS means they are looking for the body control.
Since there's
' only one instance of that class on the form we don't care about
the text
ElseIf currentFindMode = FINDMODE_BYCLASS Then
If Left(className, length) = CLASS_BODY Then
hwndRichEdit = hwnd
returnValue = False
End If
End If

End If

EnumWindowProc = returnValue

End Function

''' <summary>
''' Helper function to get the window text of the HWND in one call.
''' </summary>
Private Function GetWindowText(ByVal hwnd As Long) As String

Dim buff As String
buff = Space(GetWindowTextLength(hwnd) + 1)

GetWindowTextAPI hwnd, buff, Len(buff)
GetWindowText = Left(buff, Len(buff) - 1)

End Function


--
Josh Einstein
Einstein Technologies
Microsoft Tablet PC MVP
Tablet Enhancements for Outlook 2.0 - Try it free for 14 days
www.tabletoutlook.com
 
Cool. Does it work universally (WordMail or Outlook editor, formats (plain
text, HTML, RTF)?

The window and process subclassing I've seen with WordMail is horrendous,
it's miles of code just to get a true hWnd for a WordMail window usually.
 
That will only work for standard Outlook forms but it should work among all
items as far as I know. WordMail should be alot easier to set the cursor
position using the object model.

--
Josh Einstein
Einstein Technologies
Microsoft Tablet PC MVP
Tablet Enhancements for Outlook 2.0 - Try it free for 14 days
www.tabletoutlook.com
 
Wow! =) Thank you guys!

It'll take me some time just to copy-paste it in the right places in my
macro :)
 
Guys, sorry can't figure it out. Could you please help a bit more?

PROBLEM 1:

This is my macro, but it doesn't do anything

Public Sub AddAppointment()

Dim objApp As Outlook.Application
Dim objAppointment As Outlook.AppointmentItem
Dim datStart As Date

datStart = Application.ActiveExplorer.Selection.Item(1).Start

Set objApp = New Outlook.Application
Set objAppointment = objApp.CreateItem(ItemType:=olAppointmentItem)

With objAppointment
.Subject = "Call "
.Start = datStart
.Duration = 5
.ReminderMinutesBeforeStart = 0
.Subject = "Call "
.Save
.Display
End With

End Sub


PROBLEM 2:

Maybe when I was editing the macros I've put something on the wrong
line, but it breaks in macro Private Sub SetPositionInternal
on the line EnumChildWindows hwnd, AddressOf EnumWindowProc, 0 giving
error
Compile error:
Invalid use of AddressOf operator

Any ideas? Thank you!
 
Sorry I forgot to mention that AddressOf can only be used in a standard
module (*.bas) so you'll have to add that to your project.

As for problem #1, I have no idea off the top of my head, but one wonders
why you are creating a new Application object instead of using "Application"
which is already available.

Set objAppoinemt = Application.CreateItem(olAppointmentItem)

--
Josh Einstein
Einstein Technologies
Microsoft Tablet PC MVP
Tablet Enhancements for Outlook 2.0 - Try it free for 14 days
www.tabletoutlook.com
 
Thank you, Josh!

I moved your code to the module and it works great! Also for my first
problem, I found a solution here
http://www.outlookcode.com/codedetail.aspx?id=616 and modified your
CreateTestItem as follows below. It does what I need to do, the only
minor thing is that it opens and closes an appointment which makes a
quick flicker on the screen, but I guess I can live with that. Thank
you and Ken for your help!

This is my macro (apart from other parts that put cursor where I want
it):

Sub NewCall()

Dim objExpl As Outlook.Explorer
Dim objFolder As Outlook.MAPIFolder
Dim objCB As Office.CommandBarButton
Dim objAppt As Outlook.AppointmentItem
Dim objApptCustom As Outlook.AppointmentItem
On Error Resume Next

Set objExpl = Application.ActiveExplorer
If Not objExpl Is Nothing Then
Set objFolder = objExpl.CurrentFolder
If objFolder.DefaultItemType = olAppointmentItem Then
Set objCB = objExpl.CommandBars.FindControl(, 1106)
If Not objCB Is Nothing Then
objCB.Execute
Set objAppt = Application.ActiveInspector.CurrentItem
Set objApptCustom =
objFolder.Items.Add("IPM.Appointment.your_custom_class")
With objApptCustom
.Subject = DEFAULT_SUBJECT
.Start = objAppt.Start
.End = objAppt.End
.Duration = 5
.ReminderMinutesBeforeStart = 0
.Display
End With
End If
End If
End If

objAppt.Close olDiscard

Set objCB = Nothing
Set objAppt = Nothing
Set objApptCustom = Nothing
Set objFolder = Nothing
Set objExpl = Nothing

'SetBodyCursorPos 5
SetTextBoxCursorPos DEFAULT_SUBJECT, 5

End Sub
 
Great! Glad to hear it's working for you. Sometimes I just get into those
coding moments and it's encouraging to actually hear back from someone that
used it!

VBA was certainly a walk down memory lane... actually more like a dark
smelly alley! I hope my children live to see the day when Office uses .NET
as its automation model.

--
Josh Einstein
Einstein Technologies
Microsoft Tablet PC MVP
Tablet Enhancements for Outlook 2.0 - Try it free for 14 days
www.tabletoutlook.com
 
Back
Top