I am using excel-dna as base function, then I call a "vsto" function from an addin to trigger a web service request on the selected function. My issue is that I d like to use the DNA function to parse the ranges to be send to the service. It return a string currently ("waiting for service call..."), and if the VSTO methods call the function it passed another variable to return something else.
I cannot extract other thing than string, object comes back empty when I use "evaluate" in vsto.
I think the best way would be to reach a global cache variable stored in the vsto addin from the excel-dna function. I could not manage to to this.
Addins button push => addins evaluate Excel DNA => DNA store data in VSTO Addin variable => VSTO call the service and paste the returning data.
Thank you,
Ok I found out on:
MSN Blog
namespace AddIn{
[ComVisible(true)]
[Guid("****************************")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAddinUtilities
{ void youraddinfunction();
}
[ClassInterface(ClassInterfaceType.None)]
public partial class ThisAddIn : IAddinUtilities
{
protected override object RequestComAddInAutomationService()
{ return this; }
public void yourfunction (){ DoSomething }
}
In the excel Dna function :
var application = (Application)XL.ExcelDnaUtil.Application;
var addin = application.COMAddIns.Item(AddinName);
var what = addin.Object;
what.youraddinfunction;
Yoyo's approach is strictly speaking correct, but for an approach that is more portable, I suggest combining ExcelDNA with NetOffice. Here is a snippet to get you started. Note that you will need to cleanup your Application references to COM proxy objects in the OnDisconnection method. For more details, check out Excel Addin Portability Tutorial
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ProgId("Sample.MyAddIn")]
public class MyRibbon : ExcelRibbon
{
public override void OnConnection(object comApp, ext_ConnectMode ConnectMode, object objAddin, ref Array custom)
{
// glue NetOffice + Excel DNA
m_ExcelApplication = new Application(null, m_ComApplication);
// other initialization...
}
}
Related
I had code like this working with Haxe 3:
macro public static function get(key:String)
{
return Context.makeExpr(Context.definedValue(key), Context.currentPos());
}
However, after migrating to Haxe 4 this fails to compile with error:
Uncaught exception macro-in-macro
How should I go about migrating this function to Haxe 4? Is there a better way to access build flags in order to avoid this issue?
As #Gama11 alluded to, there's not actually a problem with your macro function, there's a problem with where you're calling it from. (Haxe 4 may have gotten more strict with these checks.)
If you have:
Main.hx
class Main
{
public static function main()
{
// Can call get from here:
var cvar = MacroUtil.get('cvar');
MacroUtil.some_macro_function();
trace('Hello world! cvar=${ cvar }');
}
}
MacroUtil.hx
import haxe.macro.Context;
import haxe.macro.Expr;
class MacroUtil
{
macro public static function get(key:String):Expr
{
return Context.makeExpr(Context.definedValue(key), Context.currentPos());
}
macro public static function some_macro_function()
{
// Cannot call get from here:
var cvar:Expr = get('cvar');
trace('will trace at compile time, and cvar is ${ cvar }');
return macro trace('will trace at runtime');
}
}
And execute it with: haxe -x Main -D cvar=abc
That will generate the error you're experiencing. It's because in some_macro_function, you're already in the macro context, so you can't call the macro function get from there.
There are a couple ways of dealing with this.
One Approach
You can use #if macro / if !macro to detect the macro context and adjust accordingly. So as silly as this looks, it does indeed solve your particular problem:
class MacroUtil
{
#if !macro macro #end public static function get(key:String):Expr
{
This function signature says, if I'm already in the macro context, don't consider this function a macro function. It's just a static helper at that point. And remember that it returns an Expr, not a String like it does in the main context.
If you mix macro and non-macro functions in a single file, you may also find yourself needing to use #if macro to avoid this condition as well.
Another Approach
You can refactor your macro functions into macro functions and macro helpers. It's a little more verbose, but maybe a little more clear as to what's happening:
MacroUtil.hx
import haxe.macro.Context;
import haxe.macro.Expr;
class MacroUtil
{
macro public static function get(key:String):Expr
{
return Context.makeExpr(MacroHelpers.get_define(key), Context.currentPos());
}
macro public static function some_macro_function()
{
// Cannot call get from here:
var cvar:String = MacroHelpers.get_define('cvar');
trace('will trace at compile time, and cvar is ${ cvar }');
return macro trace('will trace at runtime');
}
}
class MacroHelpers
{
public static function get_define(key:String):String
{
return Context.definedValue(key);
}
}
If you do it this way, then your macro functions all call the MacroHelpers, and non-macro function call the MacroUtils. Notice the helper returns a String, and it's up to the call-site to then convert it to an expression, if that's what they want.
We ended up removing this whole get method and switching occurrences to use Compiler.getDefine() instead, which is supported both by Haxe 3 and 4.
I believe the problem we were facing was related with the fact that this static macro get was being called from our test runner script, so that probably was the place where a macro was calling another macro. Still, I tried to put the solution suggested by Jeff Ward in place but kept getting the same result.
I'm working with the revit api, and one of its problems is that it locks the .dll once the command's run. You have to exit revit before the command can be rebuilt, very time consuming.
After some research, I came across this post on GitHub, that streams the command .dll into memory, thus hiding it from Revit. Letting you rebuild the VS project as much as you like.
The AutoReload Class impliments the revit IExteneralCommand Class which is the link into the Revit Program.
But the AutoReload class hides the actual source DLL from revit. So revit can't lock the DLL and lets one rebuilt the source file.
Only problem is I cant figure out how to implement it, and have revit execute the command. I guess my C# general knowledge is still too limited.
I created an entry in the RevitAddin.addin manifest that points to the AutoReload Method command, but nothing happens.
I've tried to follow all the comments in the posted code, but nothing seems to work; and no luck finding a contact for the developer.
Found at: https://gist.github.com/6084730.git
using System;
namespace Mine
{
// helper class
public class PluginData
{
public DateTime _creation_time;
public Autodesk.Revit.UI.IExternalCommand _instance;
public PluginData(Autodesk.Revit.UI.IExternalCommand instance)
{
_instance = instance;
}
}
//
// Base class for auto-reloading external commands that reside in other dll's
// (that Revit never knows about, and therefore cannot lock)
//
public class AutoReload : Autodesk.Revit.UI.IExternalCommand
{
// keep a static dictionary of loaded modules (so the data persists between calls to Execute)
static System.Collections.Generic.Dictionary<string, PluginData> _dictionary;
String _path; // to the dll
String _class_full_name;
public AutoReload(String path, String class_full_name)
{
if (_dictionary == null)
{
_dictionary = new System.Collections.Generic.Dictionary<string, PluginData>();
}
if (!_dictionary.ContainsKey(class_full_name))
{
PluginData data = new PluginData(null);
_dictionary.Add(class_full_name, data);
}
_path = path;
_class_full_name = class_full_name;
}
public Autodesk.Revit.UI.Result Execute(
Autodesk.Revit.UI.ExternalCommandData commandData,
ref string message,
Autodesk.Revit.DB.ElementSet elements)
{
PluginData data = _dictionary[_class_full_name];
DateTime creation_time = new System.IO.FileInfo(_path).LastWriteTime;
if (creation_time.CompareTo(data._creation_time) > 0)
{
// dll file has been modified, or this is the first time we execute this command.
data._creation_time = creation_time;
byte[] assembly_bytes = System.IO.File.ReadAllBytes(_path);
System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assembly_bytes);
foreach (Type type in assembly.GetTypes())
{
if (type.IsClass && type.FullName == _class_full_name)
{
data._instance = Activator.CreateInstance(type) as Autodesk.Revit.UI.IExternalCommand;
break;
}
}
}
// now actually call the command
return data._instance.Execute(commandData, ref message, elements);
}
}
//
// Derive a class from AutoReload for every auto-reloadable command. Hardcode the path
// to the dll and the full name of the IExternalCommand class in the constructor of the base class.
//
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class AutoReloadExample : AutoReload
{
public AutoReloadExample()
: base("C:\\revit2014plugins\\ExampleCommand.dll", "Mine.ExampleCommand")
{
}
}
}
There is an easier approach: Add-in Manager
Go to Revit Developer Center and download the Revit SDK, unzip/install it, the check at \Revit 2016 SDK\Add-In Manager folder. With this tool you can load/reload DLLs without having to modify your code.
There is also some additional information at this blog post.
this is how you can use the above code:
Create a new VS class project; name it anything (eg. AutoLoad)
Copy&Paste the above code in-between the namespace region
reference revitapi.dll & revitapiui.dll
Scroll down to AutoReloadExample class and replace the path to point
your dll
Replace "Mine.ExampleCommand" with your plugins namespace.mainclass
Build the solution
Create an .addin manifest to point this new loader (eg.
AutoLoad.dll)
your .addin should include "FullClassName" AutoLoad.AutoReloadExample
This method uses reflection to create an instance of your plugin and prevent Revit to lock your dll file! You can add more of your commands just by adding new classes like AutoReloadExample and point them with seperate .addin files.
Cheers
My PLUGIN is firing on Entity A and in my code I am invoking a web service that returns an XML file with some attributes (attr1,attr2,attr3 etc ...) for Entity B including GUID.
I need to update Entity B using the attributes I received from the web service.
Can I use Service Context Class (SaveChanges) or what is the best way to accomplish my task please?
I would appreciate it if you provide an example.
There is no reason you need to use a service context in this instance. Here is basic example of how I would solve this requirement. You'll obviously need to update this code to use the appropriate entities, implement your external web service call, and handle the field updates. In addition, this does not have any error checking or handling as should be included for production code.
I made an assumption you were using the early-bound entity classes, if not you'll need to update the code to use the generic Entity().
class UpdateAnotherEntity : IPlugin
{
private const string TARGET = "Target";
public void Execute(IServiceProvider serviceProvider)
{
//PluginSetup is an abstraction from: http://nicknow.net/dynamics-crm-2011-abstracting-plugin-setup/
var p = new PluginSetup(serviceProvider);
var target = ((Entity) p.Context.InputParameters[TARGET]).ToEntity<Account>();
var updateEntityAndXml = GetRelatedRecordAndXml(target);
var relatedContactEntity =
p.Service.Retrieve(Contact.EntityLogicalName, updateEntityAndXml.Item1, new ColumnSet(true)).ToEntity<Contact>();
UpdateContactEntityWithXml(relatedContactEntity, updateEntityAndXml.Item2);
p.Service.Update(relatedContactEntity);
}
private static void UpdateContactEntityWithXml(Contact relatedEntity, XmlDocument xmlDocument)
{
throw new NotImplementedException("UpdateContactEntityWithXml");
}
private static Tuple<Guid, XmlDocument> GetRelatedRecordAndXml(Account target)
{
throw new NotImplementedException("GetRelatedRecordAndXml");
}
}
I have the current method example:
public void MethodName(string param1,int param2)
{
object[] obj = new object[] { (object) param1, (object) param2 };
//Code to that uses this array to invoke dynamic methods
}
Is there a dynamic way (I am guessing using reflection) that will get the current executing method parameter values and place them in a object array? I have read that you can get parameter information using MethodBase and MethodInfo but those only have information about the parameter and not the value it self which is what I need.
So for example if I pass "test" and 1 as method parameters without coding for the specific parameters can I get a object array with two indexes { "test", 1 }?
I would really like to not have to use a third party API, but if it has source code for that API then I will accept that as an answer as long as its not a huge API and there is no simple way to do it without this API.
I am sure there must be a way, maybe using the stack, who knows. You guys are the experts and that is why I come here.
Thank you in advance, I can't wait to see how this is done.
EDIT
It may not be clear so here some extra information. This code example is just that, an example to show what I want. It would be to bloated and big to show the actual code where it is needed but the question is how to get the array without manually creating one. I need to some how get the values and place them in a array without coding the specific parameters.
Using reflection you can extract the parameters name and metadata but not the actual values :
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.testMethod("abcd", 1);
Console.ReadLine();
}
public void testMethod(string a, int b)
{
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
StackFrame sf = st.GetFrame(0);
ParameterInfo[] pis = sf.GetMethod().GetParameters();
foreach (ParameterInfo pi in pis)
{
Console.Out.WriteLine(pi.Name);
}
}
}
I'm trying to re-use some of the model configurations on several entities that implements a interface.
Check this code:
public static void ConfigureAsAuditable<T>(this EntityTypeConfiguration<T> thisRef)
where T : class, IAuditable
{
thisRef.Property(x => x.CreatedOn)
.HasColumnName("utctimestamp")
.IsRequired();
thisRef.Property(x => x.LastUpdate)
.HasColumnName("utclastchanged")
.IsRequired();
} // ConfigureAsAuditable
as you can see I'm trying to call the extension method "ConfigureAsAuditable" on my onmodelcreating method like this:
EntityTypeConfiguration<Account> conf = null;
conf = modelBuilder.Entity<Account>();
conf.ToTable("dbo.taccount");
conf.ConfigureAsAuditable();
When debugging i get this exception:
The property 'CreatedOn' is not a declared property on type
'Account'. Verify that the property has not been explicitly excluded
from the model by using the Ignore method or NotMappedAttribute data
annotation. Make sure that it is a valid primitive property.
Thanks in advance :)
PD:
I'm using EF 5-rc, VS 2011 and .NET Framework 4.5
I think a better approach would be to implement your own derived version of EntityTypeConfiguration. For example:
public class MyAuditableConfigurationEntityType<T> : EntityTypeConfiguration<T>
where T : class, IAuditable{
public bool IsAuditable{get;set;}
}
Then, when building your model, use that new type:
var accountConfiguration = new MyAuditableConfigurationEntityType<Account>();
accountConfiguration.IsAuditable = true; // or whatever you need to set
accountConfiguration.(HasKey/Ignore/ToTable/Whatever)
modelBuilder.Configurations.Add(accountConfiguration);