Short Version
I am attempting to access the TimeZoneStruct using VSTO from an Outlook Appointment.
The following error is thrown when attempting to access it.
System.Runtime.InteropServices.COMException (0x80040102): Object does not support property "http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/82330102".
Interestingly, I am able to get a similar property, TimeZoneDescription, using the same method with no exceptions:
http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/8234001F
My code is below; the first call to GetProperty succeeds, but the second does not.
//OK returns TimeZone Description string
dynamic tz1 = pa.GetProperty("http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/8234001F");
//NOK throws a COMException
dynamic tzStruct = pa.GetProperty("http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/82330102");
Long Version
I am developing a plugin that reads the Outlook calendar.
Currently the difficulty is with recurring appointments that were created with different timezones that have different Daylight Savings Time settings.
In order to find all appointments of a recurring meeting series, I need timezone information.
The first approach I used was to obtain the timezone information by extracting the timezone name. This works in most cases but is not ideal.
Outlook.PropertyAccessor pa = appointment.PropertyAccessor;
dynamic tz1 = pa.GetProperty("http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/8234001F");
This returns a string similar to (UTC+01:00) Amsterdam, Berlijn, Bern, Rome, Stockholm, Wenen.
This works correctly, but appointments that were sent from PC's with different languages, or in the case of "old" meetings with "obsolete" timezones that were deleted in a Windows Update, this does not work so well.
I will get meetings from computers from other languages, for instance this timezone is in French and my computer will not find it.
(UTC+03:00) Moscou, Saint-Pétersbourg, Volgograd
There are also updates; this timezone below no longer exists. Volograd was put in its own timezone at UTC+04:00 in 2016. See link from Microsoft.
Old: (UTC+03:00) Moscow, St. Petersburg, Volgograd
New: (UTC+03:00) Moscow, St. Petersburg
Obviously, matching the timezone name is never going to work.
I am focusing on getting the full information using the TimeZoneStruct instead; which should allow me to create a custom TimeZoneInfo Object; and then later I will be able to convert it into Local Time.
My problem is that when attempting to access this struct, I am getting the following error:
System.Runtime.InteropServices.COMException (0x80040102): Object does not support property "http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/82330102".
I have looked at OutlookSpy and can see that the property is indeed accessible.
I am using .NET Framework 4.6; Outlook 2016; Visual Studio 2015; Windows 8.1.
Any suggestions?
UPDATE
I'm trying to access this property using VBscript on Outlook Spy and getting a similar error.
The properties that are not PT_BINARY seem to work, for some reason.
Any ideas?
here's how to repeat the experiment
Using OutlookSpy, select a recurring appointment.
Make sure you are selecting the master and open the "Current Item" to run a script on the current AppointmentItem.
Enter the following code.
See screenshot for reference.
set msg = AppointmentItem
set pa = msg.PropertyAccessor
debug.print pa.GetProperty("http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/8234001F")
debug.print pa.GetProperty("http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/82310003")
debug.print pa.GetProperty("http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/82330102")
Outlook likes to play the Big Brother to prevent you from modifying, or sometimes even accessing, some properties that it considers special.
Using Extended MAPI (C++ or Delphi) or Redemption (any language, I am its author) instead of OOM is the only workaround.
Related
My app works with a public calendar via CalDAV protocol (let's call it CalDAV calendar) which returns events in iCalendar format. One user started to create events in that calendar using Outlook localized to Russian language. It happened that Outlook put TZID field in the CalDAV calendar event in Russian language, as follows:
BEGIN:VCALENDAR
PRODID: some prod id
VERSION:2.0
BEGIN:VTIMEZONE
TZID:(UTC+03:00) Москва\, Санкт-Петербург
BEGIN:STANDARD
DTSTART:19710101T000000
TZOFFSETFROM:+0300
TZOFFSETTO:+0300
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
ORGANIZER;CN=UserName:MAILTO:username#mail.com
RRULE:FREQ=DAILY;UNTIL=20230108T100000Z
DTSTAMP:20230109T101100Z
UID:russiantz001
SEQUENCE:0
SUMMARY:Тест с 6 по 8 в 13 00 - 13 30
DTSTART;TZID="(UTC+03:00) Москва, Санкт-Петербург":20230106T130000
DTEND;TZID="(UTC+03:00) Москва, Санкт-Петербург":20230106T133000
DESCRIPTION:Russian TZ
CalDAV calendar treats events correctly. To deserialize iCalendar event I am using iCal.NET library which in turn uses NodaTime method DateTimeZoneProviders.Tzdb.GetZoneOrNull(TimeZoneId) to convert time from a time zone to UTC. It searches all time zone providers (IANA, BCL, serialization, etc) to see if TimeZoneId matches. Unfortunately, NodaTime does not understand TimeZoneId in Russian.
My question: how to get a correct English equivalent of the TimeZoneId in Russian generated by the localized Outlook?
.NET method FindSystemTimeZoneById throws exception that TimeZoneId is not found.
My app works in Linux environment. Therefore I cannot use Windows registry HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zones records. Moreover, to use registry records Windows should have been localized to the Russian language which would not happen for sure.
For now I am thinking just to use (UTC+03:00) prefix of the time zone Id in Russian, but I am not sure if this is right decision. For example, will time zone offset be correct during daylight saving period?
I would greatly appreciate any link or hint how to solve this conversion issue.
Time zone IDs should never be localized. What you have in the TZID field appears to be a time zone display name, not an ID. The application that created that file is incorrectly using the DisplayName property of the TimeZoneInfo object where it should be using Id property instead.
The correct Windows ID that should be showing in the file is "Russian Standard Time". Or it could (preferably) show the equivalent IANA time zone ID, which is "Europe/Moscow". They should be those exact strings and not translated to Russian.
The iCal format itself (and anything consuming it) doesn't care about this because it is strictly looking at the TZID field as it exists within the file. But anything else you use it for absolutely will.
The original application needs to be updated to return a time zone identifier instead of a display name in the TZID field.
Just using the time zone offset might be sufficient - but it may not always be. For example, if the time zone is one that changes offsets due to daylight saving time, the offset in the display name won't necessarily be the correct offset in effect for the event in the calendar.
The offset might also be different on the start time than on the end time, if the event crosses a DST transition. Moreover, if the event is recurring, the offset can be different between occurrences of events.
Then again, that particular time zone doesn't use DST (at least it doesn't presently), so you may never encounter such cases.
I am search Outlook using interop and I'm trying to filter emails based on date & time, including down to milliseconds, but it appears not to be supported.
I have the following filter, if I remove the sub-second component it works - it does not return anything, but with the '.1234' it is returning everything in the Inbox.
urn:schemas:httpmail:datereceived > '2023-01-09 13:22:22.1234' and urn:schemas:mailheader:subject like '%Example Test Email'
Is it possble to filter/search using sub-second values?
Is it possble to filter/search using sub-second values?
Nope. Outlook evaluates date-time values according to the time format, short date format, and long date format settings in the Regional and Language Options applet in the Windows Control Panel. In particular, Outlook evaluates time according to that specified time format without seconds. If you specify seconds in the date-time comparison string, the filter will not operate as expected.
Yes, both Outlook UI and OOM go though the same code that always rounds all datetime values to minutes. You'd need to use Extended MAPI (C++ or Delphi) or Redemption (any language, I am its author) if you want to work around that limitation.
We are writing a c# server to generating the .ics files which would be shared by people from different timezones. We have one requirement says if the people in Sydney open the file the event says 9:30pm. The people in Perth should also see it as 9:30pm. i.e. No auto timezone offset applied the calendar by outlook.
I have looked many places and yet to find a solution.
Is that possible?
I don't think this really makes sense in terms of what an ics file represents - it's an invitation to an event, where "an event" is a thing which happens at a specific time. If something's happening at 09:30 in Sydney, then it's not happening at 09:30 in Perth so it can't be the same event. Sounds to me like you need to create multiple events, one for each timezone.
I work for a company that develops a CRM tool and offers integration with MS Office(2003 & 2007) from windows XP to 7. (I'm working using Win7)
My task is to call an Outlook instance (using C#) from this CRM tool when the user wants to send an email and prepopulate with data of the CRM tool (email, recipient, etc..)
All of this already works just fine.
The problem I'm having is that Outlook's "object model guard" is throwing com Exception
(Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT)))
the moment I try to read a protected value from the mailItem (such as mail.bodyHTML).
Example Snippet:
using MSOutlook = Microsoft.Office.Interop.Outlook;
//untrusted Instance
_outlook = new MSOutlook.Application();
MSOutlook.MailItem mail = (MSOutlook.MailItem)_outlook.CreateItem(MSOutlook.OlItemType.olMailItem);
//this where the Exception occurs
string outlookStdHTMLBody = mail.HTMLBody;
I've done quite a bit of reading and know that my Outlook Instance (derived by using new Application) is considered untrusted and therefore the "omg" kicks in.
I do have a workaround for development:
I'm running VS2010 as Administrator and if I run Outlook as Administrator as well - all is good. I suppose this is due to them having the same integrity levels(high) and the UAC(?) is not complaining. But that just ain't the way to go for deployment.
Now the question is:
Is there a way to obtain a trusted instance of Outlook so that I can avoid this exception?
I've already read that when developing an Office Add-In using VSTO one can obtain a trusted Instance from the OnComplete event and/or using "ThisAddin"
But I "merely" want to start an outlook instance and preopulate it, and do not want to develop an Add-In since this is not the requirement.
And to make it clear - I have no problem with pop ups informing the user that outlook is being accessed - I just want to get rid of the exception!
So how can I get around this problem using code?
Any help is highly appreciated!
Thomas
Take a look at Dimitry's Redemption Lib, It was designed to do exacly this.
Well,
I've already spent way too much time and energy on this question so I think I came up with a pragmatic workaround for my particular case - but no real solution!
The problem is apparently due to the programms running at different integrity levels (Outlook = medium, VS2010 = admin or high). Office runs by default on a medium level and so will my future application once deployed. So there shouldn't be any trouble, since if the CRM and Outlook run at the same level, there's no problem.
For development I just let em both run on high, or medium (starting my compiled files from the debug folder).
In any other case a Messagebox warning is shown informing the user of the different integrity levels that cause an exception and prevent access.
At the code level, when I try to read any (by Outlook) prepolutated, protected properties and the object model guard raises the exception, I just catch it and use default values instead.
Why I had to read them in first place is currently beyond me - but so were the specs which were handed to me.
Anyway thanks for reading and if I ever come up with a solution I'll be sure to psot it - until then keep in mind that a pragmatic solution is better then none!
Happy Father's Day everyone!
I use a VB6/COM+ application which outputs date/time values based on the short date settings in the Control Panel, Regional Settings, for the user that runs it. The program that then parses that output has a configurable setting for the date format it expects, and presents in the UI.
e.g. If the regional setting for the user is set to mm/dd/yyyy, and it outputs 06/18/2009, the application expecting "18/06/2009" fails with "String was not recognized as a valid DateTime".
As we usually run this application as a service account, which we have not logged in as interactively to create a profile, we generally set the correct date format and then tick the "Apply all settings to the current user account and the default user profile" option.
I would like to be make the C# configuration utility I have written for this mess to be able to set the date format programmatically for a given user.
Edit
I would like nothing more than to change the code, but do not have the ability to do so at this time.
I also know that what I am asking is a bad thing to do. With regards to "it should be the user's choice" - I am that user, as I create it explicitly for the task; I just want to set the date format by a scripted method, rather than having to do the clicking myself.
This is specifically discouraged by Microsoft. Any solution you may come up with will be a filthy hack that will probably stop working soon.
Think of it this way: who are you to decide those settings? Don't you think that's the user's decision?
Back on topic: find an unambiguous format for the applications to communicate in, such as YYYYMMDD. The application that displays can then simply respect the actual user settings, as it should.
But, since you can't change it, just poke into the registry:
Current user:
HKEY_CURRENT_USER\Control Panel\International
Specific user:
HKEY_USERS\(user SID)\Control Panel\International
Default user:
HKEY_USERS\.DEFAULT\Control Panel\International
sShortDate is probably the value you want to change.
If you are going to modify the profile to suit your needs, why not just ignore the profile settings and hardcode the format you want in your app?
code:
Imports System.Threading
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US", False)
Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\International", "sShortDate", "M/d/yyyy")
While persistently changing a user's culture (regional settings) is to be done cautiously, there are legitimate use cases.
On Windows 8 and Windows Server 2012 and above, Windows PowerShell comes with the
Set-Culture cmdlet, which is the programmatic equivalent of choosing a different region via Control Panel (intl.cpl).
For instance, Set-Culture fr-CA is the equivalent of interactively choosing region French (Canada) for the current user.
Caveat: Mixed cultures such as en-DE (sic) appear not to work as of Windows PowerShell v5.1 - see this answer of mine.
While it won't be fast, it is possible to call PowerShell commands from C#.