Conversion of vbs to C#, unable to get ScriptingEngine - c#

I have a VBScript which automates a little step of a SAPGUI Application.
The point is, it is needed to be converted to a dll due to internal reasons. So I created a .Net Class Library and added the Microsoft.VisualBasic.dll as assembly reference. Now I am able to get the application object, but I'm unable to execute the following methods on the object itself.
I tried through getting the type of the application and then calling getMethod() to access the function, but this didn't work out.
object application = SapGuiAuto.GetType().GetMethod("GetScriptingengine");
And I tried accessing the function through the Microsoft.VisualBasic.Interaction.Methods but these do not provide the function needed.
Here my vbs:
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell/shellcont[0]/shell").selectedNode = "0000000003"
session.findById("wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell/shellcont[0]/shell").doubleClickNode "0000000003"
session.findById("wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell/shellcont[0]/shell").selectedNode = "0000000004"
session.findById("wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell/shellcont[0]/shell").nodeContextMenu "0000000004"
session.findById("wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell/shellcont[0]/shell").selectContextMenuItem "XXEXEC"
session.findById("wnd[0]/usr/cntlSINWP_CONTAINER/shellcont/shell/shellcont[0]/shell").selectedNode = " 2"
session.findById("wnd[0]/usr/cntlSINWP_CONTAINER/shellcont/shell/shellcont[0]/shell").selectedNode = " 3"
session.findById("wnd[0]/usr/cntlSINWP_CONTAINER/shellcont/shell/shellcont[1]/shell/shellcont[0]/shell").pressToolbarButton "CREA_RAW"
Sadly my C# Script is quite small, since it's the first thing I'm getting stuck on:
public static void RunScriptParameterless()
{
object SapGuiAuto = Interaction.GetObject("SAPGUI", "");
MethodInfo application = SapGuiAuto.GetType().GetMethod("GetScriptingengine");
object session = application.Invoke(SapGuiAuto, null);
}
I just get a NullPointerException on the application declaration line.
Actually I want an object just like in the VBS which is a connection on which I can operate on.

Related

Google Scripts, calling isRequired and setRequired on multipleChoiceItem fails

I'm working on a piece of C#-code that maintains a questionnaire on Forms and keeps it in sync with a local database, e.g. when users use the program they simultaneously change data on Forms and in the database.
Since there is no Forms-API I'm using Google Scripts with a couple of helper methods as an inbetween to perform the changes on Forms.
One of the options of the program is to change existing questions, and specifically whether a question is required to be answered. I use the following code:
var questionItem = listOfItems[startOfSection + 1];
var currQues = questionItem.getTitle();
if(currQues !== questionString) {
Logger.log('Changed questionString from ' + currQues + ' to ' + questionString);
questionItem.setTitle(questionString);
}
var currReq = questionItem.isRequired();
if(currReq !== isQuestionRequired) {
questionItem.setRequired(isQuestionRequired);
}
When checking for the type of variable questionItem by calling the getType()-method, it tells me it's a multipleChoiceItem, which has a method called isRequired to read the current bool, and setRequired to set the bool. However, calling both isRequired and setRequired fail, the error message being
[Cannot find function isRequired in object Item.]
and the error type is
[TypeError]
Logger shows my questionItem var is a MultipleChoiceItem, so why does my code fail? And why does Scripts return a value to my C#-code saying the method was called on a generic "Item"?
Another method that sets new questions also calls setRequired after creating a MultipleChoiceItem and that one works without a problem.
FYI, startOfSection, questionString and isQuestionRequired are parameters given to the method during the request using the ScriptsService of the C# API.
setRequired requires a Boolean as parameter. The problem is that isQuestionRequired is not a Boolean.
If isQuestionRequired is a string, which value is 'true', you could replace
questionItem.setRequired(isQuestionRequired)
by
questionItem.setRequired(isQuestionRequired === 'true');
var questionItem = listOfItems[startOfSection + 1];
The above line of code tell us that questionItem gets its values from an array. It's very likely that problem is on how the array members were created.
As you already found that the error occurred on an object of "generic item" type, one solution is to use asMultipleChoiceItem() to make to conversition to the expected type.
Change
questionItem.setRequired(isQuestionRequired)
to
questionItem.asMultipleChoiceItem().setRequired(isQuestionRequired)

Clearscript vbscript com ado interaction

