Can I make C# start Outlook in the code?
In VB6 we use object 'Outlook.Application' and write:'
Set oOutlook = CreateObject("Outlook.Application")
Set oNameSpace = oOutlook.GetNamespace("MAPI")
Set oInbox = oNameSpace.Folders(1)
'Set oInbox = oInbox.Folders("Inbox")
oInbox.Display
'oOutlook.Quit 'Close All Outlook copies
Copy/Paste from link: http://www.ozgrid.com/forum/showthread.php?t=73886
System.Diagnostics.Process will only start a process.
To do additional actions such choosing folders, you need to use Microsoft Visual Studio Tools for Office (VSTO). And here is it's reference. For example:
var outlook = new Microsoft.Office.Interop.Outlook.ApplicationClass();
outlook.Quit();
If you just want to start the outlook; using System.Diagnostics.Process would be the easiest way. :)
You could use its ProgID to get the type and the activator
Type objectType = Type.GetTypeFromProgID("Outlook.Application");
object outlook = Activator.CreateInstance(objectType);
But using this in C# you will lose all type information (i.e. no IntelliSense) and you need to call some ugly method to invoke the operations with LateBinding (google for Type.Invoke)
Other option is add a reference to Microsoft.Office.Interop.Outlook.ApplicationClass, so you have compile time type information and create an instance for Outlook in the usual way
using Microsoft.Office.Interop.Outlook;
Microsoft.Office.Interop.Outlook.ApplicationClass outlook
= new Microsoft.Office.Interop.Outlook.ApplicationClass();
Or you could use my Late Binding Helper library and use it like this
Invoker outlook = BindingFactory.CreateAutomationBinding("Outlook.Application");
outlook.Method("Quit").Invoke();
No Intellisense with this one, but at least the library will save you from the ugly calls to Type.Invoke and give you a fluent interface instead.
This works (you might have to change the path to what it is on the machine on which the app will run):
public static void StartOutlookIfNotRunning()
{
string OutlookFilepath = #"C:\Program Files (x86)\Microsoft Office\Office12\OUTLOOK.EXE";
if (Process.GetProcessesByName("OUTLOOK").Count() > 0) return;
Process process = new Process();
process.StartInfo = new ProcessStartInfo(OutlookFilepath);
process.Start();
}
Related
I've been trying to create a PPT with C# using something like the code below.
Microsoft.Office.Interop.PowerPoint.Application pptApp = new Microsoft.Office.Interop.PowerPoint.Application();
The problem is, if there's another powerpnt process running, the line of code above doesn't do anything (even when debugging it). The application just hangs infinitely.
Is there a way to be able to generate PPTs without having to kill an existing powerpnt process?
With Aspose.Slides for .NET, you don't need to install PowerPoint to generate presentations with a single line of code:
using (Presentation presentation = new Presentation())
{
// Add content to the presentation here
// ...
presentation.Save("output.pptx", SaveFormat.Pptx); // You can choose many other formats
}
Also, you can see your results by using Online Viewer here.
I work at Aspose.
In NET Framework you can hook into the "Running Object Table" (ROT) and get a running Powerpoint instance using InteropServices.Marshal.
Then you can work with the running instance. If it is not running you can start it.
using System.Runtime.InteropServices;
using PowerPointApp = Microsoft.Office.Interop.PowerPoint.Application;
PowerPointApp ppApp = null;
try
{
var ppType = System.Type.GetTypeFromProgID("PowerPoint.Application");
var ppRaw = Marshal.GetActiveObject("PowerPoint.Application");
ppApp = ppRaw as PowerPointApp;
}
catch
{
}
if (ppApp == null)
{
ppApp = new PowerPointApp();
}
Marshal.GetActiveObject is not available in .NET Core and current .NET 5/6
I am trying to automate the creation of install packages for the company i work for and am using the Installshield Automation Interface to create an MSI project. One of the things we have done up to now (manually if you can believe it) is go through all of the files we want to release after importing them into installshield and setting them to "Always overwrite" on a folder by folder basis since it seems you cant do it recursively on a parent folder. When creating a Basic MSI on the installshield GUI it lets you do this, however when creating an MSI via the COM object it appears this option is only available to InstallScript which i cant make an MSI with.
Anywho my code kinda looks like this
static void AddFiles(string[] aFiles, ISWiAuto24.ISWiProject oISProj, string sProjName, string ePackName)
{
oISProj.OpenProject(sProjName, false);
string installdirectory = "[ProgramFilesFolder]" + ePackName;
oISProj.INSTALLDIR = installdirectory;
Console.WriteLine("Adding ePack files");
for (int i = 0; i < aFiles.Length;i++ )
{
Console.WriteLine(aFiles[i]);
ISWiComponent NewComponent = oISProj.AddComponent("Component_"+i);
string string_PathToFile = aFiles[i].Substring(0,aFiles[i].LastIndexOf("\\"));
string string_RelativeToInstallDir = string_PathToFile.Substring(aFiles[i].LastIndexOf(ePackName) + ePackName.Length);
NewComponent.Destination = installdirectory+string_RelativeToInstallDir ;
NewComponent.AddFile(aFiles[i]);
/*----------------------------Fails Here--------------------------------------*/
NewComponent.OverwriteMainOptions=0;
/*----------------------------------------------------------------------------*/
}
oISProj.SaveProject();
oISProj.CloseProject();
Console.WriteLine("Done");
}
static voidMain(string[] args){
ISWiAuto24.ISWiProject oISProj = new ISWiAuto24.ISWiProject();
string ePackName = "ThisMonthsBundle"
string[] aFiles = new[] {#"c:/Foo/Roo/Goo/"+ePackName+"/File0",#"c:/Foo/Roo/Goo/"+ePackName+"/File1",#"c:/Foo/Roo/Goo/"+ePackName+"/File2",#"c:/Foo/Roo/Goo/File3"}
string sProjName = "C:/Foo/Bar.ism"
oISProj.CreateProject(sProjName, ISWiProjectType.eptMsi);
AddFiles(aFiles,oISProj,sProjName);
}
does anyone know a way around this?
the error is: COM Exception was unhandled - This property is not supported for Basic MSI Project. You need to remove the line that calls the property from your automation code.
I found an old forum post back in 2010 on the flexera community forum where a flexera developer responded to a user saying that this can be done like so:
ISWiComponent NewComponent = oISProj.AddComponent("Component_1");
NewComponent.Destination = "[ProgramFilesFolder]" + "ProgramName";
NewComponent.AddFile("c:\File1");
ISWiFiles Files = NewComponent.ISWiFiles;
foreach (ISWiFile File in Files)
{
File.OverrideSystemVersion = true;
File.Version = "65535.0.0.0";
}
the developer in question recognised the need for the automation interface to support the ISWiFile.AlwaysOverwrite property and raised a work order for it. i guess they just havent gotten around to it in the 8 years since
https://community.flexerasoftware.com/showthread.php?194448-installshield-2009-automation-File-property-quot-Always-overwrite-quot
Anyway, The above appears to work
I need to create a set of rules in Microsoft Outlook via C#.
I have found a lot of documentation online, but unfortunately it is not working for me.
I create the rule using the function below:
{
Outlook.Application OutlookApplication = Marshal.GetActiveObject("Outlook.Application") as Outlook.Application;
Outlook.MAPIFolder OutlookInbox = (Outlook.MAPIFolder)OutlookApplication.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
Outlook.Rules rules = null;
try
{
rules = OutlookApplication.Session.DefaultStore.GetRules(); //Gets list of outlook rules
}
catch
{
Debug.WriteLine("Could not obtain rules collection.");
return;
}
string ruleName = "TestRule";
Outlook.Rule rule = rules.Create(ruleName, Outlook.OlRuleType.olRuleReceive); //Creates new rule in collection
rule.Name = ruleName;
//From condition
rule.Conditions.From.Recipients.Add("allixhd#gmail.com");
rule.Conditions.From.Enabled = true;
//Subject condition
rule.Conditions.Subject.Text = new string[] { "#test" };
rule.Conditions.Subject.Enabled = true;
//Move action
Outlook.MAPIFolder ruleFolder = OutlookInbox.Folders["TestFolder"]; //Gets the folder with name TestFolder
rule.Actions.MoveToFolder.Folder = ruleFolder;
rule.Actions.MoveToFolder.Enabled = true;
rule.Enabled = true;
//Save rules
try
{
rules.Save(true);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
The problem I face is that the rule is created successfully in my Outlook instance. I am able to open the Rule window in Outlook and I can see my rule. When I open the rule, all the settings appear correct. However when I run the rule it does not work.
If I manually create an identical rule in Outlook it does work.
I have also found the following:
- Create the rule in Outlook via my C# function
- Open the rule window in Outlook
- Tick and untick a checkbox and save
- The rule runs correctly.
- Note: If I only change the name, rather than unticking and reticking a checkbox, this does not work.
- I tried to replicate this with a hack in the code forcing this behaviour, and the rule did not work.
I wonder if there is some setting I am missing that is applied when you use the rule interface in Outlook?
Any advice would be very welcome.
Thanks
I'd suggest starting from releasing all underlying com objects in the code. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object.
To release all COM objects you need to break the chain of calls and declare the each property and method call on a separate line of code.
OutlookApplication.Application.ActiveExplorer().Session.GetDefaultFolder
There is no need to call the Application property of the Application class. You have already got an instance of the Application class.
Also there is no need to call the ActiveExplorer method of the Application class. You can use the Session property or the GetNamespace method of the Application class. Review the code and release all underlying COM objects.
rules.Save(true);
Do you get any exceptions when calling the Save method?
Anyway, I'd suggest creating a rule manually and then exploring its properties to create the same rule programmatically.
I have solved this question.
The domain of the From email address was in a hierarchy in outlook and so not being recognized correctly. I have included all the email addresses for the user and now the rule works.
I have tried 2 approaches to achieve the end of being able to create and send an Outlook Task, both error out in a way that I am unable to resolve on my own.
I'm having trouble creating an Outlook Task using Microsoft Outlook 14.0 Object Library and the How To from MSDN: http://msdn.microsoft.com/en-us/library/office/ff184639.aspx
The first line of this code creates an Outlook.TaskItem:
Outlook.TaskItem task = Application.CreateItem(
Outlook.OlItemType.olTaskItem) as Outlook.TaskItem;
The "Application.CreateItem" throws an error:
'System.Windows.Forms.Application' does not contain a definition for 'CreateItem'
Instead of System.Window.Forms.Application, I think the class it is looking for is in the Outlook.ApplicationClass, but this doesn't work either.
Hence the second attempt to replace the above code with the code is below to create the TaskItem:
Outlook.ApplicationClass app = new Outlook.ApplicationClass();
Outlook.TaskItem tsk = (Outlook.TaskItem)
app.CreateItem(Outlook.OlItemType.olTaskItem);
The error I get is:
Interop type 'Microsoft.Office.Interop.Outlook.ApplicationClass' cannot be embedded. Use the applicable interface instead.
I'm still learning C# and am not sure how to resolve either of these errors. Any help is much appreciated.
If outlook is already running add the following method in your class:
public static Microsoft.Office.Interop.Outlook.Application GetActiveOutlookApplication()
{
return ( Microsoft.Office.Interop.Outlook.Application )System.Runtime.InteropServices.Marshal.GetActiveObject( "Outlook.Application" );
}
... Then to use it
Outlook.Application app = GetActiveOutlookApplication();
Outlook.TaskItem tsk = (Outlook.TaskItem) app.CreateItem(Outlook.OlItemType.olTaskItem);
... For a new instance of outlook you may be able to try (not sure if this works)
Outlook.Application app = new Outlook.Application();
Outlook.TaskItem tsk = ( Outlook.TaskItem )app.CreateItem( Outlook.OlItemType.olTaskItem );
Back in .NET 1.0 days I wrote a method to return the target of a shortcut on MS Windows. It did this through using an interop to the Windows Script Hosting Object Model and brute forced through the COM interface:
private FileInfo GetFileFromShortcut(FileInfo shortcut)
{
FileInfo targetFile = null;
try
{
IWshRuntimeLibrary.WshShell wShell = new IWshRuntimeLibrary.WshShellClass();
IWshRuntimeLibrary.WshShortcut wShortcut = (IWshRuntimeLibrary.WshShortcut)wShell.CreateShortcut(shortcut.FullName);
// if the file wasn't a shortcut then the TargetPath comes back empty
string targetName = wShortcut.TargetPath;
if (targetName.Length > 0)
{
targetFile = new FileInfo(targetName);
}
}
catch (Exception)
{ // will return a null targetFile if anything goes wrong
}
return targetFile;
}
This still bugs me, and I was looking to replace this with something more elegant, but only if the replacement actually works at least as well. I still can't find a native C# way of finding the target of a shortcut. Is there one, or is this still the best way of doing this type of thing?
It looks like someone has written a class to manipulate shortcut files in C# called ShellLink, but it too uses COM.
Can't you just open the .lnk or .url file and parse it?
This talks about the same thing and shows what the files look like:
http://www.programmingtalk.com/showthread.php?t=7335
I got interested in this as well a while ago.
Here is the accepted response with a link to a (informal) description of the format of LNK files. Apparently, all available methods yet go through some API.