Outlook Interop Exception HRESULT: 0xCA140115 - c#

I have some pretty basic code that seems to work for most people but there's at least one workstation that throws this HRESULT code when it runs these couple lines of code:
Outlook.Application _OutlookInstance = new Outlook.Application();
Outlook.Stores stores = _OutlookInstance.Session.Stores;
Any idea what HRESULT code 0xCA140115 is or what it means? I can't find it on MSDN anywhere...
The workstation that experiences the problem is at a remote call center location, so I can't do any immediate testing/debugging, or easily see what is specifically different about this workstation versus the others. I would imagine there might be more workstations at that same call center that could have the error, but this code is still in the testing phase.

Sorry for the delay, but I was able to get through several more iterations of testing and find out what the issue was. First off, my original post was incorrect. The code flow made it seem like the error was happening during those 2 initial lines, but it was actually happening a little later, when I was looping through the stores, like this:
Outlook.Stores stores = _OutlookInstance.Session.Stores;
foreach(Outlook.Store store in stores) // <----- THIS LINE
{
...
}
Each time the user ran this, he would get a different HRESULT error code:
0xCA140115
0xAF64011D
0xC1F4011D
0xC834011D
The only consistent factor was the "4011" in the middle.
When I upped the logging, I could see that the user had 18 mailboxes and the foreach() loop was getting through the first 3 but failing on the 4th. The 4th mailbox was a "Public Folders" store associated to another mailbox that was added in a different way than the rest of the mailboxes (it had something to do with it being an Outlook 365 mailbox that required different authentication).
So essentially it ended up being that any attempt to even touch that particular mailbox/store (including the "store" variable being set) would result in that COM exception.
I was able to work around it by looping through stores via numeric index so that the setting of "store" was inside my try/catch block, like this:
for(int i = 0; i < stores.Count; i++)
{
try
{
Outlook.Store store = stores[i];
...
}
catch(Exception)
{
...
}
}
Now when the loop hit that particular store, I could tell that it was Outlook saying that the server wasn't available, and the store was an online-only store, so the store couldn't be accessed.
I'm still not certain about why the error codes changed each time, but there you have it.

Related

Cannot read all users from Active Directory - [DirectoryServicesCOMException] MoveNext()

