I see there is a problem with the error handling in VBScript, So I would like to fix this using c# code (COM). Here, I need to access Err object of VBScript in c#.net code. I did add the reference namespace VBScript_Global to the project, but VBScript_Global.ErrObj is an abstract class, so could not access it. Is there a way that c# code can watch the Err.Number.
Let me put it more clear,
In VB6, we have On Error GoTo in which if there is a runtime error it automatically drops into error handling code and we can report the error there and do appropriate action.
The same is true with .net and Java (it may be try/catch there).
Where as in VBScript, we have On Error Resume Next (it does not support GoTo ).
On Error Resume Next just moves the controller to the next statement and continue with the execution. Where, we need to explicitly check whether Err.number <> 0 after each statement in the code, which is not feasible to implement.
So I want a generic approach in VBScript, if there is a runtime error, then I should be able to report it somehow.
I thought of writing a dll in c#.net which always checks for the Err.Number of VBScript and report when there is an error occurred. Is this possible? Or my approach is wrong?
Any other alternative suggestions/ideas to handle this situation is appreciated. Thanks.
If the dll cannot do what am looking for, is there a way I can always check whether Err.number of VBScript is NOT 0 out side the VBScript?
VBScript executes in a separate environment. You cannot access an intrinsic VBScript object outside of VBScript, or more appropriately, Windows Script Host.
Related
I am writing a license module (DLL) for multiple applications. This DLL will be used in applications by adding reference. One of the requirement (pass case) for this DLL is that, if license validation fails, calling application should terminate/crash. It should not gracefully shutdown; it must crash. I do not want to show message, write log etc.
DLL and applications (using this DLL) are written in DotNet 4.
Quick solution I can think of is to throw exception instead of returning value from method. But, the exception could be caught by application and purpose will not be fully served.
Workaround for this is to declare custom exception as internal in my DLL. But, this also could be bypassed by catching Exception class.
One dirty alternative I can think of is to write a code (endless recursion or something) that will throw StackOverflowException. But I am looking for something better.
Is there any way to throw custom non-catchable exception?
References:
Ref1 and Ref2 discuss about in built DotNet non-catchable exception. My question is about custom non-catchable exceptions.
Environment.FailFast is the way to go, nothing can then prevent your application from shutting down.
Keep in mind that C# libraries can be easily changed and recompiled, so you might also want to look into using obfuscators as well.
I'm looking at NLua for scripting of an existing C# application, where C# functions called from lua may throw exceptions.
So far, I found this:
If the lua code does not handle an exception in a called C# function, NLua wraps and re-throws it so it can be handled at C# level.
If lua code does "catch" an exception via xpcall, I have found no way to access the exception's details (e.g -.Message)
The former allows me to get a debug.traceback(), a lua-level stackdump, but I don't get details of the exception.
The latter provides the exception, but no way to get a Lua stackdump (I get lua file and line in .Source, but that isn't enough).
The question is:
Can I get details of a C# exception in a NLua "xpcall" error handler (? At least the .Message field, even better the actual exception type.
Alternatively, can I handle a C# exception in NLua (with the intention of creating a lua stackdump) and re-throw it?
Or can I get a lua stackdump somehow from the "lua state" when e.g.luaState.DoFile("myScript.lua") causes an exception?
Any help would be appreciated. NLua seems near-perfect for what I have in mind, if I could only sort out the exception handling.
You need to use pcall from your script. The NLua will wrap the exception and return on second value returned by pcall.
error, exception = pcall (someFunction)
if (not error) then
print(exception.Message)
end
Example on GitHub.
I’m working with a .NET 4 application written mostly in C#. The application has a user interface, but it also has an automation interface that allows the features of the application to be exploited directly from a .NET client. It also supports automation via COM, and for this there are “COM adapter” DLLs that present the classes/methods in the “real” DLLs in a COM-friendly way.
For example, let’s say the API for the bulk of the functionality is in a DLL called “Alpha.DLL”: a .NET client can simply reference that DLL directly, but a separate DLL called “Alpha.Com.DLL” is provided for use by COM clients (e.g. VBA).
There are 3 such COM adapter DLLs, and while two work fine, I simply cannot get the last one to work correctly.
The problem DLL only has two classes defined within it, and while I can instantiate one of them from a COM client such as VBScript, I get an error when I try to instantiate the other. The error I get is:
-2146234304 (0x80131040) Automation Error
I can instantiate the same class from .NET code, just not from a COM client.
I’ve tried using FUSLOGVW.EXE to look for assembly-loading errors, but there don’t seem to be any (and in any case, the fact that I can instantiate the other class from the same DLL suggests that it’s not the DLL itself that can’t be found/loaded?).
I’ve tried attaching a debugger and putting a breakpoint inside the constructor for the offending class, but it doesn’t get hit when I try to instantiate the class from VBScript. (A breakpoint in the constructor of the class that works does get hit).
I’ve checked the registry entries for the class I’m trying to instantiate, and I can’t see any problem. The GUIDs and version numbers all seem to match up.
I’m all out of ideas, and at the end of my tether, and I’d be extremely grateful for some help…
-2146234304 (0x80131040) Automation Error
The common problem with using .NET code from a COM client like VBA is that .NET exceptions get rather difficult to diagnose. You have to make do with an often cryptic HRESULT error code, you don't get the Holy Stack trace to see how code blew up. This exception is a doozy like that, it is FUSION_E_REF_DEF_MISMATCH, you can find these HRESULT codes in the CorError.h SDK include file.
You'd normally get the easier to interpret exception message "The located assembly's manifest definition does not match the assembly reference". And the stack trace to tell you what type caused this exception so you'll know what assembly is the problem. Nothing like that when this failed when called from VBA.
It is otherwise an every-day .NET mishap, the CLR found your assembly but its [AssemblyVersion] does not match the reference assembly's version that your code was compiled with. COM certainly increases the odds that this can go wrong, the version is recorded in the registry when you register the assembly with Regasm.exe. Forgetting to re-register if you do it by hand instead of letting the build system take care of it is a very easy oversight. Also very easy to copy dependent DLLs in the client EXE's directory, so the CLR can find them, and forgetting to update them.
Fuslogvw.exe does show this kind of mishap, hard to guess why you don't see anything. The backup plan is to use SysInternals' Process Monitor. It also shows you how the client is reading the registry, another thing that often goes wrong in COM. And you'll see it locating the DLL from the registry key so you'll have a shot at guessing why it found an old one.
Stay out of trouble by using the GAC, often necessary anyway to help the CLR to find dependent assemblies and to solve COM's rather severe DLL Hell problem. And strongly consider using the .NET 4 AppDomain.FirstChanceException event. Good to log exceptions before they turn undiagnosable in the COM client.
please check first
your com dll is placed into GAC
you dont't forget about regasm
http://www.jagjot.com/2014/01/register-c-vb-net-dll-regasm-gacutil/
check cpu architecture
does your com dll depends on anything outside GAC?
Aaargh. I found the problem. I said in my question:
I’ve checked the registry entries for the class I’m trying to instantiate, and I can’t see any problem. The GUIDs and version numbers all seem to match up.
...which was true. However, what I had not noticed was that in the registry definition of one of my classes, the public key token was wrong.
This explains why one class could be instantiated while the other could not, and possibly why there was nothing in the FUSLOGVW log (because the assembly was loaded OK when an instance of the "good" class was created).
Thanks for your help, Hans and Dimzon.
I'd liked to know whether it is possible to call a function in VBScript from C#. Let me try to clarify. I'm using an application (Quick Test Professional or "QTP") that automates another application, mostly using VBScript. There is the ability, via an add in model, to extend the test functionality by writing add-ins to the testing application (QTP) that are .NET assemblies. The basic workflow is that the VBScript tests automate the test application, and can call methods on a class in the extensibility add in assembly to do more complicated things. This part works fine.
What I'd like to know is whether it is possible for my C# code (in the extensibility add in assembly) to call back to a function in the VBScript. I don't think the test application framework (QTP) explicitly supports this, so I'm wondering if there is any way to do this using standard interop techniques. I was half way thinking of using GetRef() to get a reference to the VBScript function of interest, passing this as a parameter to a method I call in the extensibility addin (I suspect I would run into marshaling issues even at this point?) and then within the C# code of my extensibility add in, somehow call a method on this object; this is where I'm completely lost (since I don't know how to do this without the necessary type information normally used in reflection).
I'm thinking this may not be possible, but would like confirmation if that's the case.
Thank you!
In the end not so hard but finding it out was harder
In vbscript set a=getref
In c# declare the ref as an object
https://community.saas.hpe.com/t5/Unified-Functional-Testing/C-compile-on-the-fly-thru-dotnetfactory/m-p/1611299#M22811
private object _UFTCallBackFunction = null;
public int callMeBack2()
{
string[] retParts = {"Yep this is value 1"};
_UFTCallBackFunction.GetType().InvokeMember("",
System.Reflection.BindingFlags.InvokeMethod, null,
_UFTCallBackFunction, retParts);
return 0;
}
public void InitUFTCallBack(object UFTCallBackFunction)
{
_UFTCallBackFunction = UFTCallBackFunction;
}
And then in vbs
Set oCallMe = GetRef("CallMeBackWithAParameter")
oTestCom.InitUFTCallBack(oCallMe)
oTestCom.callMeBack2()
Function callMeBackWithAParameter(P1)
print "I wass called back from C# having value " & P1
End Function
How does the VBScript call the C# code? I suspect that it is really calling on QTP, and QTP is calling the C# code. In that case, only QTP could possibly call the VBScript back.
Under what circumstances would your C# code call back? I doubt that VBScript can be called back asynchronously.
That's a toughie.
You MAY want to try writing an event handler in the VBScript side for the .NET component and raising an event on the .NET side when you want the function to be called.
Just be warned it may not even work, as it really depends on QTP's scripting engine. And even if it should, don't be surprised if it becomes an exercise in frustration.
See examples on WSH and event handling http://msdn.microsoft.com/en-us/library/ms974564.aspx Again, this probably won't apply to QTP, but it's to give you an idea of potential approach to the problem.
Edit: Additional link which may or may not help!
http://www.west-wind.com/presentations/dotnetfromVfp/DotNetFromVfp_EventHandling.asp
I made a COM object with c# and let VS register it for me. I can see it in registry and if I make a test app I can add a reference to it and it works as expected with all the methods available and functional.
Now If I try and use it in a MSMQ rule nothing happens. It will not be invoked. Is this because it is a .NET assembly? Is it because I do not have VS Pro? Do you have any idea at all?
You haven't by any chance registered your component on a mapped network drive have you? MSMQ runs in a different WinStation to the interactive WinStation. Network drives that are mapped in the interactive WinStation are not visible in other WinStations which could result in the symptom you described (component not found).
You need to check the system event log for error messages (eventvwr.exe). If your component is registered and MSMQ is properly configured to activate your component but it fails, most likely the problem is with permissions. The event log should contain the details of the prolem.
Update!!!
I was messing around with this again. I created a simple EXE to fire when a message is received. It accepts 2 string parameters.
I forgot to pass the parameters the first time and I get the SAME error as I was discribing before. About the COM object not being found. I passed the parameters and it worked fine.
I thought I was passing the parameters to my COM object just fine, but maybe not. Maybe I'm doing something wrong. I will create a COM with no parameters and see if I can force the COM to invoke.
If anyone as examples of creating objects to accept parameters, please let me know.