I have encountered a strange problem, which I could solve but don't understand why it did occur.
I have build a DLL with COM enabled. In this DLL I have classes that did use the functions CInt, CDec and IsNumeric. If I test these classes from a .NET application then it works ok. But when I called/run these classes from a Win32 application (with COM) then I did get an "E_UNEXPECTED(0x8000FFFF)" error.
After some debugging I found out that the problem would go away if I:
- replaced IsNumeric with Integer.TryParse or Decimal.TryParse
- replaced CInt with Integer.Parse
- replaced CDec with Decimal.Parse
Can anyone explain this? Again, I could solve it by doing this but I would like to know why.
Just a guess.
I think that this is somehow related to the fact that all legacy functions like CInt, CDec, etc are defined in Microsoft.VisualBasic.dll assembly, which appears not to be playing well with COM.
That's pretty strange. Sounds to me like the arguments passed by the unmanaged code caused an exception in the VB.NET code. Your unmanaged code cannot detect managed exceptions. It should be visible in the debug output in the Output window, you should see a first-chance exception with exception code 0xe0434f4e.
Your changes are not a true replacement for CInt/CDec, they'll only handle string arguments. But stranger yet is that CInt() doesn't have trouble with strings, it shouldn't throw.
You are playing fast and loose with argument types though, treating strings as numbers is always trouble. Make sure you declare the argument type. Putting Option Strict On at the top of your source code is a good way to operate the two-by-four.
Related
I'm using NUnit to verify some code and have a problem reporting helpful information. My tests go something along the following lines:
Assert::IsTrue(myClassInstance.SomeMethodToTest(), "Test failed: {0}", myClassInstance.LastError);
The problem is that the LastError property is evaluated before the method is tested so the last error is blank.
Is there any way to delay the evaluation of the last error to give the function some more meaningful output?
Well, that's a big bummer, but you are invoking Undefined Behavior here. NUnit was originally designed for Java, ported pretty well to C# and VB.NET. Languages that promise strict left-to-right function argument evaluation order in their language spec. So that Assert.IsTrue() method has well defined behavior in those languages.
But not in C++/CLI, it takes advantage of the UB rule in C++. No doubt inspired by the [ParamArray] for the 3rd argument, it first polishes off that one before evaluating the other arguments. You get right-to-left order. Shooting off the hip, I'd say that this has something to do with varargs emulation.
Not so sure what to recommend, sailing around UB is forever tricky. You can technically provide your own overloads of Assert::IsTrue() with one or more Object^ arguments. The compiler will pick those instead of the [ParamArray] overload. Or avoid the [ParamArray] overload completely and use String::Format() to generate the message argument instead. You'll now get left-to-right. That's still UB however, it looks okay but I can't promise this will work with every possible set of argument expressions.
Ouch, sorry.
I have an application that involves a lot of communication between managed (C#) and unmanaged (C++) code. We are using Visual Studio 2005 (!), and we use the interop assembly generated automatically by tlbimp.
We have fairly good luck passing simple structs back and forth as function arguments. And because our objects are fairly simple, we can pack them into SAFEARRAYs using the IRecordInfo interface. Passing these arrays as arguments to COM methods seems to work properly.
We would like to be able to embed variable-length arrays in our UDTs, but this fails badly. I don't think I have been able to find a single piece of documentation showing how someone has accomplished this. Nor have I found documentation that says it can't be done.
1) Naive approach: Simply declare a safearray in the managed code:
struct MyUdt {
int member1;
BSTR member2;
SAFEARRAY *m3;
};
The C++ compiler is happy with this, but the generated IDL confounds tblimp.exe. It reports that it is unable to convert the signature for member m3, and the signature for member tagSAFEARRAY.rgsabound. These are only warnings, but they are meaningful, the resulting assembly is not usable.
Using LPSAFEARRAY, oddly enough, fails in different ways, but for the same reason, tblimp just can't deal with it.
2) Trickier: Pack it into a variant:
struct MyUdt {
int member1;
BSTR member2;
VARIANT m3;
};
We have code that builds safearrays of UDTs, and it never gives us any trouble. It's basically copied from MSDN. Using that code to create a safearray, then:
pVal->m3.vt = VT_SAFEARRAY | VT_RECORD;
pval->parray = p;
Fails in odd ways. It always breaks, some variations produce an OutOFMemoryException... odd, others fail in different ways. (I'm not sure if a pRecInfo pointer is required here or not, but it fails the same way, present or not.)
The Google search space for this is badly polluted with answers to questions that I am not asking:
How do you pass UDT/structs from unmanaged code.
How do you pass a SAFEARRAY of structs? (We're doing this fine.)
How do you use p/invoke or customer marshalling to pass UDTs.
And many answers describing how to define things from the managed side, not the unmanaged side.
And then there are a couple of Microsoft KBs describing problems with VT_RECORD in early versions of .NET. I don't think these are germane - VT_RECORD types work with VARIANT and with SAFEARRAY. (But maybe not with the UDT marshallling...)
If this won't ever work, it would be nice to at least know why.
Mark
I have de-compiled some old code from a legacy VB.NET app using ILSply and this line has appeared:
Operators.ConditionalCompareObjectEqual(safeDataReader["isLoader"], -1, false)
I'm aware this is compiler generated, but its not advised that this code is used in application source code. My question is why is this the case and what should it be in 'normal' code?
The documentation for the method says it right there:
Represents the overloaded Visual Basic equals (=) operator.
Why? I don't "know", but it's easy to make an educated guess.
The semantics of the "=" operator in VB.NET are just a bit different from those of C# and the standard Object.Equals(). The semantics are inherited from VB6 and cannot be changed for backward compatibility reasons. Obviously this method implements the VB6 semantics for the compiler.
It would make an interesting read to come up with a systematic analysis of the differences.
Further thoughts:
The reason it's "not recommended" is because there is no reason to call the method from VB.NET: just use =. In C#, there is no particular reason to invoke the VB6 semantics so the method doesn't make a lot of sense there either.
Obviously, if you are compiling C# code generated from VB.NET, then those are special circumstances: calling the method is the right thing to do, unless you're willing to take the time to analyze the code and prove to yourself that the standard = cn be substituted safely.
I'm trying to port a C++.NET (managed extensions) application to C++/CLI. However I'm not very strong with the syntax yet.
What I'm trying to do is to create a wrapper for a C Dll file.
To do this I'm using DllImport but I failed to found documentation on it's use. There are some problems due to changes of the syntax but I couldn't find out why yet.
The C++.NET line looks like this:
[DllImport("my.dll", CharSet = Ansi, CallingConvention = Cdecl, EntryPoint = "#10")]
static MY_STATUS CPPInit(MY_HANDLE *pLmxHandle);
The idea is to pass a reference of MY_HANDLE to the function which initializes it. One problem is that the keywords Ansi and Cdecl are unknown. I expect I need to put some class infront of them but it's a little hard without docs or samples.
The other thing I have is a function which returns a static string:
char *MyFunc();
Can I assume that it can be mapped to String^?
Thanks in advance.
thanks for the comment.
I thought to myself that I need to build a mixedmode library in order to avoid p/invoke. This just takes some time though.
Actually I solved the compile error in another way. Although I havn't tested it yet because I'm facing some 32/64 bit issues which I can't solve because of other bugs in Whidbey beta2.
My solution was to write the protype in the following way:
interior_ptr<MY_HANDLE> pMyHandle;
From what I understood it should give the function a reference (hence an address) to the dll function. Once I get to try it out I will see if my idea works.
Otherwise I will go for the following option (which i've been offered):
[Out] IntPtr p_MyHandle
Anyway I think the problem is solved because one of those should work.
in VB.NET it is possible to omit parentheses when you call a parameterless function. However this can be very confusing because developers could think that a statement is accessing a property instead of a method. this could result in a performance drop if you are calling the method again and again instead of storing the result in a temp variable.
is there an option in VS2008 or a compiler option to force parentheses on statements that are calling a method?
and if so, would it be also possible that VS will insert missing parentheses automatically if you "format document" (Menu: Edit - Advanced)?
thanks, toebens
No there is no such option in the VB.Net compiler. Parens are optional and there is no warning or error that exist for using a lack of them.
The other reason is that VB.Net is a language which tries to be flexible and get the syntax out of the way of the user. This type of restriction goes against this general philosophy.
Another issue to consider is that it's not a universally enforceable restriction. VB.Net allows for late binding scenarios whenever option strict is set to off. In these scenarios it is impossible for the VB.Net compiler to determine ahead of time if a particular call is a property, statement or not a valid call at all.