I have a C# feeder that generates some data and sends them to some sort of frontend. Is there a direct way in which I can receive these data using excel microsoft office ?
P.S. I do not want to write a code that recieves the data and then writes it into excel sheet. I want to be able to directly get the data from excel itself, as a frontend for my C# backend. Is that ever possible ?!
I did a quick dr. Google search for WebService calls from Excel and found the following article
Option Explicit
' Excel VBA Function wrapper to call currency conversion Web Service on the web!
Public Function ccyConvert(rsCurrIn As String, rsCurrOut As String,
ByVal vfAmtIn As Single) As Single
Dim objSClient As MSSOAPLib30.SoapClient30
' Remove the 30 if using an earlier version of SOAP
Dim fResult As Single
' Point the SOAP API to the web service that we want to call...
Set objSClient = New SoapClient30
Call objSClient.mssoapinit(
par_WSDLFile:="http://webcontinuum.net/webservices/ccydemo.wsdl")
' Call the web service
fResult = objSClient.calcExcRate(rsCurrIn, rsCurrOut, vfAmtIn)
Set objSClient = Nothing
ccyConvert = fResult
End Function
As Excel has the possibility to access data (from different dataSources) it may be a proper solution to create a c# WebService which delivers the requested data.
Pls note that this is not my code - it's just a copy from the mentioned article - so credit goes to the author!
I just thought about another solution. You may consider making your own C# com component. Within any excel VBA code you are now able to call any method within your assembly. Once again mr. google found an article describing how to achieve this!
c# code for your own com component
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace DotNetLibrary
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class DotNetClass
{
public DotNetClass()
{
}
public string DotNetMethod(string input)
{
return "Hello " + input;
}
}
}
VBA code within an excel macro
Private Sub TestDotNetCall()
Dim testClass As New DotNetClass
' or do whatever you want with return value
MsgBox testClass.DotNetMethod(“World”)
End Sub
Related
I have a VB based block of code I need to rewrite in C# and I'm writing a function which creates an instance of a COM object and creates a new terminal session, goes out, reads a screen and returns the contents of the screen. Right now though I feel like I'm not taking the right approach in C# and would appreciate some feedback.
VB Code
set bzlipi = CreateObject("BlueZone.LIPI")
bzlipi.Username = "myuserid"
bzlipi.Password = "mypassword"
bzlipi.HostAddress = "101.122.0.138"
bzlipi.ShowTransferStatusWindow = False
bzlipi.LocalPromptBeforeOverwrite = False
result = bzlipi.ReceiveFile( "local.txt", "MYLIB/F4101" )
MsgBox bzlipi.ErrorMessage
C#
using BZLIPILib;
using BZWHLLLib;
public void Connector() {
object Host = Activator.CreateInstance(Type.GetType("BZLIPILib.LIPI"));
//Set Host properties
}
As it stands, this is not not recognizing any properties within Host as its
VB counterpart does above. I've made all the available COM object
references within package manager of my VS project. What should I be
doing differently?
Change:
using BZLIPILib;
using BZWHLLLib;
...
object Host = Activator.CreateInstance(Type.GetType("BZLIPILib.LIPI"));
...to:
using BZLIPILib;
using BZWHLLLib;
...
LIPI Host = new LIPI();
...then intellisense will work as expected.
Update: It appears that the actual code required is:
using BZLIPILib;
using BZWHLLLib;
...
LipiObj Host = new LipiObj();
...as per OP's comment below.
One of my friend has an application built in Clipper. Now he wants to add some new features to his application, but he does not know how to code for it. I can complete his requirements in a console application in .net. So, I written a function like below in C#:
public static void sendSmsDemo(string MobileNo, string Password)
{
Console.WriteLine("Your Mobile Number is : " + MobileNo + "\n" + "Your Password is : " + Password);
}
I call this function in main method's constructor. And my program works fine.
Now, He wants to call this function from his application developed in Clipper. Is there anybody who knows how to communicate between C# app and Clipper app?
If what you're wanting is to call a C# routine natively from Clipper, you're out of luck.
Another approach may be to recode the Clipper app in Vulcan.NET. Vulcan is a .NET native development environment for XBase.
Otherwise, there may be other techniques, but more details are needed: for example, whether your colleague is using Clipper 5 or Harbour, etc. Some more source from the Clipper side showing what is needed would be helpful.
1º First Step
I create a Class Library in C# and compile options, mark Register for COM interop.
2º The Class sample
Public Class Order
Public Function Total() As Decimal
Return 100
End Function
Public Property Description As String = "Teste"
End Class
3º Test in Harbour
// Now is possible use methods e properties the class
include "minigui.ch"
Function Main()
Local oOrder
//HarbourInvoke the name of my Class Library in C#
oOrder = CreateObject("HarbourInvoke.Order")
MsgInfo(oOrder:Total())
MsgInfo(oOrder:Description())
oOrder:Description := "new test"
MsgInfo(oOrder:Description())
oSuma := nil
Return Nil
I would like to automate an SAP GUI window using the C# language. I am able to do it in VBScript but code reuse is horrible. Besides Id like to use threading instead of having 80 or more processes running. Where can I find any documentation and samples of how to do this? Here is the code I am working with. Basically, the problem I am facing is - how do I make a connection to SAP GUI then create an SAP GUI on the fly then start making transactions and entering text in some fields.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using White.Core.Factory;
using White.Core.UIItems.Finders;
using White.Core.InputDevices;
using System.Threading;
using System.Diagnostics;
using SAP.Connector;
using SAP;
namespace SAP_Automation
{
class Program
{
public static void Main(string[] args)
{
string ExeSourceFile = #"C:\Program Files\SAP\SapSetup\setup\SAL\SapLogon.s8l";
White.Core.Application _application;
White.Core.UIItems.WindowItems.Window _mainWindow;
var c = SAP.Connector.Connection.GetConnection("**");
var c = new SAPConnection("ASHOST=*; GWHOST=*; GWSERV=*; ASHOST=*; SYSNR=00;USER=user; PASSWD=**;");
c.Open();
}
}
}
}
As you can see I can create a connection but I dont know how to create a session to the GUI and start entering text in fields. Any examples and samples would be appreciated.
This might be necro-threading but I was in a similar situation where I work. We needed SAP GUI Automation for testing purposes that could integrate with the rest of our homegrown automation platform written in C#. I helped create a proposal for one solution that took advantage of a SAP provided library for GUI automation that could be used as the basis for an automation layer for SAP.
Does the following file exist on your SAP file installation? x:\Program Files\SAP\FrontEnd\SAPGui\sapfewse.ocx?
If so, add it to Visual Studio (or whatever IDE you're using) as a reference. It is basically a class library which contains a bunch of SAP specific objects that will allow you to interact with. It is very effective because it exposes most of what you need from the SAP GUI. We discovered in other attempts that a lot of the objects in SAP were not available.
This is an early proof of concept I did. Start SAP with a connection string, enter credentials, navigate to a transaction code.
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using SAPFEWSELib;
namespace SAPGuiAutomated
{
//created a class for the SAP app, connection, and session objects as well as for common methods.
public class SAPActive
{
public static GuiApplication SapGuiApp { get; set; }
public static GuiConnection SapConnection { get; set; }
public static GuiSession SapSession { get; set; }
public static void openSap(string env)
{
SAPActive.SapGuiApp = new GuiApplication();
string connectString = null;
if (env.ToUpper().Equals("DEFAULT"))
{
connectString = "1.0 Test ERP (DEFAULT)";
}
else
{
connectString = env;
}
SAPActive.SapConnection = SAPActive.SapGuiApp.OpenConnection(connectString, Sync: true); //creates connection
SAPActive.SapSession = (GuiSession)SAPActive.SapConnection.Sessions.Item(0); //creates the Gui session off the connection you made
}
public void login(string myclient, string mylogin, string mypass, string mylang)
{
GuiTextField client = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-MANDT", "GuiTextField");
GuiTextField login = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-BNAME", "GuiTextField");
GuiTextField pass = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-BCODE", "GuiPasswordField");
GuiTextField language = (GuiTextField)SAPActive.SapSession.ActiveWindow.FindByName("RSYST-LANGU", "GuiTextField");
client.SetFocus();
client.text = myclient;
login.SetFocus();
login.Text = mylogin;
pass.SetFocus();
pass.Text = mypass;
language.SetFocus();
language.Text = mylang;
//Press the green checkmark button which is about the same as the enter key
GuiButton btn = (GuiButton)SapSession.FindById("/app/con[0]/ses[0]/wnd[0]/tbar[0]/btn[0]");
btn.SetFocus();
btn.Press();
}
}
//--------------------------//
//main method somewhere else
public static void Main(string[] args)
{
SAPActive.openSAP("my connection string");
SAPActive.login("10", "jdoe", "password", "EN");
SAPActive.SapSession.StartTransaction("VA03");
}
You're right there is not a lot of documentation on this subject. Below are a few sources that helped me get started
-Original source of our plan
http://scn.sap.com/thread/1729689
-Documentation on the API (For VB and javascript but the general rules and objects are identical). Definitely read the portion on the SAP GUI Runtime hierarchy. It'll answer a lot of questions.
http://www.synactive.com/download/sap%20gui%20scripting/sap%20gui%20scripting%20api.pdf
It is very important here to understand what UI Automation can do and what its limitations are. It was designed to automate a user interface's capabilities. You can click buttons, enter text in a textbox, move windows, etcetera, whatever a user can do using the mouse and keyboard.
What it can not do is bridge the tall wall that the operating system puts up between processes. A wall that prevents a process from accessing the memory of another process. This is a very important security and safety feature. It for one prevents a process from accessing data that should be private to a process. Like a password. And for another it stops a crashing process from affecting other processes that run on the machine. You can kill a process with Task Manager and everything keeps motoring along happily as though nothing happened.
A consequence of this is that creating a SAPConnection object in your program is a connection that only your program can use. There is no mechanism to somehow pass this object to another process with UI Automation. At best you could use the data you retrieve from the connection to affect what buttons you click.
The kind of process interop that would allow sharing data between processes is well supported in .NET. Low-level approaches are socket and named pipes, high-level are Remoting and WCF. Older programs have COM Automation support, Office is a good example of that. That however requires two to tango, both programs must be written to take advantage of it.
So if you are trying to automate an existing SAP application and this app does not otherwise explicitly support automation, the kind that an Office program supports, then you are pretty much stuck with just filling text boxes and clicking buttons.
You can automate any kind of application (browser, desktop, java, etc) with UiPath.
Here's a tutorial on how to automate data entry, menu navigation and screen scraping on SAP.
You can
use it from code (SDK). It has a tool that auto-generates C# code
create and run workflows (visual automation) directly from UiPath Studio.
Here's a sample of the C# auto-generated code:
// Attach window menu
UiNode wnd3 = UiFactory.Instance.NewUiNode().FromSelector("<wnd app='sap business one.exe' cls='#32768' idx='1' />");
// Click 'Business Pa...' menu
UiNode uiClickBusinessPamenu_3 = wnd3.FindFirst(UiFindScope.UI_FIND_DESCENDANTS, "<ctrl name='Business Partners' role='popup menu' /><ctrl automationid='2561' />");
uiClickBusinessPamenu_3.Click(88, 9, UiClickType.UI_CLICK_SINGLE, UiMouseButton.UI_BTN_LEFT, UiInputMethod.UI_HARDWARE_EVENTS);
// Attach window 'SAP Business'
UiNode wnd4 = UiFactory.Instance.NewUiNode().FromSelector("<wnd app='sap business one.exe' cls='TMFrameClass' title='SAP Business One 9.0 - OEC Computers' />");
// Click 'Add' button
UiNode uiClickAddbutton_4 = wnd4.FindFirst(UiFindScope.UI_FIND_DESCENDANTS, "<wnd cls='ToolbarWindow32' title='View' /><ctrl name='View' role='tool bar' /><ctrl name='Add' role='push button' />");
uiClickAddbutton_4.Click(13, 24, UiClickType.UI_CLICK_SINGLE, UiMouseButton.UI_BTN_LEFT, UiInputMethod.UI_HARDWARE_EVENTS);
Here's how workflow automation of SAP Business One menus, buttons or typing looks like:
And finally the SDK documentation is located here... in case you don't want to use workflows.
Note: I work at UiPath. You should also try other automation tools like Automation Anywhere, WinAutomation, Jacada, Selenium, Ranorex use them side by side and choose the one that suits better your needs.
I have c# code behind my Excel-dna addin which is successfully downloading data from a service. I have created a ribbon in Excel-dna with a button which triggers the download, and now I want to display the data in a new worksheet. How do I create a worksheet and add rows?
I tried calling xlcWorkbookInsert from my c# code using:
ExcelReference newSheet = (ExcelReference)XlCall.Excel(XlCall.xlcWorkbookInsert, 1);
but I always get a ExcelDna.Integration.XlCallException exception. Is this the correct approach, or is there a simpler way to go about doing this?
I also tried pasting an object[,] of data to an existing sheet:
ExcelReference sheet1 = (ExcelReference)XlCall.Excel(XlCall.xlSheetId, "Sheet1");
ExcelReference myTargetPasteArea = new ExcelReference(1, 1, 2, 10, sheet1.SheetId);
myTargetPasteArea.SetValue(result);
There are no errors this time, but nothing happens (although I can see the code being executed when I step through in debug).
Your code is calling to Excel via the C API (that's how the XlCall.Excel(...) and ExcelReference stuff in Excel-DNA works). But you can't call the C API directly from your ribbon event handler. You have two options:
Make a detour via a macro. This is easy if you change your ribbon xml code:
<button onAction="RunTagMacro" tag="MyMacro" />
and then define a macro:
public static void MyMacro()
{
// ... do your work here ....
}
You can also call the macro yourself from the event handler - the RunTagMacro internally just calls
object app = ExcelDnaUtil.Application;
app.GetType().InvokeMember("Run", BindingFlags.InvokeMethod,
null, app, new object[] { control.Tag }, new CultureInfo(1033));
Another option is to change your interaction code to use the COM API. For this you'll need to use the 'dynamic' support in .NET 4, or reference an interop assembly - either the version-specific Primary Interop Assemblies for Office, or some version-independent interop assemblies like NetOffice.
XlCall.Excel(XlCall.xlcWorkbookInsert, 1);
returns a bool: true - success, false - failure
So casting it to ExcelReference is the cause of the exception.
You may need an xlcNew before that xlcWorkbookInsert. Take a look in the Excel-Dna source at the GetApplication method in Excel.cs.
I wrote a VSTO Excel addin using Visual Studio 2010 and after having managed to work around most of the obstacles Microsoft throws into the path of the righteous developer, I finally have to admit defeat.
My project contains a Ribbon with some controls, a custom task pane that allows users to search a database via a RESTful interface and a RTD server that lets them put this data in their worksheets. So far, so ... well, painful, I guess: After a lot of struggle with Interop, ComVisibility and AppDomains (what a great idea!), my current status is as follows.
In the worksheets, I call a wrapper function for RTD like this (snipped):
Public Function call(value as String)
Dim addin as Office.ComAddIn
Set addin = Application.ComAddIns("MyAddin")
addin.Object.RTD(value)
End Function
This is (part of) the addin class:
namespace Some
{
[Guid("...")]
[ComVisibleAttribute(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class MyAddin {
[snip]
public String RTD(String value)
{
String returner = null;
try
{
returner = Globals.ThisAddin.Application.WorksheetFunction.RTD(SERVERID, "", value);
}
catch(COMException ce)
{
returner = ce.StackTrace;
}
return returner;
}
}
}
And the relevant part of the RTD Server class:
namespace Some
{
[Guid("...")]
[ComVisibleAttribute(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("MyRTDServer")]
public class Server : Excel.IRtdServer
{
[snip]
}
}
In Debug mode I:
Create a, empty new workbook
Add an "=RTD(...)" formula to a cell
Add a wrapper function call "=call(...)" to a cell
Save the workbook
Open the workbook
Stop Debugging and start it again
Open the workbook
I observe:
At 3, everything works fine
At 5, everything works fine
At 7, when recalculating my cells, I get a Unable to get the RTD property of the WorksheetFunction class exception in the cell of 3) and #N/A in the cell of 2). However, I can see that the topics are registered in the RTD server and as soon as the data is available, the exception is replaced with the correct data. Also, if I do NOT recalculate the cells, they display the saved value and then correctly update to the retrieved value once the data is available.
If in deployed mode, I observe:
At 2, I get #N/A
At 3, I get a Unable to get the RTD property of the WorksheetFunction class exception
Any help, please? :(
EDIT:
Testing the same procedure with a very basic RTD server in a blank Addin project shows exactly the same results: a loaded excel file displays #N/A if an RTD-formula is recalculated before the server has the data available.
I would like to inquire: WTF?
Cheers,
Che
The 'Unable to get the RTD property....' error is just the Excel object model's way of saying there was an error in the function call.
Does your RTD server have any dependencies on the rest of your add-in? The fact that 2) fails when deployed, makes it look like the RTD server needs some other bits to be initialized before it runs happily. The way the VSTO add-in is put together, your assembly is likely to be loaded totally separately for the RTD server and for the COM add-in, and in your problematic cases the RTD instance is loaded first.
Perhaps you can test with a sample RTD server instead of your own, just to confirm that the error is there and not in the wrapper or elsewhere in the VSTO add-in. Then you can dig into your RTD server to see what goes wrong.
-Govert
Excel-DNA - Free and easy .NET for Excel