I am trying to implement a email functionality using VSTO Outlook AddIn. But
I am getting ComAddIn.Object as always null due to this i am not able to
access the member of VSTO AddIns
Outlook.Application OutlookObj = new Outlook.Application();
object AddinName = "OutlookAddIn";
COMAddIn AddIn = OutlookObj.COMAddIns.Item(ref AddinName);
IOutLookApp utils = (IOutLookApp)AddIn.Object;
utils.CallOlMethod();
This is TheAddIn.cs
namespace OutlookAddIn
{
public interface IOutLookApp
{
void CallOlMethod();
}
public partial class ThisAddIn
{
protected override object RequestComAddInAutomationService()
{
OutlookApp ol = new OutlookApp();
return ol;
}
#region VSTO generated code
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see
https://go.microsoft.com/fwlink/?LinkId=506785
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
public void CreateOutlookItem()
{
Outlook.MailItem newEmail = new Outlook.MailItem
{
To = "example#gmail.com",
Subject = "testing",
Importance = Outlook.OlImportance.olImportanceLow
};
newEmail.Send();
}
}
public class OutlookApp:
StandardOleMarshalObject,
IOutLookApp
{
public void CallOlMethod()
{
Globals.ThisAddIn.CreateOutlookItem();
}
}
}
What I am doing wrong here? though my AddIn class is exposed still the ComAddIn.Object is null, why? Kindly help resolving the issue.
To expose your VSTO add-in to external callers do following steps:
Define interface as dual and make it COM visible
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IOutLookApp
{
void CallOlMethod();
}
Also define a class that implements the interface as shown bellow
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class OutlookApp : StandardOleMarshalObject, IOutLookApp
{
public void CallOlMethod()
{
//do something
}
}
Read more: Call code in VSTO Add-ins from other Office solutions and
VSTO Add-ins, COMAddIns and RequestComAddInAutomationService
Edit:
It is also required to check "Register For Com interop" in project settings and make sure to run Visual Studio as administrator.
Related
I'm writing C++ code that calls C# code. The C# may need to invoke methods back in the C++ code. If both parts were C# I think I would use following mechanism. Please note I pass EventHandler from ShouldBCpp to Csharp instead of registering in ShouldBCpp since ShouldBCpp does not know what csharp points to (& can't change CsharpBase).
public abstract class CsharpBase
{
public abstract void SomeMethodDoingActionInB();
}
public class Csharp : CsharpBase
{
public Csharp(EventHandler f)
{
MySpecialHook += f;
}
public event EventHandler MySpecialHook;
public override void SomeMethodDoingActionInB()
{
if (MySpecialHook != null)
MySpecialHook(this, null);
}
}
public class ShouldBCpp
{
public CsharpBase csharp;
public ShouldBCpp()
{
csharp = new Csharp(NotificationFromClassB); // actually using Activator::CreateInstance
}
public void NotificationFromClassB(object sender, EventArgs e)
{
}
public void Go()
{
csharp.SomeMethodDoingActionInB();
}
}
class Program
{
static void Main(string[] args)
{
ShouldBCpp shouldBCpp = new ShouldBCpp();
shouldBCpp.Go();
}
}
Question is how to write ShouldBCpp in C++/CLI. Bonus points for using delegate :)
Thank you
A simple translation to C++/CLI would look like this:
public ref class IsCppCLI
{
public:
CsharpBase^ csharp;
IsCppCLI()
{
csharp = gcnew Csharp(gcnew EventHandler(this, &IsCppCLI::NotificationFromClassB));
// You didn't show your Activator code,
// but I believe it would translate to C++/CLI as this:
csharp = dynamic_cast<CsharpBase^>(
Activator::CreateInstance(
Csharp::typeid,
gcnew array<Object^> {
gcnew EventHandler(this, &IsCppCLI::NotificationFromClassB)}));
}
void NotificationFromClassB(Object^ sender, EventArgs^ e)
{
}
void Go()
{
csharp->SomeMethodDoingActionInB();
}
}
I'm writing a VSPackage and I need to have menu item with checkbox, just like on this sample image below:
I went through this msdn reference regarding .vsct files, bud didn't fine any information explaining how to do it. What I have now is standard menu item with icon and text (code sample from MyPackage.vsct file):
<Buttons>
<Button guid="guidMyPackageCmdSet" id="cmdidMyPackage" type="Button">
<Icon guid="guidImages" id="myPackageBitmap" />
<CommandFlag>TextChanges</CommandFlag>
<CommandFlag>DontCache</CommandFlag>
<CommandFlag>FixMenuController</CommandFlag>
<Strings>
<ButtonText>MyPackage</ButtonText>
</Strings>
</Button>
</Buttons>
I need this additional checkbox. How to do it?
The properties like Checked, Visible, Enabled or Supported can´t be defined via the VSCT file. You need a command handler that controls the command´s state. I´ve created a base class that wraps the creation of the OleMenuCommand instance and handles the command´s BeforeQueryStatus event. This is a slimmed version of my implementation, but it will give you an idea how to solve it...
internal abstract class CommandHandler : IDisposable
{
private readonly OleMenuCommand command;
protected CommandHandler(Guid group, int id)
{
var commandid = CommandID(group, id);
this.command = new OleMenuCommand(this.Invoke, commandId);
this.command.BeforeQueryStatus += this.OnBeforeQueryStatus;
}
protected virtual void OnExecute() { }
protected virtual void OnQueryStatus(QueryStatusEventArgs e) { }
private void Invoke(object sender, EventArgs e)
{
this.OnExecute();
}
private void OnBeforeQueryStatus(object sender, EventArgs e)
{
OleMenuCommand command;
if ((command = sender as OleMenuCommand) != null)
{
var e = new QueryCommandEventArgs
{
Checked = command.Checked,
}
this.OnQueryStatus(e);
command.Checked = e.Checked;
}
}
public void Dispose()
{
this.command.BeforeQueryStatus -= this.OnBeforeQueryStatus;
}
}
public class QueryCommandEventArgs : EventArgs
{
public bool Checked { get; set; }
}
The CommandHandler class allows to control the state of any menu command. Just derive new handler implementations from it and override the OnExecute and OnQueryStatus methods, like...
internal sealed class MyCommand : CommandHandler
{
private bool checked;
public MyCommand() : base(GuidCmdSet, MyCommandId) { }
protected override void OnExecute()
{
this.checked = !this.checked; // toggle checked state
}
protected override void OnQueryStatus(QueryStatusEventArgs e)
{
e.Checked = this.checked;
}
}
Here is my Error Message which is shown when I browse: ../api/User
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'RavenReader.Web.Controllers.UserController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<StackTrace>
at System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
</Error>
My Controller Classes are
public class BaseController : ApiController
{
private readonly ICookieStorageService _cookieStorageService;
public BaseController(ICookieStorageService cookieStorageService)
{
_cookieStorageService = cookieStorageService;
}
}
public class UserController : BaseController
{
private readonly RavenUserFacade _facade;
private readonly ICookieStorageService _cookieStorageService;
public UserController(ICookieStorageService cookieStorageService, RavenUserFacade facade):base(cookieStorageService)
{
_facade = facade;
}
// GET api/User
public IEnumerable<RavenUserView> Get()
{
var users = _facade.GetAllUser();
return users.RavenUsers;
}
..........................................
..........................................
}
According to http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/ this blog I organized my NinjectDependencyScope class, NinjectDependencyResolver class and NinjectWebCommon as follows:
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
var disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
public static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IDbFactory>().To<IDbFactory>().InSingletonScope();
kernel.Bind<IUnitOfWork>().To<EFUnitOfWork>();
kernel.Bind<IRavenUserRepository>().To<RavenUserRepository>();
kernel.Bind<IRavenUserFacade>().To<RavenUserFacade>();
kernel.Bind<ICookieStorageService>().To<CookieStorageService>();
kernel.Bind<ICacheStorage>().To<HttpContextCacheAdapter>();
}
}
I am using visual Studio 2013 Ninject For MVC-3
I am posting this answer in order to help you track down the root issue you are facing. It is not a solution but this is how I reproduced the exact same error you are having.
First of all, you should use a different implementation for the NinjectDependencyResolver. I've set this gist. The reason behind that is avoiding problem with scopes (specially singletons), which you can learn more about here.
Back to your problem, the error is in your bindings, somewhere. First, try removing the InSingletonScope from your IDbFactory. Then, try removing one dependency from your controller constructor and check if that works. Finally, strip out the base class and see if it works.
These steps are just to guide you track down the problem. I've replicated your scenario here and I couldn't face the same issue. My setup was like this:
public class BaseController : ApiController
{
protected readonly IService _service;
public BaseController(IService service)
{
_service = service;
}
}
public class ValuesController : BaseController
{
public ISomeOtherDependency Dependency { get; set; }
public ValuesController(IService service, ISomeOtherDependency dependency) : base(service)
{
Dependency = dependency;
}
// GET api/values/5
public string Get(int id)
{
return _service.CreatedAt.ToString("u");
}
}
public interface ISomeOtherDependency
{
}
public class ConcreteDependency : ISomeOtherDependency
{
}
public interface IService
{
DateTime CreatedAt { get; }
}
public class Service : IService
{
public Service()
{
CreatedAt = DateTime.Now;
}
public DateTime CreatedAt { get; private set; }
}
And my bindings:
kernel.Bind<IService>().To<Service>(); // If I comment this, I get the same exception.
kernel.Bind<ISomeOtherDependency>().To<ConcreteDependency>();
But by commenting out one of these bindings, I get the exact same error as you:
ValuesController' does not have a default constructor
I hope this gets you on the right track to fix your issue.
Thanks for your reply. I followed each your steps but same results here. Finally I debugged by bindings that belongs inside NinjectWebCommon.cs and I found a problem here. While debugging it shows me following problem:
Locating source for
Bootstrapper.cs not found
You need to find Bootstrapper.cs to view the source for the current call stack frame
'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'. Checksum: MD5 {13 3e b1 f3 ba a7 65 14 f6 dc 4d f1 dd aa 21 bf}
The file 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs' does not exist.
Looking in script documents for 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'...
Looking in the projects for 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'.
The file was not found in a project.
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\crt\src\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\crt\src\vccorlib\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\atlmfc\src\mfc\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\atlmfc\src\atl\'...
Looking in directory 'C:\Program Files\Microsoft Visual Studio 11.0\VC\atlmfc\include'...
The debug source files settings for the active solution indicate that the debugger will not ask the user to find the file: c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs.
The debugger could not locate the source file 'c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs'.
Base user control BaseUserControl.cs
namespace BaseClass
{
public partial class BaseUserControl : UserControl
{
protected ResourceManager _translator = null;
public BaseUserControl()
{
InitializeComponent();
InitTranslation();
}
#if DEBUG
/// <summary>
/// Initialize translation component (ResourceManager)
/// </summary>
protected virtual void InitTranslation()
{
throw new NotImplementedException();
}
#else
public abstract void InitTranslation();
#endif
}
}
Implementation of base user control
namespace BaseClass
{
public class Implemented : BaseUserControl
{
public Implemented() : base()
{
}
protected virtual override void InitTranslation()
{
_translator = null; //null only for int this example otherwise initialize
}
}
}
The issue is that if you try to open Implemented class in the designer it gives an error "The method or operation is not implemented." and preventing that.
The idea was to force the implementaion of InitTraslation() in inherited class.
Stack info:
at BaseClass.BaseUserControl.InitTranslation() in C:\Users\XXX\Documents\Visual Studio 2010\Projects\BaseClass\BaseClass\BaseUserControl.cs:line 55
at BaseClass.BaseUserControl..ctor() in C:\Users\XXX\Documents\Visual Studio 2010\Projects\BaseClass\BaseClass\BaseUserControl.cs:line 22
I have a simple custom work item control that works flawlessly in VS 2013. I recently installed VS 2015 on my Windows 10 box and the control throws an error like so:
TF400939: The custom control type 'TimSheetsControl.WITimeSheetControl' does not implement the IWorkItemControl interface or is compiled for a different version of Visual Studio.
This is frustrating because the control does implement IWorkItemControl Interface. Also compiling to a version of Visual Studio doesn't seem to be a thing, at least as far as I understand it.
I tried to create a very simple control (just a ComboBox on a screen) to do some testing and I got exactly the same error.
I guess I have a couple questions:
Should I be doing this type of custom control in Visual Studio anymore? Or should I be creating web controls to replace what was once done in Visual Studio.
Is there something I'm doing terribly wrong which is causing this to fail?
The very simple control code I created is below, I'm happy to answer questions about my environment if that information is useful.
Thanks for your time and attention.
UserControl Code Behind (WITimeSheetControl):
namespace TimSheetsControl
{
public partial class WITimeSheetControl : UserControl, IWorkItemControl
{
private object WorkItemDataSource;
protected IServiceProvider ServiceProvider = null;
public WITimeSheetControl()
{
InitializeComponent();
}
public StringDictionary Properties{get; set;}
public bool ReadOnly { get; set; }
public object WorkItemDatasource
{
get
{
return WorkItemDataSource;
}
set
{
WorkItemDataSource = value;
}
}
public string WorkItemFieldName { get; set; }
public event EventHandler AfterUpdateDatasource;
public event EventHandler BeforeUpdateDatasource;
public void Clear()
{
}
public void FlushToDatasource()
{
}
public void InvalidateDatasource()
{
if (string.IsNullOrEmpty(WorkItemFieldName))
{
throw new ArgumentNullException("The fieldname property for the WITimeSheetControl is not set.");
}
cmbPosition.SelectedIndex = -1;
}
public void SetSite(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
}
}
UserControl Designer Code:
namespace TimSheetsControl
{
partial class WITimeSheetControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.cmbPosition = new System.Windows.Forms.ComboBox();
this.SuspendLayout();
//
// cmbPosition
//
this.cmbPosition.DropDownWidth = 145;
this.cmbPosition.FormattingEnabled = true;
this.cmbPosition.Items.AddRange(new object[] {
"Business Analyst",
"Programmer"});
this.cmbPosition.Location = new System.Drawing.Point(139, 23);
this.cmbPosition.MaximumSize = new System.Drawing.Size(165, 0);
this.cmbPosition.Name = "cmbPosition";
this.cmbPosition.Size = new System.Drawing.Size(151, 21);
this.cmbPosition.TabIndex = 0;
//
// WITimeSheetControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.cmbPosition);
this.Name = "WITimeSheetControl";
this.Size = new System.Drawing.Size(1219, 565);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ComboBox cmbPosition;
}
}
wicc:
<?xml version="1.0" encoding="utf-8" ?>
<CustomControl xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Assembly>TimSheetsControl.dll</Assembly>
<FullClassName>TimSheetsControl.WITimeSheetControl</FullClassName>
</CustomControl>
You need to compile a version of your custom control that targets the TFS 2015 binaries in order for your control to load in VS 2015.