.add(true) what does a "true" parameter/argument mean - c#

I have just started learning C# and use Visual Studio to write programs. After a lot of searching via internet and my C# book...and asking other experienced programmers...nothing to answer the following question: What does the parameter/argument "true" in the add() method mean in the following lines of code:
var excel = new microsoft.office.interop.excel.application();
var workbook = excel.workbooks.add(true**);
the add() argument usually has nothing in the parenthesis or maybe 1 or 2 to indicate the number of workbooks to open...but "true"? Thanks

Here is the documentation for the C# VSTO Workbooks.Add(...): https://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.workbooks.add.aspx and here is the documentation for the VBA version: https://msdn.microsoft.com/en-us/vba/excel-vba/articles/workbooks-add-method-excel
Office's COM automation APIs for VSTO definitely need some work for C# ergonomics. The problem is that the method accepts a COM Variant value (System.Object in .NET) argument value, which means it will accept anything you throw at it and handle it internally without any compile-time type safety. This is a poor API design, instead it should have typed overloads instead ("overloads" are different methods/functions with the same name, but strongly-typed parameters). But there's no point me complaining about it now :D
Further confounding things, the conversion from your Boolean true value to a COM Variant object is done entirely behind-the-scenes. But first, let's consider the documented, valid argument values:
Optional Object. Determines how the new workbook is created. If this argument is a string specifying the name of an existing Microsoft Excel file, the new workbook is created with the specified file as a template. If this argument is a constant, the new workbook contains a single sheet of the specified type. Can be one of the following XlWBATemplate constants: xlWBATChart, xlWBATExcel4IntlMacroSheet, xlWBATExcel4MacroSheet, or xlWBATWorksheet. If this argument is omitted, Microsoft Excel creates a new workbook with a number of blank sheets (the number of sheets is set by the SheetsInNewWorkbook property).
...that's a lot to consider!
We can derive what the overloads would be and then document them separately:
workbook.Add() - As the parameter is optional, it means you can call it without any arguments. The effect is creating a new workbook with a number of blank sheets (where the number comes from SheetsInNewWorkbook).
workbook.Add( String templateFileName ) - If the argument is a string, then it's treated as a filename to a template file to use. Obviously this is not marshalable to a Boolean value so this is not happening in your case.
workbook.Add( Int32 constant ) - The documentation uses the term "constant" which I believe really means an Int32 value. It only accepts the values from XlWBATemplate which are defined here: https://msdn.microsoft.com/en-us/vba/excel-vba/articles/xlwbatemplate-enumeration-excel - those values are -4109, 4, 3 and -4167.
The documentation does not say what happens if the argument value is none of those. The fact it seems to work in your case suggests the value passed as a COM Variant containing the bool and it is simply ignored. I don't believe the runtime would marshal the Boolean to an Int32, given Variant supports boolean values, and even if it were marshaled to an Int32 then you'd likely get an argument error as 1 is not defined in XlWBATemplate.
Solution: Change Workbooks.Add( true ) to just Workbooks.Add() and see if there's any change in behaviour. If not, then keep the change; otherwise then you've encountered some undocumented behaviour in the Excel COM API and you should document this in a code-comment (and let us know too!)

Related

Create new PayPal.Payments.DataObjects.TransactionResponse

Is it possible to create a new PayPal.Payments.DataObjects.TransactionResponse?
I'm currently working on upgrading (our old ERP system) to TLS 1.2, and I need to override a function that returns a PayPal.Payments.DataObjects.TransactionResponse, but PayPal.Payments.Communication.PayflowNETAPI.SubmitTransaction returns a string. Trying to simply create a new PayPal.Payments.DataObjects.TransactionResponse hasn't worked - I'm told in the VB code that:
'PayPal.Payments.DataObjects.TransactionResponse.Private Sub New()' is not accessible in this context because it is 'private'.
Trying in the C# code yields a less descriptive error:
'TransactionResponse' does not contain a constructor that takes 0 arguments
(replacing the 0 with any number of arguments that you put in -- I tried up to 8 or 9)
I am open to solutions in either VisualBasic or C#. Although the function in question is in VB, we opted to send our transactions to an internal processing server, which will return the string (written in C#), so I can do this from either side.
Basically, I just need to take the response (currently in string format), probably parse it (although a straight string conversion would be fine too), and put the info into a PayPal.Payments.DataObjects.TransactionResponse.
You have source code here.
You can check which parameter send to the constructor.
From a quick read of the Paypal SDK code mentioned by Ygalbel, it looks like there is no new() function. Rather, you would declare your var of type PayPal.Payments.DataObjects.TransactionResponse and then use the set and get accessors to set/get data in the class.

