I have an excel addin (*.xla) that contains many complex functions that all take input parameters and return values. I unfortunately cannot create a *.XLL as I don't have access to the *.xla file.
I've managed to use C# to write the excel function into a cell (as a string), calculate the cell, and then retrieve the result back into C#. This method works but it feels very ad hoc and inefficient.
Given the situation described above, is there a better way for calling a custom excel function (that takes parameters) from C#?
How about using the excellent Excel-DNA to build a C# XLL that uses xlfEvaluate to invoke the UDF defined in the .xla? MSDN doc for xlfEvaluate: https://msdn.microsoft.com/en-us/library/office/bb687913.aspx. You can pass in any string that can appear in a worksheet cell. So it shouldn't be too difficult to code some C# to compose the name of the VBA function and some parameters into a string and then pass them to xlfEvaluate.
Related
We are looking to be able to programmatically create an Excel workbook which would call custom code from within a cell. Cells would look something like:
=MyCode(A1:A10)
My first thought was to use VBA, but since the algorithm is proprietary the powers that be want it to be protected. I can put a password on it, but it is well documented (here on StackOverflow) on how to get around such passwords.
My second thought was to create an Excel 2013 Workbook project in Visual Studio, but I haven't found anything useful on how to expose a function in C# so it can be called like I described.
Next I thought about having VBA call the C#, and found instructions at https://msdn.microsoft.com/en-us/library/bb608613.aspx. I followed those instructions to the letter, but when I try to run the VBA code I get an error with the GetManagedClass function: Object Library Feature not Supported.
Are there any good references on how to do something like this?
You're looking for Excel-DNA.
This open-source library allows you to create managed Excel add-ins, and supports making user-defined functions, but also macros, real-time RTD data sources etc.
Creating an Excel UDF in C# is then as simple as:
[ExcelFunction(Description = "My first .NET function")]
public static string SayHello(string name)
{
return "Hello " + name;
}
and you can call from a cell as:
=SayHello("Walter")
For code protection with .NET, you'd need to use an obfuscator - there are a variety of free and paid-for ones available.
I have also tried this sample, with the same error. I found a solution that worked for me.
In the ISheet1.cs file, replace the ISheet1 interface declaration with the following code. This code makes the ISheet1 interface public, and it applies the http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.comvisibleattribute.aspx attribute to make the interface visible to COM.
C#
[System.Runtime.InteropServices.ComVisible(true)]
public interface ISheet1
{
void CreateVstoNamedRange(Microsoft.Office.Interop.Excel.Range range, string name);
}
Full article her: http://www.nullskull.com/q/10059408/c-code-to-set-excel-workbook-macro-enabled-and-to-trust-vba-projects.aspx
I have created a webtest in visual studio to perform a test on a Rest API.I have some code that generates a random serial number that i need to pass into my QueryString parameter is there anyway to do this? I noticed that i can bind xml, csv and a database to it for Dynamic values. Would i have to change my code to wright to a xml file or is it possible to perform a direct call to the method inside the .cs file? C# Langauge.
I want to do something like in the below method but i want the sessionToken.sessionToken() to be the method that was called from the .cs file.
QueryString Parameters
generatedToken=sessionToken.sessionToken()
Write your code within the PreRequest method of a Web Test Request plugin, or call your method from the plugin. One of the last statements of the plugin should write the generated value to a context parameter, with code something like:
e.WebTest.Context["YourContextParameter"] = TheGeneratedValue.ToString();
The value of the query string parameter can then be in one of these styles
{{YourContextParameter}}
or
Some text{{YourContextParameter}}more text
With a little more effort you can pass the context parameter name as a parameter of the plugin.
It can be useful to add diagnostics from the plugin into the log; to showit has been called and to record its output. This can be done with a statement of the form:
e.WebTest.AddCommentToResult("Plugin result is " + TheGeneratedValue.ToString());
Another approach is to convert the entire webtest to a coded test, by using one of the command icons just above the webtest. That produces C# that you can edit as much as you want. However, that conversion is a one-way process. After doing it you cannot use the webtest editor to further change the test. Hence I recommend the plugin route.
I've been looking at the microsoft support page Binding for Office automation servers with Visual C# .NET to try to create an Excel Worksheet, populate it with values in a datatable, and save it to the machine.
I have an implementation that uses early-binding and simply loops through the items, but I don't know how you would achieve this with late-binding, and I need to be able to embed the Interop types to make the application version independent in regard to MS Office.
How would I add the rows from a datatable to a new Excel Worksheet using late-binding?
I would recommend writing an interface and abstracting the data population step, and the excel step. That way you can have a system that implements early binding with excel to do things, and then an engine that uses this interface to populate the excel sheet. Step 2 would be to write a second implementation of the interface using Late Binding rather than early binding. Then you just substitute the second implementation for the first in your code when you create the interface.
In the code, you would only create 1 object, the interface itself. When creating it though, you can assign it as any other class/implementation that implements that interface...here's an example from my own code:
ISpreadsheetControl SSInterface;
if (conditionCheck())
SSInterface = new ExcelImplementer();
else
SSInterface = new OpenOfficeImplementer();
I Only ever use the 1 object, SSInterface, when placing data or changing page settings, etc etc...whatever else I implemented...but it can do so in two different manners based on which Class I assigned to the interface at load time.
As for the specifics and details on "how to"...I find the second example in the link you provided to be very helpful indeed. Its all about Type and Invoke. The difficulty will be keeping track of what you are working with at any given time. That is one of the things that will make it harder to work with, and a good reason to extract the early binding implementation first. That way you can see all the method names you will need and their parameter lists when writing the second.
I also want to add this: The very simple and short answer to your question is "Do it exactly the same way you already are" You just change 'how' you are calling the method that is populating the data...and all the rest of the excel interop implementation along with it.
UPDATE
I think this might do what you are looking for, although its messy enough that I would recommend putting it (both operations actually, one can call the other) into its own separate method, somewhere.
//Get a range object that contains the cell.
Parameters = new Object[2];
Parameters[0] = iRow + 1;
Parameters[1] = iCol;
objRange_Late = objSheet_Late.GetType().InvokeMember( "Cells",
BindingFlags.GetProperty, null, objSheet_Late, Parameters );
//Write value in cell
Parameters = new Object[1];
Parameters[0] = row[col.ColumnName];
objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty,
null, objRange_Late, Parameters );
I have to admit, I don't have an implementation that I can test this on right now, but according to the things I know about it, that should work. If "Cells" doesn't work, I would also the same code with "Range"...I dont actually know if that one takes numerical input or not.
link to Cells property description (msdn)
you might also want to explore that whole system a bit, it can help you find some of the things you might be looking for.
Tested Managed to successfully create and test the above code, it works perfectly.
I have an Excel UDF which takes 2 parameters, I want to utilize Excel built-in Funciton arguments window/dialog, In addition to the standard behavior(ie. you can select cell reference or type in textbox for parameter value), I want to use a dropdownlist for the second parameter, the first parameter has search ability, i.e. when you type in "C", it will pop up a list of availables values starting with "C". I wonder if it is possible to inherit from Excel built-in dialog and how?
If not possible, I have to create custom form to make it work similar to Excel function arguments window. I see A window that behaves both modally and non-modally, maybe that's the way to go? I have not tried yet since I do not quite get what's talked there. thanks
the application is very large so giving a brief back ground and the problem
when the user logs in, a button is displayed having the text of the function he is allowed to call.
the function he is allowed is mapped in the database table
its made sure that the name of the actual function is same to the ones used in the db.
problem
the name is extracted, and stored as text field of button and also in a string variable.
now how am i supposed to call this function using the string variable which has the name stored in it!
like we type
name-of-function();
but here i dont know the name, the string at run time does so i cant write like
string()!!?
You will need to use reflection to do this. Here is a rough sketch of what you need to do:
// Get the Type on which your method resides:
Type t = typeof(SomeType);
// Get the method
MethodInfo m = t.GetMethod("methodNameFromDb");
// Invoke dynamically
m.Invoke(instance, null);
Depending on your actual needs you will have to modify this a little - lookup the used methods and types on MSDN: MethodInfo, Invoke
Well, no matter what you do, there is going to have to be some kind of mapping done between a database "function" and your "real" function. You can probably use Reflection using your Types and MethodInfo.
However, this sounds like a maintenance nightmare. It also sounds like you are reinventing user roles or the like. I would be very cautious about going down this path - I think it will be much more complex and problematic than you think.