I'm using clearscript as a vbscript execution engine.
I have exposed the following C# object (I appreciate it doesn't actually execute a query, I'm just testing for now):
public class SCB
{
public ADODB.Recordset executeQuery(string q)
{
ADODB.Recordset _recordset = new ADODB.Recordset();
_recordset.Fields.Append("Id", ADODB.DataTypeEnum.adInteger);
_recordset.Fields.Append("Name", ADODB.DataTypeEnum.adVarChar, 20);
_recordset.Open(System.Reflection.Missing.Value
, System.Reflection.Missing.Value
, ADODB.CursorTypeEnum.adOpenStatic
, ADODB.LockTypeEnum.adLockOptimistic, 0);
_recordset.AddNew(Type.Missing, Type.Missing);
_recordset.Fields["Name"].Value = "Test";
return _recordset;
}
}
}
I have created a vbscript host using:
_engine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging);
And added the class as an object with this line:
_engine.AddHostObject("SCB", HostItemFlags.GlobalMembers, new SCB());
If I run some vbscript code via the following call I receive an error (described below):
_engine.ExecuteCommand(code);
The code I am executing is the following:
Function GetUniversalMessage
dim lRS, sMessage, sColour,sTimeout
Set Lrs = SCB. executeQuery ("SELECT MESSAGE, TIMEOUT, COLOUR, ENABLED FROM U_SCROLLER WHERE SCROLLER_ID=1 AND ENABLED='Y' AND (DISABLE_TIME IS NULL OR DISABLE_TIME>GETDATE())")
if not lRS.EOF then
End If
End Function
I receive an exception that lrs.eof is not a valid field ... but it is valid for an ado com object, and if I check the object created in executeQuery before it returns to the script engine, the EOF field is present.
When I debug by attaching the debugger and calling the stop command, I can see that the lrs object in vbscript does not contain EOF, or most of the valid Recordset fields.
Can someone assist me in explaining what clearscript is doing to the object before it is inserted into the vbscript engine?
Thanks,
Rob
Check whether you're using embedded Interop types. That feature is problematic for scripting because the embedded types are stripped of any members you don't use in managed code.
For example, if you don't use EOF in managed code, the metadata for the EOF property will be left out of the embedded version of Recordset.
In Visual Studio, try setting the Embed Interop Types property of your ADODB reference to False.
Another thing to try would be to change the executeQuery return type to object, or add the attribute [ScriptMember(ScriptMemberFlags.ExposeRuntimeType)].

C# program connecting to example DBus daemon always gets 'Access is denied: DBus.BusObject'

For our current project we are using DBus (1.6.n).
It is largely accessed from C++ in shared memory mode, and this works really well.
I am now trying to access the same DBus from a C# program.
In order to try things out first, I downloaded the latest version of dbus-sharp I could find, and started the daemon included in the download to see if I could connect to it from my test C# app.
Whenever I make a connection, the daemon console shows that I am communicating with it, but as soon as I try to access any methods on the connection I get the error;
'Access is denied: DBus.BusObject'
Here is the code I have tried;
DBus.Bus dBus = null;
try
{
//input address comes from the UI and ends up as "tcp:host=localhost,port=12345";
//dBus = new Bus(InputAddress.Text + inputAddressExtension.Text);
//string s = dBus.GetId();
//dBus.Close();
//DBus.Bus bus = DBus.Bus.System;
//DBus.Bus bus = Bus.Open(InputAddress.Text + inputAddressExtension.Text);
//DBus.Bus bus = DBus.Bus.Session;
//DBus.Bus bus = DBus.Bus.Starter;
var conn = Connection.Open(InputAddress.Text + inputAddressExtension.Text);
var bus = conn.GetObject<Introspectable>(#"org.freedesktop.DBus.Introspectable", new ObjectPath("/org/freedesktop/DBus/Introspectable"));
bus.Introspect();
}
finally
{
if(dBus != null)
dBus.Close();
}
The commented code produces the same error eventually too.
I have stepped through with the debugger and it always gets to the following code in the TypeImplementer.cs;
public Type GetImplementation (Type declType)
{
Type retT;
lock (getImplLock)
if (map.TryGetValue (declType, out retT))
return retT;
string proxyName = declType.FullName + "Proxy";
Type parentType;
if (declType.IsInterface)
parentType = typeof (BusObject);
else
parentType = declType;
TypeBuilder typeB = modB.DefineType (proxyName, TypeAttributes.Class | TypeAttributes.Public, parentType);
if (declType.IsInterface)
Implement (typeB, declType);
foreach (Type iface in declType.GetInterfaces ())
Implement (typeB, iface);
retT = typeB.CreateType (); <======== Fails here ==========
lock (getImplLock)
map[declType] = retT;
return retT;
}
I have not found any useful examples or documentation about accessing DBus from C#, and there seem to be few recent entries about this anywhere, so maybe no-one else is trying this.
I am running the daemon in the same folder as the test program.
As I am running on windows, the daemon is listening on the tcp setting;
string addr = "tcp:host=localhost,port=12345";
Since this is the example included with the download, I thought it would be really simple to get it going, but alas no luck yet.
Has anyone else been here and know the next piece of the puzzle?
Any ideas would be appreciated.
Having received no comment or response, I will answer the question with the information I have found since asking it.
There appears to be no useful C# interface to DBus. (By useful, I mean one that works!)
The only information or examples I could find are not up to date and no effort appears to be being expended on providing a working interface.
I have decided to interface with DBus by using a C++ implementation written as a Windows service, and my C# program will send messages to DBus via the service. This seems to work ok, so satisfies the business need.
I am disappointed not to be able to get the C# to DBus working, but there are lots of service bus implementations that work on Windows, so in future I will look at implementing those instead of DBus.
If anyone does come up with a workable, documented solution to accessing DBus from C# on Windows, I would still be interested to see it.
I had the same error when I created new test project and add dbus cs source files to it main project assembly. It was when IBusProxy type dynamically created in dynamically created assembly.
asmB = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("NDesk.DBus.Proxies"), canSave ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run);
modB = asmB.DefineDynamicModule ("NDesk.DBus.Proxies");
......
retT = typeB.CreateType ();
I think it was cause current running assembly isnt friendly for created assembly. And just when I add to project compiled NDesk.DBus.dll this error disappeared.

