I am developing Add-in for Excel 2013 and I have created a function in Excel Add-In as below
public string ExcelReturnString()
{
return "This is the string: hi";
}
I have used below code to call the function, but it throws an error.
Application.Run(ExcelReturnString)
How can I call the Add-in function in macro?
This is about the farthest thing from straight-forward, but this is how you accomplish the task. I'm going to be as explicit as possible, because the first two or three times I tried to do this, I missed a LOT.
First, when you create the class that hosts ExcelReturnString(), you need to decorate the class with an interface that has the following attributes and then also tag the attributes for each method you want to expose. I made the add-in class "TestExcelAddIn" for the sake of this example:
using System.Data;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
namespace TestExcelAddIn
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IStringGetter
{
string ExcelReturnString();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class StringGetter : IStringGetter
{
public string ExcelReturnString()
{
return "This is the string: hi";
}
}
}
Then, in the main class, associated with "Excel" in your project, you have to override RequestComAddInAutomationService in the following manner. Again, I am including EVERYTHING so you know which class is which (I didn't when I first read it).
namespace TestExcelAddIn
{
public partial class ExcelTest
{
private StringGetter myAddIn;
protected override object RequestComAddInAutomationService()
{
if (myAddIn == null)
myAddIn = new StringGetter();
return myAddIn;
}
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO generated code
#endregion
}
}
Now VBA is ready to consume this method in the following manner:
Sub Test()
Dim addin As Office.COMAddIn
Dim automationObject As Object
Dim returnString As String
Set addin = Application.COMAddIns("TestExcelAddIn")
Set automationObject = addin.Object
returnString = automationObject.ExcelReturnString
End Sub
You could have given me 100 years to figure this out, and I would not have. Actually credit MSDN for the Rosetta stone on it:
https://msdn.microsoft.com/en-us/library/bb608621.aspx?f=255&MSPPError=-2147217396
In addition to DaveMac's note above, also keep in mind a couple of points when calling another routine:
If you're calling a macro from a routine that resides in the same workbook/addin as that routine, you don't have to use Application.Run. You can just call it by using its name:
MyMacro
If you're calling a macro that is in a different workbook, then you do need to use Application.Run, but you will also want to use the workbook name where the macro resides, otherwise VBA will not know where it should look for the macro:
Application.Run "'My Fancy Spreadsheet.xlsm!'MyMacro"
Your code appears to be java.
Excel uses Visual basic, for example.
Function excelreturnstring()
excelreturnstring = "this is the string: hi"
End function
Related
I am programming an application that checks some data in a DB (the DB continuously updated).
For getting the data from the DB I am using an assembley (.dll file) programmed by another team (I can't get/change the code of the .dll file).
I want to "stress test" my algorithem/porgram with my own data (extreme data), I can't change the DB.
a simplified code example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//timer1.Interval = 10000
private void timer1_Tick(object sender, EventArgs e)
{
DataTable values = someLib.GetData(DateTime.Now.AddDays(-1),DateTime.Now);
CheckData(values); //checking the data form the DB, I want to "stress test" this function/logic.
}
}
I want someLib.GetData function to return a specific data (ment to check my program).
I can write a new function that returns the same DataTable like someLib.GetData (same colums etc.) but with my own data, the problem is that this solution requires to manually check all the occurrences of GetData (and more functions that take data from the DB) and change them manually.
I am searching for some systematic way for approaching this.
Another way I thought of is to just delete the reference and "repair" all the errors, the problem is there is a lot of functions I am using in the aforementioned library that I am still in need of.
My qustion is, is there any way to override/disable a function/s (or even whole classes) from an assembly I dont have the code of?
Thank you.
EDIT: the method/s are not virtual.
What about this solution (if I understand the problem correctly):
public class MyLib {
public SomeLib someLib { get; set; }
public MyLib (SomeLib someLib) {
this.someLib = someLib;
}
public void methodFromSomeLibWhichIsRequired(...) {
return someLib.methodFromSomeLibWhichIsRequired(...);
}
// ... so on for any used methods of SomeLib
public DataTable getData() {
// my own implementation of method of SomeLib
}
}
Than all that you need is change the declaration of your SomeLib instance to MyLib instance, i.e. instead of
SomeLib someLib = new SomeLib();
use this
MyLib someLib = new MyLib(new SomeLib());
So you don't need to change the name of someLib everywhere and you just implement those methods in your MyLib which you need from SomeLib.
I am developing a 2D game in MonoGame with Visual Studio 2013. Due to the ease of implementation, I also choose to implement the editor as a static class that contains ALL the editor functionality (key/mouse events, draw calls, other logic). I used Windows Forms as it was quite easy to do and I do not care much for performance for this task.
The way it works is that the Editor instances a form with the editor controls and that allows me to perform operations directly to the game data in memory for each draw layer, such as adding/moving/removing tiles or other elements. I found it quite convenient and it works fine so far with only a minimal amount of code brought to the main game/rendering loop. At the same time, I am able to view and work on the game window directly.
To exclude the editor at any point, all I need to do is to delete the folder from the project that contains the Editor class along with any referenced classes and comment-out a few lines of code, giving me the clean version of the game.
However, I recently discovered I need to add more logic to the draw loop, the first issue being I need to visually indicate the selected tiles with a rectangle border around. This would be easy to do if I would interfere with the main game draw logic (the Renderer class), but I certainly do not want to keep the code there because it may get complex.
I could come over the drawn result (see below code, at the Draw override) and paint over, but that would force me to re-use a part of the rendering code in the editor. Also, that would loop again over all tiles and logic and I find that inefficient.
The best way I thought about implementing this is to call Editor.DrawLayer() from the game's DrawLayer() 's own method if it exists. If it does not exist, do nothing. This way I would not need to remove anything else from the code, just delete the Editor class.
namespace Main
{
public class Main : Game
{
...
public Main()
{
...
}
protected override void Initialize()
{
...
Editor.Initialize(); // TODO remove these on publish
}
protected override void LoadContent()
{
...
Editor.LoadContent(); // TODO remove these on publish
}
protected override void UnloadContent()
{
...
Editor.Unload(); // TODO remove these on publish
}
protected override void Update(GameTime gameTime)
{
Editor.Update(); // TODO remove these on publish
...
Renderer.Instance.Update(gameTime);
...
}
protected override void Draw(GameTime gameTime)
{
Renderer.Instance.Draw(spriteBatch, gameTime);
...
// Editor.Draw(); // I would avoid this
}
}
}
I am able to recognize if the Editor class exists by using this method:
private static void GetAssemblies()
{
Assembly projectAssemblies = Assembly.GetExecutingAssembly();
namespaceList = new List<string>();
foreach (Type type in projectAssemblies.GetTypes())
{
namespaceList.Add(type.FullName);
}
}
public void TryStartingEditor()
{
if (namespaceList.IndexOf("Main.Editor") > -1)
{
Config.EditorExists = true;
}
}
However, I cannot add any code that would survive the Editor class removal as any namespace such as:
Editor.whatever();
would not be legal any more.
My main question is: What would be a good way of calling this class's methods that may not exist at a later point in time without the compiler going crazy?
I am open for any OTHER suggestion that would allow me to implement the editor as less-intrusive as possible relative to the main game loop.
Note. I know that removing a class is a simple matter of also deleting all pieces of code that reference it and that's not a big deal, maybe 5 minutes when the project is done, so know I am not determined to use this method, I am curious if it can be done with ease.
Later edit. I believe I can summarize the problem simply by showing these two scenarios. I would like scenario 2 to be possible somehow.
Scenario 1. Editor class exists
public static class Editor {
... everything about editor
}
public function AnyFunctionAnywhere() {
...
if (EditorExists) {
// Ok, we run this, class exists, no problem.
Editor.callSomeMethod();
}
....
}
Scenario 2. Editor class is suddenly missing and we don't necessarily want to remove all calls to it.
public function AnyFunctionAnywhere() {
...
if (EditorExists) {
// Somehow don't throw "The name 'Editor' does not exist in the current context".
Editor.callSomeMethod();
}
...
}
Thank you kindly and let me know if I should explain more clearly any aspects.
I believe I found a good solution using System.Reflection. I created a new singleton class that handles calling in the manner I wanted and it seems to work fine. Here it is below.
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Main
{
public class LocalSystem
{
// Use this to store the list of classes/methods. bool is redundant
public static Dictionary<Tuple<string, string>, bool> classMethods = new Dictionary<Tuple<string, string>, bool>();
// Singleton
private static LocalSystem instance;
public static LocalSystem Instance
{
get
{
if (instance == null)
{
GetAssemblies(); // We do this once. I suspect this to be slow.
instance = new LocalSystem();
}
return instance;
}
}
// Editor specific callers
public void InvokeEditorMethod(string methodName) // Call function
{
invokeClassMethod("Main.Editor", methodName, null);
}
public void InvokeEditorMethod(string methodName, params object[] values) // Call function with some arguments
{
invokeClassMethod("Main.Editor", methodName, values);
}
// This tries to invoke the class.method
private void invokeClassMethod(string className, string methodName, params object[] values)
{
if (!ClassHasMethod(className, methodName)) // We check if the class name and method exist. If not, we bail out.
return;
try
{
Type.GetType(className).GetMethod(methodName).Invoke(null, values);
}
catch(Exception e)
{
if (e is TargetParameterCountException) // This error might be more common than others
{
throw new Exception("Wrong number of parameters provided for method " + methodName + " within " + className);
}
throw; // Something else went wrong
}
}
private static void GetAssemblies()
{
Assembly asm = Assembly.GetExecutingAssembly();
foreach (Type type in asm.GetTypes())
{
string discoveredClass = type.FullName;
foreach (MethodInfo method in Type.GetType(discoveredClass).GetMethods())
{
if (!classMethods.ContainsKey(new Tuple<string, string>(discoveredClass, method.Name)))
classMethods.Add(new Tuple<string, string>(discoveredClass, method.Name), true);
}
}
}
private static bool ClassHasMethod(string className, string methodName)
{
return classMethods.ContainsKey(new Tuple<string, string>(className, methodName));
}
}
}
Usage:
LocalSystem.Instance.InvokeEditorMethod("Initialize");
or
LocalSystem.Instance.InvokeEditorMethod("MethodWithParams", 1, "foo");
Notes.
I haven't covered returning values from invoking functions. Tried for a few minutes but it seems a bit more complicated than I am willing to invest time for. Considering my working model, I should never expect a return value. If I would, it would mean I am moving the editor logic to where it isn't supposed to be, therefore I abandoned this aspect.
You will notice that the exposed methods use the "Main.Editor" class. This is particular for my needs, but if you need to handle multiple arbitrary classes, you can expose a more broad implementation of invokeClassMethod.
Thanks!
I have a class
public class ApplicationClass
{
public ApplicationClass()
{
// Some code here
public bool Check()
{
// some code here
}
}
}
I am calling the Check function in a click event
protected void CheckFunction_Click(object sender, EventArgs e)
{
new ApplicationClass().Check();
}
Now in the ApplicationClass constructor I want to get the info about the name of the function which is called and parameters if any i.e the Check function.
How can I get these details ?
I want to save all the functions that are being called. Instead of placing the call to function at every function can I have it at one place?
It need not be inside a constructor necessarily.
This is not possible. Maybe it looks like it is because of the notation. This is what your code expands to:
protected void CheckFunction_Click(object sender, EventArgs e)
{
var temp = new ApplicationClass();
temp.Check();
}
If you just want to call a method of class without needing an instance, you might want to use a static method - at least your example looks like it. Of course initialization must be done elsewhere or in a static constructor. A static constructor is invoked only once though!
public static bool Check()
{
// some code here
}
ApplicationClass.Check();
If you want information about the methods invoking the current method you may use.
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
Please note that fetching the stack trace can be considered slow, it should not be used in a loop or performance critical code.
That is not possible. If it was the other way around, you could have used the StackTrace class to check what was called, but as said, that is not the case now. (If you had called Check first, it would have appeared on the stack then)
You could opt to use Expression or LamdbaExpression class to retrieve information of the call.
See the question and answers from Get the name of a method using an expression to get an idea how Expressions might be handy.
I've been working on a simple dll library that is com-accessible so that other softwares can use our library (from any managed or unmanaged language).
Creating a com-accessible dll is fairy easy:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MyNamespace
{
//This interface defines purely the events. DotNetEventSender should implement this interface with the ComSourceInterfaces() attribute
//to become an Event Source.
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface COMEventsInterface
{
//[DispId(1)]
// we don't have any events, but if needed, include them here
}
[ComVisible(true)]
public interface ICOM
{
//Methods
int Sum(int[] intsToSum)
}
//Identifies this interfaces that are exposed as COM event sources for the attributed class.
[ComSourceInterfaces(typeof(COMEventsInterface))]
//Tells the compiler not to generate an interface automatically and that we are implementing our own interface (IDotNetEventSender)
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class COM : ICOM
{
// Methods
public int Sum(int[] intsToSum)
{
int sum = 0;
foreach ( int i in intsToSum )
{
sum += i;
}
return sum;
}
}
}
In debug mode in would now mark this project to register for com-interop via Project>Properties>Build>Register for com interop.
In release mode I have an installer which marks the primary output from my project as "vsdrpCOM".
And this works great, in most cases. But somehow on some machines (all American) this won't work. The com class gets registered but I constantly get the error: HRESULT 0x80131534, which is actually already descibed here on SO: Error when instantiating .NET/COM interop class via classic ASP
But realy, I don't see any solution here. I've checked for user rights, domain rights, ...
EDIT:
The constructor of my real class does this one thing:
(I've added the try catch because I found on SO that this is an error in the constructor...)
// Constructor
public COM()
{
try
{
// register itself with the application
MyApplication.COMObject = this;
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
It just registers itself to a static class' property COMObject:
private static COM _comObject;
public static COM COMObject
{
get
{
return _comObject;
}
set
{
_comObject = value;
}
}
Although, the COM class doesn't really need to register itself, i've done this for future use if I would like to trigger Events
Well, I happens to be that i have faulty declared a DateTime in one of my declarations of a static class... private DateTime myDateTime = Convert.ToDateTime("15/09/2013 12:00:00");
And ofcourse, on a EU system, this will work, but on an American (or even others) this gives an error because there is no 15th month...
This gets triggered even before the constructor of my com-accessible class and that's why the error couldn't be handled.
Dumb mistake, but proves that sometimes errors look very complex while they are very simple.
I have created a wrapper class to access PDF FORMS using PDFBox , by using the wrapper I m trying to execute it with VBScript..
Here is my wrapper class (Class Library) with COM enabled
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.util;
using org.apache.pdfbox.pdmodel.interactive.form;
namespace PDF.API
{
public class PDFDocument
{
private PDDocument PD;
public void load(string PDFPath)
{
PD = PDDocument.load(PDFPath);
}
public PDDocumentCatalog getDocumentCatalog()
{
return PD.getDocumentCatalog();
}
public void save(string PDF_Path)
{
PD.save(PDF_Path);
}
public void close()
{
PD.close();
}
}
here is my vbscript
Set TestPDF = CreateObject("PDF.API.PDFDocument")
Set test = PDFDocument.load("D:\\PDF_FORMS\\sample_form.pdf")
Set PDDocumentCatalog = test.getDocumentCatalog()
Set PDAcroForm = PDDocumentCatalog.getAcroForm()
Set PDFField = PDAcroForm.getField("Forenames")
PDField.setValue("VBSCRIPT")
test.save("D:\\PDF_FORMS\\a.pdf")
test.close()
Now it throws me Object required for PDDocument
could not able to resolve this issue
can any one help me out please
Thanks
As Ansgar Wiechers and Aphoria already mention, your Load is a method of your PDFDocument class, and to simplify yourself, you may use the same name as variable name in your .vbs, i.e.:
Set PDFDocument = CreateObject("PDF.API.PDFDocument")
Next issue I see, is that your Load method is a void (not return value), so the syntax should been like this:
PDFDocument.load "D:\path\to\file_a.pdf"
Set PDDocumentCatalog = PDFDocument.getDocumentCatalog()
' ... '
PDFDocument.save "D:\path\to\file_b.pdf"
PDFDocument.close
And I not touched C# recently, but as far as I remember you need a Constructor.
namespace PDF.API
{
public class PDFDocument
{
private PDDocument PD;
public PDFDocument()
{ //class constructor
}
public void load(string PDFPath)
{
PD = PDDocument.load(PDFPath);
}
// ...
}
}
I think you need to change PDFDocument.load... to TestPDF.load....
Set TestPDF = CreateObject("PDF.API.PDFDocument")
Set test = TestPDF.load("D:\\PDF_FORMS\\sample_form.pdf")
Set TestPDF = CreateObject("PDF.API.PDFDocument")
Set test = PDDocument.load("D:\\PDF_FORMS\\sample_form.pdf")
You're using PDDocument without instantiating it first. You probably meant to do this:
Set test = TestPDF.load("D:\\PDF_FORMS\\sample_form.pdf")
As a side note: I'd recommend to escape backslashes inside your class. In VBScript it's usually not required to escape backslashes in paths (WMI notwithstanding), so it may confuse your users if you handle this differently.