I've been searching for a solution for a few days now, I've looked through the MSDN for Interop.Outlook and I think I've found what I need, but can't seem to implement it properly.
Here's the code I've came up with based on something similar I saw in VBA.
class Program
{
Stores allstores = new Stores();
Store store;
static void Main(string[] args)
{
foreach (var store in allstores)
{
MessageBox.Show(store.FilePath);
}
}
}
`
This essentially needs to cycle through a list of computers, and run this code on their outlook(some 2003, some 2007) in order to inventory all connected PST's in each outlook profile. I'm sure there's more code to this, but I can't get this portion to work at all. There seems to be a lack of information on inventorying Outlook data files, most of it is reading e-mails from the mailboxes and not the data file itself.
If someone could shed some light on what I'm overlooking, It'd be greatly appreciated.
EDIT:
I've actually made a working piece of code now, however I have a problem with compatibility. The program works as designed in Office 2010/2007, however it crashes when accessing a 2003 version. I imagine I need to use the Microsoft Office Object 11.0, however I only have Microsoft Office Object 12.0 listed - is there a way to get the 11.0 reference?
This may be of use, pretty thorough object model comparison and development guide.
There is no reason to actually log to any Outlook profiles (which might require an authentication prompt). All the information is already in the profile section in the registry. The exact location is Outlook version specific, and the profile section guids are generated randomly, so the documented profile management API (IProfAdmin etc.) is the way to go, but unfortunately it is Extended MAPI and requires C++ or Delphi.
As of Outlook 2007, Outlook Object Model exposes Namespace.Stores collection and Store.FilePath property, so you can loop through all stores and read the FilePath property for each store (be sure to filter out OST files).
Note that there can be multiple Outlook profiles (as shown in Control Panel | Mail | Show Profiles), but Outlook can only work with one profile at a time, so to use a different profile, you'd need to close Outlook.
If using Redemption is an option (I am its author), it includes ProfMan library (accessible in any language) which will let you extract all PST file locations from all local profiles without actually logging in.:
'Print the path to all the PST files in all profiles
PR_PST_PATH = &H6700001E
set Profiles=CreateObject("ProfMan.Profiles")
for i = 1 to Profiles.Count
set Profile = Profiles.Item(i)
set Services = Profile.Services
Debug.Print "------ Profile: " & Profile.Name & " ------"
for j = 1 to Services.Count
set Service = Services.Item(j)
If (Service.ServiceName = "MSPST MS") or (Service.ServiceName = "MSUPST MS") Then
'there should be only one provider for this service
'but we should really loop through all the providers
Debug.Print Service.Providers.Item(1).ProfSect.Item(PR_PST_PATH)
End If
next
next
Related
I'm creating a solution for managing remote MS Office documents. I used library made by IT Hit WebDAV System (www.webdavsystem.com) as a prototype. It's doing pretty well actually, except I cannot open document in read-only mode using URIs for office (based on Office URI Schemes by Microsoft).
I want to open the document in read-only mode, so someone else can edit it in the same time. As it can be seen in B-3. URI Scheme Syntax part of mentioned documentation, there are three commands available:
ofe - open for edit
ofv - open for view
nft - new from template
It seems that server acts always as "ofe" commands was given, no matter which one was used. Actually, entering "whatever" also works, it can be literally everything. Using MS Word for example, I post request order below:
OPTIONS => HEAD => OPTIONS => OPTIONS => LOCK => GET => PROPFIND => OPTIONS
As I am understanding correctly, successful LOCK attempt results in opening the document in edit mode. That tells me, that somewhere before that point MS WORD should ask for permission to do it, but I analyzed previous requests and was unable to find any related data.
It is not my environment issue also. I checked it with SharePoint and it was ok. That's why I would blame the server.
As I read that sentence(below) in this question,
most WebDAV clients ignore this and pretend that the entire server is either read-write or read-only
I started to wonder. Maybe that's the case? Maybe the library skips that and treats every file as read-write? If yes, how can I check it to be sure?
I've checked also this topic. The author mentions, that he has Office URI command in his OPTIONS requests, but links are no longer valid. In the requests that are sent by MS Office 2016, I can't find it anywhere. Should it be anywhere? Where?
Last, but not least, I found this topic. It seems to be exactly my problem, but it don't have the solution mentioned, or at least anything that worked in my case.
I will appreciate any help.
We have recently retested ofv and ofe options with latest MS Office 2016 for Windows and for Mac OS X with all updates installed. Here is what we have found:
On Windows this option is being ignored. Regardless of this parameter
MS Office opens as read-write.
On Mac OS this option is required. MS
Office respects this option and opens depending on ofv/ofe as
read-only or read-write.
From our experience there is no reliable way to open a document as read-only. In SharePoint Online (SPS 2016) there is also no option to open a document as read-only in the desktop version of MS Office.
One workaround could be throwing DavException in IFileAsync.WriteAsync() method implementation when saving a file. Please note that MS Office will ignore the message text being returned and will just display a generic error.
Another workaround would be marking a document as read-only in IMsItemAsync.GetFileAttributesAsync() method implementation:
public async Task<FileAttributes> GetFileAttributesAsync()
{
return fileSystemInfo.Attributes | FileAttributes.ReadOnly;
}
MS Office will display a yellow ribbon "UPLOAD FAILED This file is locked for editing by another user".
I need to get information about the product of a process.
As an example, I need to know whether the process WINWORD belongs to Office 2010 or Office 2013. Another example would be with the software of adobe creative suite.
In general for a process, which name can be the same for different suites, how to find out the suite version.
In a service I have a list of process names, retrieved from a server. I track for how long a user has been using these process and send this info back to the server. Because the service will be installed in several computers, the Office suite, the Adobe suite or any other product, may be different, but the process is likely to be named the same in each suite.
Currently, in the server I have no way to identify to which version the process belongs to. It a requierement to be able to show for how long, for example, Microsoft Word 2010 has been used and so for each version
I hope I'm being clear.
Thanks #Niels for your contribution, which is to retrieve a process MajorPart from it's FileVersionInfo.
We can send this info as an addition. Surely it makes it simple to identify a suites like Office, where all the products versions major part are the same, butt...
With the adobe list you've showed me that in a adobe suite most products will have a different mayor versions and that's what we're affraid of with checking a process FileVersionInfo. Having to setup in the server a way to link each product's major version with the suite just for adobe, means that such thing has to be done for each software in the same or similar situation.
You can look into the file properties, as also exposed by Explorer:
To retrieve this data in .NET you inspect a FileVersionInfo instance as returned by FileVersionInfo.GetVersionInfo. Samples are provided on both help pages, but the easiest would be for your case as you're only interested in the major version numbers:
// Get the file version for the notepad.
FileVersionInfo myFileVersionInfo =
FileVersionInfo.GetVersionInfo(Environment.SystemDirectory + "\\Notepad.exe");
// Print the product major part number.
textBox1.Text = "Product major part number: " + myFileVersionInfo.ProductMajorPart;
Build numbers themselves are well documented for good software suites like MS Office.
I'm trying to run this code:
this.storage =
Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts)
.GetStorage("ws_up_storage", Outlook.OlStorageIdentifierType.olIdentifyByMessageClass);
It runs perfectly well on some machines, but on others it throws this exception:
I also tried other folder names, like olFolderInbox, olFolderCalendar. I've looked at Microsoft docs for this, and it says this error is to be expected if the folder is one of the following:
The folder is a Microsoft Exchange public folder, an Internet Message Access Protocol (IMAP), MSN Hotmail, or a Microsoft SharePoint Foundation folder.
The user permission for the folder is read-only.
The store provider does not support hidden items.
The sad fact is, I do not know how to check which one of these is true and if it's at all possible.
How would I go about determining the cause of the problem and addressing it?
The easiest way to handle all these cases is to try to get a storage. You will need much efforts to implement all cases. The PR_MDB_PROVIDER property allows to identify the store provider, but not all cases such as user permissions for the folder and etc. You can use the try/catch block where you may check the error code - 0x80040102 (MAPI_E_NO_SUPPORT).
However, you may use any low-level property viewers (for example, a free open source tool - MFCMAPI) for exploring Extended MAPI property values. Thus, you may find all the required info about not supported scenarious.
The error 0x80040102 is MAPI_E_NO_SUPPORT, which means the store does not support hidden (associated) items.
Read the PR_MDB_PROVIDER property (DASL name http://schemas.microsoft.com/mapi/proptag/0x34140102) using PropertyAccessor.GetProperty. The returned 16 byte array will be specific for each store kind. E.g. for an Exchange store, it will be pbExchangeProviderPrimaryUserGuid (5494A1C0297F101BA58708002B2A2517). Take a look at any object in the store in question using OutlookSpy (I am its author - click IMessage, IMAPIFolder, or IMsgStore) to see the PR_MDB_PROVIDER property.
I am trying to figure out how to drag and drop an email from Outlook 2010 into my .NET application. I've seen quite a few articles, most with very complex solutions. My thought is it shouldn't be that complex ... but I could be wrong.
Any help would be much appreciated!
A easier solution has been posted here: Get body from Outlook email [Drag’n’Drop]
Outlook.Application outlook = new Outlook.Application();
Outlook.Explorer oExplorer = outlook.ActiveExplorer();
Outlook.Selection oSelection = oExplorer.Selection;
foreach (object item in oSelection)
{
Outlook.MailItem mi = (Outlook.MailItem)item;
Console.WriteLine(mi.Body.ToString());
}
It uses Microsoft.Office.Interop.Outlook.dll. (It's on NuGet with the same name)
The two answers above are both good. However, there are a couple of things you need to know.
In the first answer you can download the sample program and run it and you will find that everything works great so long as you are running it on a 32 bit computer, otherwise, you have to recompile your program from "AnyCPU" to "X86". I spent most of today trying to figure out why the first two characters of the .msg file names (of the emails) I was dragging and dropping were missing. As soon as I recompiled with "X86" it all started working.
In the second answer you will find that yes you can use the code and it is a whole lot easier, however, if you need your application to run on some other version of outlook (other than the one you added to your references) it probably will not work. I used to use the same kind of Office objects referred to in the second answer and I ran into problems all the time when someone wanted to use my program on a different version of Office (i.e. if I pulled in Office version 14 and they wanted to use it on Office 2007).
i have this web application in c# .net running on an external web server.In that i am trying to generate and save the word doc on the server ( without opening it) . It runs fines on my local machine as i am having word installed on my machine but on the server it is showing error on using MyApplication Class. I understand it is not possible to install word on the server . Right now i am referenceing word.interopp assembly in my application .
Is there any better way to solve the issue .
Thanks and regards
Vickey Y.
If you're trying to use Office Interop without installing office on the server, then it's clearly going to fail.
Could you install Word on a different server and expose some sort of web service to create the document for you and serve the file contents back to the original server to save?
You may be able to use some third party libraries which can generate the relevant Word format, but I don't know of any.
What format does it have to be? Is it a complicated document? Could you just use RTF?
We use a third party tool called Aspose.Word. This allows you to perform a whole bunch of Word releated stuff without the need to install Word itself on the server.
the word.interop uses an instance of word to generate and save the documents. Even though it doesnt display the UI, the process of WINWORD will be running. In short, you need word installed on the server to use word.interop. When we did this, we also encountered issues when the servers needed to be compatible with word 2007 documents too, so its not an easy venture working with Word. Hope you get through the issue ok :)
I think you can do something like this.
I should alow you to open a document from the server.
protected void btnCreateWordBulletin_Click(object sender, EventArgs e)
{
String a= Server.MapPath("/Solution/Templates/Sport/Sport.doc");
String b= Server.MapPath("/Solution/Templates/Sport/SportSave.doc");
CreateWordDocument(a, b);
}
protected void CreateWordDocument(object fileName, object saveAs)
{
//Set Missing Value parameter - used to represent
//a missing value when calling methods through interop
object missing = System.Reflection.Missing.Value;
//Setup the Word.App class
Microsoft.Office.Interop.Word.Application WordApp = new Microsoft.Office.Interop.Word.ApplicationClass();
Microsoft.Office.Interop.Word.Document aDoc = null;
// Check to see that file exists
if (System.IO.File.Exists((string)fileName))
{... Activating doc etc...}}
Yes, you can have Word running on server. However, note that opening winword.exe process from web service will probably fire winword.exe as ASPNET user. Some versions of MS word displayed some customization modal form during first run, making it impossible to automate process of using Word in server environment. The solution was making ASPNET “login-enabled” user, logging to server as an ASPNET user, running Word manually, closing all first-time-configuration modal forms, and then setting ASPNET user to its normal state. Since those configuration windows appeared only during first run of winword (more precisely: until configuration was approved by user), this actually worked.
Note: using winword on server needs some legal investigation. As far as I know MS attitude towards such solutions is rather negative, while some legal systems find it perfectly ok. Also take into consideration need for managing winword processes, and … and in fact, this is a bit crude hack.
OfficeWriter is another potential solution for you if you need true DOC and DOCX (as opposed to RTF or some other format):
http://www.officewriter.com
Take a look at OpenXML which is the file format all word (and Office) documents are saved in by default. http://openxmldeveloper.org/