How to CreateObject in C#?

I want to translate the following VB6 code into C#
If optHost(0).Value Then
Set m_oScpiAccess = New IcSCPIActiveX.IcSCPIAccess
Else
sHost = txtHost.Text
Set m_oScpiAccess = CreateObject("Exfo.IcSCPIActiveX.IcSCPIAccess", sHost)
End If
I used TlbImp.exe to create wrappers for the COM classes, and I tried:
if (string.IsNullOrEmpty(host))
{
// this works
IcSCPIAccess = new IcSCPIAccess();
}
else
{
// throws MissingMethodException
IcSCPIAccess = (IcSCPIAccess)Activator.CreateInstance(
typeof(IcSCPIAccessClass),
host);
}
But there is no constructor which accepts the host parameter
It is not a constructor call. The sHost variable contains the name of a machine, the one that provides the out-of-process COM server. The equivalent functionality is provided by Type.GetTypeFromProgId(), using the overload that allows specifying the server name:
var t = Type.GetTypeFromProgID("Exfo.IcSCPIActiveX.IcSCPIAccess", sHost, true);
obj = (IcSCPIAccess)Activator.CreateInstance(t);
I named it "obj", do avoid giving variables the same name as the interface type. A gazillion things can still go wrong, having the COM server properly registered both on the client and server machine and setting the DCOM security correctly is essential to make this code work. Don't try this until you are sure that the original code works properly.

How do I look up a Corba service with C# and IIOP.NET?

I am writing a C# client for a Corba server and I am using IIOP.NET, going by the example on the following page: http://iiop-net.sourceforge.net/rmiAdderDNClient.html
I have gotten this far without errors:
// Register channel
IiopClientChannel channel = new IiopClientChannel();
ChannelServices.RegisterChannel(channel, false);
// Access COS naming context
CorbaInit init = CorbaInit.GetInit();
NamingContext context = init.GetNameService(host, port);
The variable "host" is a string with the computer name of the server and "port" is an int representing the port number. The values for these are currently used by other systems to connect to the server so I can confirm that they are correct.
However, trying to connect to the trader service yields an exception in runtime. Here is the code I use to do that:
// Looking up VB Trader
NameComponent[] names = new NameComponent[] { new NameComponent("TraderInterface") };
object obj = context.resolve(names);
And here is the error message I'm getting:
"CORBA system exception : omg.org.CORBA.INV_OBJREF, completed: Completed_No minor: 10102."
This seems to suggest an invalid object reference, but what does that mean? Is the string I am passing to the resolve method incorrectly formatted? I have tried many different names for this service as used in other systems, but I always get the same error, which makes me wonder whether I am even interpreting it correctly.
Incidentally, in my desperation, I have also attempted to obtain an object reference from the IOR, but this again throws a different exception (namely omg.org.CORBA.ORB_package.InvalidName).
OrbServices orb = OrbServices.GetSingleton();
object obj = orb.resolve_initial_references(traderIOR);
Any advice is welcome.
I was never able to reach my server with any of the above methods, however the following code is what finally got the communication working:
Hashtable props = new Hashtable();
props[IiopChannel.BIDIR_KEY] = true;
props[IiopServerChannel.PORT_KEY] = port;
// register corba services
IiopChannel channel = new IiopChannel(props);
ChannelServices.RegisterChannel(channel, false);
MyInterface obj = (MyInterface)RemotingServices.Connect(typeof(MyInterface), ior);
I'm not entirely sure why I had to use this (seemingly) unconventional way. Perhaps it is due to the lack of a naming service running on the server. Whatever the cause, I hope this helps somebody out there.

Categories