Passing a COM method default parameter

I have a ComVisible COM class written in C#. I want to call it from another C# bit of code using COM and pass the default value for the parameter. I can call plenty of other methods without default arguments.
This is the best I can come up with. The first two lines work for all my other methods.
Type mytype = Type.GetTypeFromProgID("MyType");
dynamic myinstance = Activator.CreateInstance(mytype);
object missingValue = System.Reflection.Missing.Value;
myinstance.generatecsvdocument("mystring", ref missingValue);
My method looks like this:
public void generatecsvdocument(string mystring, string rowseperator = "\n")
When I run it I get the error:
The best overloaded method match for 'generatecsvdocument(string,
string)' has some invalid arguments
object missingValue = System.Reflection.Missing.Value;
That cannot work here. It is only valid for a COM method that takes a VARIANT as an argument. Looks like object or dynamic in C#. A very different kind of default argument mechanism than C# supports, it is the callee that determines the default value. In C# it is the caller that determines it, the C# compiler uses metadata to know that default.
Missing.Value turns in a variant of type vtError with the value DISP_E_PARAMNOTFOUND at runtime. Signalling the COM method to use the default value. Not actually that commonly used, usually only implemented in COM servers that support scripting languages. Office Automation is the most common example, probably what inspired you to try this.
But no, your argument is string, not a variant. There is no way to discover the default either when you use late binding, implicit is that you don't know anything about the default value stored in metadata. Otherwise the reason that the vtError mechanism exists, scripting languages have the same problem. The only real way to get ahead is to rewrite the method and test for a null argument, substituting "\n" if that's the case.

How do I set a function property on a dynamic COM object?

I am looking at Amibroker's OLE documentation examples in VBScript and JS trying to convert it to C# code:
http://www.amibroker.de/guide/objects.html
In it it says:
Filter( 0, "index" ) = 1; // include only indices
Filter( 1, "market" ) = 2; // exclude 2nd market
I have a C# dynamic object that I built, and I can find and call the Filter() function, but I have no idea how to set the value after the function call, since that is not valid C# syntax.
Here is the C# code:
var type = Type.GetTypeFromProgID("Broker.Application");
dynamic ab = Activator.CreateInstance(type);
ab.Analysis.Filter(0, "market") = 2; // This is obviously not compiling
When I call ab.Analysis.Filter(0, "market"), it simply returns an int for the current setting. Is the answer to use reflection somehow? I haven't tried to go down that route wondering if there is a simpler solution.
That code snippet you found is jscript, not VBScript. It is not a function property, it is an indexed property. VB.NET supports them well. But the C# team did not like them and only permits one indexed property for a class, the indexer (this[]). By popular demand they added support in version 4. Only for COM interop. Which is what you are using.
Just like the indexer, you use square brackets for indexed properties:
AA.Filter[0, "market"] = 1;
Which should be supported by dynamic as well. Explicitly calling the setter function would be another way, AA.set_Filter(0, "market", 1).
Note that you'll have a much easier time writing this code when you add a reference to the type library. That lights up IntelliSense and the red squiggles.

Char to int implicit cast Behind the Scenes