My team is using a program written in C# to read all users from a specific OU. The program behaves very strange. Sometimes it is working for a couple of weeks and then without any big changes on our AD or any other related component, it throws an exception. Then it is not working for a couple of weeks and after some time it start to run normally again.
Code
DirectoryEntry searchRoot = new DirectoryEntry("<LDAP string>")
searchRoot.AuthenticationType = AuthenticationTypes.None;
DirectorySearcher search = new DirectorySearcher(searchRoot);
search.Filter = <our filter>;
search.PropertiesToLoad.Add("<some property>");
search.PageSize = 1;
SearchResult result;
SearchResultCollection resultCol = null;
try
{
resultCol = search.FindAll();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
if (resultCol != null)
{
Console.WriteLine("Result Count: " + resultCol.Count); //.Count throws the Exception
}
Exception
Unhandled Exception: System.DirectoryServices.DirectoryServicesCOMException: An operations error occurred.
at System.DirectoryServices.SearchResultCollection.ResultsEnumerator.MoveNext()
at System.DirectoryServices.SearchResultCollection.get_InnerList()
at System.DirectoryServices.SearchResultCollection.get_Count()
Data: System.Collections.ListDictionaryInternal
Error Code: -2147016672
Extended Error: 8431
Extended Error Message: 000020EF: SvcErr: DSID-020A07A7, problem 5012 (DIR_ERROR), data -1018
HResult: -2147016672
Message: An operations error occured.
Source: System.DirectoryServices
Stack Trace: at System.DirectoryServices.SearchResultCollection.ResultsEnumerator.MoveNext()
Target Site: Boolean MoveNext()
Additional Information
Target Framework: .Net Framework 4.6.1 (no additional libraries)
The program is executed on a domain controller
What I have tried
I have created a loop to use the MoveNext() function of the
enumerator and found out that it loads results up to a specific
element and then crashes
It is always the same element
After the first exception all retries fail as well
The user that starts it is a domain admin (but I
have also tried it with an enterprise admin account, so it is
probably not a permission issue)
I have deleted the user that should be read when the exception happens but dring the next run the exception was thrown for a previous user
I have come to a point, where I have no more ideas on solving this problem. I would appreciate all your support.
This answer just summarizes our conversation in comments.
This thread partially matches the error you are getting:
problem 5012 (DIR_ERROR) data -1018
And the answer from a Microsoft MVP is:
That is a checksum error in the database, you have corruption in your
database which is usually due to a failing disk or disk subsystem or
possibly a system crash and data not being written from a write cache.
So it sounds like you might have the same thing going on.
But it may only be one DC that has the problem. So to help you narrow down which one, you can specify the DC in the LDAP path like so:
LDAP://dc1.example.com/OU=Target,OU=My User Group,OU=My Users,DC=example,DC=com
This can help you in two ways:
It can identify the bad DC so you know which one you need to fix (and possibly take it offline until it is fixed), and
You can specifically target a good DC so your script will keep working.

Get other user's Outlook availability information

I am writing an application that creates an overview of peoples Outlook calendars, i.e it will show the amount of unplanned time per week for the coming [n] weeks.
The basics are working, but there's one thing that I am having trouble with. Some users have shared their Outlook calendar in a way so that other users can only see availability information (the time and description of the appointments), but not any details.
I verified this by opening Outlook manually and opening a shared calendar; hovering the mouse over an appointment will show a popup with begin and end time, description and location, but double clicking it gives an error: "You are not authorized to display the calendar, do you want to ask [person] to share it?".
The relevant lines from my code are:
var outlook = new Application();
var mapiNamespace = outlook.GetNamespace("MAPI");
var recipient = mapiNamespace.CreateRecipient("Scott");
recipient.Resolve();
var calendarFolder = mapiNamespace.GetSharedDefaultFolder(recipient, OlDefaultFolders.olFolderCalendar);
var calendarItems = calendarFolder.Items;
Everything I now try to do with calendarItems will raise an exception. For instance, getting Count will raise a TargetInvocationException (The client process failed, but I'm not quite sure about the exact English translation). Calling Sort("[Start]") will raise a COMException with message Unknown property: Start. Both do work for fully shared calendars.
Now, for the overview, all I need is begin and end times, so I don't really want to ask everyone to change their sharing settings, especially when that shouldn't be necessary.
My questions are:
Most important: Is there another way to get availability info that I'm overlooking?
And related: Is Interop still the way to go these days, or are there alternatives? Maybe an Office365 webservice?
Instead of using GetSharedDefaultFolder and accessing the items in that folder, you can use Recipient.FreeBusy method.

C# Launching another WPF program from a byte array [duplicate]

This question already has answers here:
Load WPF application from the memory
(2 answers)
Closed 6 years ago.
First of all, let me say that I've looked through this, and i still haven't been able to find a great solution to my problem. (I will elaborate in post)
Now to the point.
I have a program which I want to secure with a login.
My setup is as follows:
Login.exe
Application.exe (Gathered from server into byte[])
The user should login, and when successfully logged in, get the server file (Application.exe) and run it, however this file must not be stored locally on the users machine. Instead, this file, which is stored as a byte array, should be launched as a program, but, if possible, not with a location on the harddrive.
Here's how the user would see it:
First they'd get the login application, login and the application
would download the file from server, and execute it.
Now the main problem i've been struggling with is, that whenever i load this byte array, i get the following Exception:
System.Reflection.TargetInvocationException: The destination of an activation triggered an exception. ---> System.InvalidOperationException: Can not create more than one instance of System.Windows.Application in the same AppDomain.
I've tried with multiple ways, but I've always ended up with the following code:
Assembly a = Assembly.Load(tmpbytearray);
MethodInfo method = a.EntryPoint;
if (method != null)
{
object o = a.CreateInstance(method.Name);
method.Invoke(o, null);
}
I've also tried with
Assembly assembly = Assembly.Load(tmpsrc);
//entrypoint: MyMainApplication.App.Main
Type type = assembly.GetType("MyMainApplication.App");
var obj = Activator.CreateInstance(type);
type.InvokeMember("Main",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
null);
But still stuck with the same Exception.
As I've read through the reference (Section B and C) from the top I've also seen the usage of CreateInstanceFromAndUnwrap, but as I can't find a way to supply it with a byte array, instead of a file path, I've decided not to go that way.
Now I'm back to square one, and therefore asking here in my last hopes to sum up a solution to this project.
If i've made some misunderstandings throughout the post, feel free to ask, as I will do my best to be as clear and understandable as possible.
Thanks in advance!
UPDATE (Maybe another approach)
I've now thought of making a small console based application, which would act as a "launcher" for this application. However this also gives an exception:
System.Reflection.TargetInvocationException: The destination of an activation triggered an exception. ---> System.IO.IOException: The resource mainwindow.xaml was not found.
This exception is really weird, as the application itself works when ran. So the following:
Assembly a = Assembly.Load(tmpsrc);
MethodInfo method = a.EntryPoint;
if (method != null)
{
object o = a.CreateInstance(method.Name);
method.Invoke(o, null); //Exception.
}
Depending on what might be the most easy solution, what would you prefer, and how would you think of a possible solution to any of the approaches (The second, or first approach)?
(I cannot mark this as complete, but this question has now been solved)
So, some struggles later, I've finally managed to get this working.
I ended up trying many things, but the solution for me was based on this question.
I took the loader class in my Login Application and added the rest after the login has been authorized successfully:
var domain = AppDomain.CreateDomain("test");
domain.Load("Login");
var loader = (Loader)domain.CreateInstanceAndUnwrap("Login", "Login.Loader");
loader.Load(tmpsrc);
After that it somehow worked, which i'm quite surprised for. But anyways, thanks for the help and pinpoints into the proper subjects!

Get Direct Reports from Logged in user from Exchange

I need to get the direct reports from a logged in user (MVC 4)
I don't need the names of the direct reports but I do need their email addresses including their proxy addresses.
So for this reason I need to search through Exchange. I personally have never attempted to search Exchange in the past and everything I find out there tells me how to get from step 8 to the finish line but says nothing about how to go from step 1 to 8.
I can get the current users user name by simply
User.Identity.Name.Replace(#"yourdomain\", "")
and I have found this example which so far is probably the best example I have found
http://msdn.microsoft.com/en-us/library/office/ff184617(v=office.15).aspx
but even with that example the line
Outlook.AddressEntry currentUser =
Application.Session.CurrentUser.AddressEntry;
is not actually getting the current user logged into the site.
I really hope someone out there is familiar with this and can get me past this point.
I reworked the sample from the URL as the following LINQPad 4 query. I've found that LINQPad is a great way to experiment because it is very scripty, allowing quick experimentation, and you can easily view data by using the Dump() extension method. Purchasing intellisense support is totally worthwhile.
Also, I noticed there is a lot of fine print like:
The logged-on user must be online for this method to return an AddressEntries collection; otherwise, GetDirectReports returns a null reference. For production code, you must test for the user being offline by using the _NameSpace.ExchangeConnectionMode property, or the _Account.ExchangeConnectionMode property for multiple Exchange scenarios.
and
If the current user has a manager, GetDirectReports() is called to return an AddressEntries collection that represents the address entries for all the direct reports of user’s manager. If the manager has no direct reports, GetDirectReports returns an AddressEntries collection that has a count of zero.
So there are a lot of assumptions like Exchange is configured properly with Direct Report relationships, and the current user is online...which I believe brings Lync into the equation. Hopefully this LINQPad query will be useful to you. Just copy and paste it into a text editor and name it with the .linq file extension. You'll then be able to open it in LINQPad 4. BTW: You're question caught my attention because there was talk recently at my work of pulling direct reports from Active Directory. I wish I could be more helpful...good luck.
<Query Kind="Program">
<Reference><ProgramFilesX86>\Microsoft Visual Studio 12.0\Visual Studio Tools for Office\PIA\Office15\Microsoft.Office.Interop.Outlook.dll</Reference>
<Reference><ProgramFilesX86>\Microsoft Visual Studio 12.0\Visual Studio Tools for Office\PIA\Office15\Microsoft.Office.Interop.OutlookViewCtl.dll</Reference>
<Namespace>Microsoft.Office.Interop.Outlook</Namespace>
</Query>
void Main()
{
GetManagerDirectReports();
}
// Define other methods and classes here
private void GetManagerDirectReports()
{
var app = new Microsoft.Office.Interop.Outlook.Application();
AddressEntry currentUser = app.Session.CurrentUser.AddressEntry;
if (currentUser.Type == "EX")
{
ExchangeUser manager = currentUser.GetExchangeUser().GetExchangeUserManager();
manager.Dump();
if (manager != null)
{
AddressEntries addrEntries = manager.GetDirectReports();
if (addrEntries != null)
{
foreach (AddressEntry addrEntry in addrEntries)
{
ExchangeUser exchUser = addrEntry.GetExchangeUser();
StringBuilder sb = new StringBuilder();
sb.AppendLine("Name: " + exchUser.Name);
sb.AppendLine("Title: " + exchUser.JobTitle);
sb.AppendLine("Department: " + exchUser.Department);
sb.AppendLine("Location: " + exchUser.OfficeLocation);
sb.Dump();
}
}
}
}
}
I would suggest using EWS Managed API in conjunction with your code to get the direct reports for a user. As Jeremy mentioned in his response that you need to have your direct report relationships already set up. To help you get started, here some steps to get EWS Managed API up and running:
Download the latest version of EWS Managed API
Get started with EWS Managed API client applications to learn about how to reference the assembly, set the service URL, and communicate with EWS.
Start working with your code. If you need some functioning code to get you going, check out the Exchange 2013 101 Code Samples that has some authentication code already written and a bunch of examples you can modify to make your own.
If you have the email address or user name of the current user you can use the ResolveName() method to get to their mailbox to retrieve additional information. Here is an article to help with that method: How to: Resolve ambiguous names by using EWS in Exchange 2013
Essentially you want to get to the point where you can run a command similar to this:
NameResolutionCollection coll = service.ResolveName(NameToResolve, ResolveNameSearchLocation.DirectoryOnly, true, new PropertySet(BasePropertySet.FirstClassProperties));
If you give a unique enough value in the NameToResolve parameter you should only get back one item in the collection. With that, you can look at the direct reports collection within that one item and see not only the names of their direct reports, but their email addresses as well.
I hope this information helps. If this does resolve your problem, please mark the post as answered.
Thanks,
--- Bob ---

ActiveDirectory error 0x8000500c when traversing properties

I got the following snippet (SomeName/SomeDomain contains real values in my code)
var entry = new DirectoryEntry("LDAP://CN=SomeName,OU=All Groups,dc=SomeDomain,dc=com");
foreach (object property in entry.Properties)
{
Console.WriteLine(property);
}
It prints OK for the first 21 properties, but then fail with:
COMException {"Unknown error (0x8000500c)"}
at System.DirectoryServices.PropertyValueCollection.PopulateList()
at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Entry()
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Current()
at ActiveDirectory.Tests.IntegrationTests.ObjectFactoryTests.TestMethod1() in MyTests.cs:line 22
Why? How can I prevent it?
Update
It's a custom attribute that fails.
I've tried to use entry.RefreshCache() and entry.RefreshCache(new[]{"theAttributeName"}) before enumerating the properties (which didn't help).
Update2
entry.InvokeGet("theAttributeName") works (and without RefreshCache).
Can someone explain why?
Update3
It works if I supply the FQDN to the item: LDAP://srv00014.ssab.com/CN=SomeName,xxxx
Bounty
I'm looking for an answer which addresses the following:
Why entry.Properties["customAttributeName"] fails with the mentioned exception
Why entry.InvokeGet("customAttributeName") works
The cause of the exception
How to get both working
If one wants to access a custom attribute from a machine that is not
part of the domain where the custom attribute resides (the credentials
of the logged in user don't matter) one needs to pass the fully
qualified name of the object is trying to access otherwise the schema
cache on the client machine is not properly refreshed, nevermind all
the schema.refresh() calls you make
Found here. This sounds like your problem, given the updates made to the question.
Using the Err.exe tool here
http://www.microsoft.com/download/en/details.aspx?id=985
It spits out:
for hex 0x8000500c / decimal -2147463156 :
E_ADS_CANT_CONVERT_DATATYPE adserr.h
The directory datatype cannot be converted to/from a native
DS datatype
1 matches found for "0x8000500c"
Googled "The directory datatype cannot be converted to/from a native" and found this KB:
http://support.microsoft.com/kb/907462
I have the same failure. I´m read and saw a lot of questions about the error 0x8000500c by listing attribute from a DirectoryEntry.
I could see, with the Process Monitor (Sysinternals), that my process has read a schema file. This schema file is saved under
C:\Users\xxxx\AppData\Local\Microsoft\Windows\SchCache\xyz.sch.
Remove this file and the program works fine :)
I just encountered the issue and mine was with a web application.
I had this bit of code which pulls the user out of windows authentication in IIS and pulls their info from AD.
using (var context = new PrincipalContext(ContextType.Domain))
{
var name = UserPrincipal.Current.DisplayName;
var principal = UserPrincipal.FindByIdentity(context, this.user.Identity.Name);
if (principal != null)
{
this.fullName = principal.GivenName + " " + principal.Surname;
}
else
{
this.fullName = string.Empty;
}
}
This worked fine in my tests, but when I published the website it would come up with this error on FindByIdentity call.
I fixed the issue by using correct user for the app-pool of the website. As soon as I fixed that, this started working.
I had the same problem with a custom attribute of a weird data type. I had a utility program that would extract the value, but some more structured code in a service that would not.
The utility was working directly with a SearchResult object, while the service was using a DirectoryEntry.
It distilled out to this.
SearchResult result;
result.Properties[customProp]; // might work for you
result.Properties[customProp][0]; // works for me. see below
using (DirectoryEntry entry = result.GetDirectoryEntry())
{
entry.Properties[customProp]; // fails
entry.InvokeGet(customProp); // fails as well for the weird data
}
My gut feel is that the SearchResult is a little less of an enforcer and returns back whatever it has.
When this is converted to a DirectoryEntry, this code munges the weird data type so that even InvokeGet fails.
My actual extraction code with the extra [0] looks like:
byte[] bytes = (byte[])((result.Properties[customProp][0]));
String customValue = System.Text.Encoding.UTF8.GetString(bytes);
I picked up the second line from another posting on the site.

Categories