The following is valid in c# as Char can be implicitly cast to int
int i = 'a';
i am just curious about what .Net Framework do behind the scenes, i looked in to char and int types source code but unable to find where it's written.
Can any body explain what happens behind the scene?
In C# we have something that is called a Single-Rooted unified type system. That means every existing type is a subtype of one root type. Object in C#. So char or int is only short (alias) for System.Char and System.Int32. The conversion from an untyped Object to long or char (value types) is called (un)boxing.
This is a real difference compared to Java where there are the primitive types int,char.. and there is Object. Java classes like Int are wrapping the primitive types. https://en.wikipedia.org/wiki/Comparison_of_C_Sharp_and_Java
Because in C# everything is an Object (I am Object, for we are many!), all the value types implement IConvertible, as the others said.
And there is a mostly internally used enum TypeCode that is the runtime reflection info that is assigned to value type object´s like int. The Convert.To method´s are using this type information to do their job.
http://referencesource.microsoft.com/#mscorlib/system/convert.cs
The mscorlib (System namespace) can be found on github under https://github.com/dotnet/coreclr/tree/master/src/mscorlib/src/System
Further because value types are full objects (struct) lots of type/meta information is available during runtime.
C# is a safe(er) language compared to c++ for example. It does not allow unsafe impilict casts.
The cast from char to int is a widening. Int is bigger/has more space than char. It´s safe to cast.
But that´s why it is not the same as (int) 'a' like Joanvo wrote.
This is an explicit cast and you are forcing .Net to do it, no matter it´s safe or not.
For int i = 'a'; it´s fine to do an implicit cast because of the widening.
But if you try char c = 42; Visual Studio and the compiler will not allow it. Unless you force it with an explicit cast while being aware that maybe not all information from the int will fit into the char
This is also the reason why you can not use something different than a boolean (expression) inside an if.
In C/C++ you can write if(1) { } or if(0) {}. That is not allowed in C#, where you have to write if(..==1) {}. In C/C++ this is often used to check pointer for null.
You can overload the implicit and explicit operator for own types, which is useful sometimes. At least useful to know it is possible.
https://msdn.microsoft.com/en-us/library/z5z9kes2.aspx
As #shahwat and #joanvo said its the ASCII value that will be stored in i.
See this,
char value = 'a';
Console.WriteLine(value);
Console.WriteLine((int)value);
Console.WriteLine(value == 'y');
Console.WriteLine(value.GetType());
Console.WriteLine(typeof(char));
Console.WriteLine((int)char.MinValue);
Console.WriteLine((int)char.MaxValue);
Out Put:
a
97 (Integer value of char)
False
System.Char
System.Char
0 (MinValue as an integer)
65535 (MaxValue as an integer)
Edit:
microsoft
On this microsoft reference you can find the implementation of every method.
Just need to click on specific method and you will be navigated to the defination of that method.
You can also add specific VS extension related to your requirement
For ex:
Download VS extensions
by this way you would have a functionality in your VS and you can see the implementation by just right cicking on the methods and selecting "Go to Defination"
For your scenario
int i ='a';
This is not really a method (in some sense).
To view its implementation you have to use
roslyn
I am not sure would this be possible in case of Resharper , but i have just provided a way by which you can get this done.Hope this would be some help to you.
Here is a step by step guide for your scenario:
1.Setup Environment (Install VS,Roslyn) here
roslyn
2.Enable .NET Framework Source debug (if its not enabled by default)
Enable Source Debug
3.Put a break point on your statement int i='a'
4.Press f11 to step through all the implementation which is written behind this statement.
Thats all you have to do.
Imp note:
I would like to add one more thing that if above method does not worked for you ,then it would be something related to MSIL.So in that case you need to analyse what Roslyn generates from this code.
And if this is the case then you can also check it with any Reflector tool that will show you the generated MSIL.
The source code for the .NET primitive types is at http://referencesource.microsoft.com/, as indicated by #Sadaquat.
The specific implementation you're talking about is probably the implementation of IConvertable.ToInt32() from the Char struct.
That simply returns Convert.ToInt32(char value), which itself simply returns the value, since chars are integer values behind the scenes.

C# iterate generic object

Am moving from Excel VBA to VSTO using C#. In VBA I had a 3 line custom function called IsInCollection as shown below:
On Error Resume Next
Set obj = collectionObject(itemObject)
IsInCollection = Not (obj is Nothing)
I used it all the time to check if a given workbook was open, or if a workbook contained a sheet with a particular name, etc. Because the collection and the item arguments are defined as objects it would work with anything.
I'm trying to create the same utility function/method in managed code and am struggling mightily. The problem is with the collectionObject(itemObject) expression. C# doesn't allow me to just index an object as VBA did.
If anybody can point me in the right direction it would be much appreciated. From my searching I've been looking into QueryInterface but am not sure if that's where I should be looking. It seems that an Excel object comes across as a System._ComObject, so presumably I need to iterate through that somehow(?).
TIA
i think you want to check out LINQ. for example you can query collections like
IsInCollection = obj.Any(s => s != null);
The indexing operator in C# is [], not () as in VB. I'm not very familiar with COM though, so if the object you have is just an object/System._ComObject you might have to cast it to the appropriate type first, unless _ComObject has an indexer already.
It seems that finding out what type a _ComObject really is can be be a bit difficult, so you might wanna try a trick I found at http://www.mztools.com/articles/2006/mz2006013.aspx:
var typeName = Microsoft.VisualBasic.Information.TypeName( collectionObject );
I also suspect you could use the System.ComponentModel.TypeDescriptor class.

Categories