I'm trying to create a program in C# that should be able to create, backup and restore a SQL Server database.
For this, the user needs to be able to setup a connection string to the desired SQL Server (and database).
I would like to use the same dialog as for example Visual Studio for creating the connection string.
Is this possible?
The data connection dialog component linked to in this answer is no longer available for download.
However, a (apparently somewhat altered) DataConnectionDialog component has since become available on NuGet.
Installation:
Add the component to your Visual Studio project via the NuGet package manager console:
Install-Package DataConnectionDialog
Usage example:
// using Microsoft.Data.ConnectionUI;
// using System.Windows.Forms;
bool TryGetDataConnectionStringFromUser(out string outConnectionString)
{
using (var dialog = new DataConnectionDialog())
{
// If you want the user to select from any of the available data sources, do this:
DataSource.AddStandardDataSources(dialog);
// OR, if you want only certain data sources to be available
// (e.g. only SQL Server), do something like this instead:
dialog.DataSources.Add(DataSource.SqlDataSource);
dialog.DataSources.Add(DataSource.SqlFileDataSource);
…
// The way how you show the dialog is somewhat unorthodox; `dialog.ShowDialog()`
// would throw a `NotSupportedException`. Do it this way instead:
DialogResult userChoice = DataConnectionDialog.Show(dialog);
// Return the resulting connection string if a connection was selected:
if (userChoice == DialogResult.OK)
{
outConnectionString = dialog.ConnectionString;
return true;
}
else
{
outConnectionString = null;
return false;
}
}
}
Note: The dialog component referred to below is no longer available for download. Unless you have retrieved it in the past, you will probably not get this answer's sample code to work.
Alternative: There is now a different DataConnectionDialog available on
NuGet. See this answer for details.
"Data Connection Dialog" on MSDN Archive Gallery (broken as of 1 Sept. 2015)
The data connection dialog is a database tool component released with Visual Studio. It allows users to build connection strings and to connect to specific data sources. try this..
C# Sample:
static void Main(string[] args)
{
DataConnectionDialog dcd = new DataConnectionDialog();
DataConnectionConfiguration dcs = new DataConnectionConfiguration(null);
dcs.LoadConfiguration(dcd);
if (DataConnectionDialog.Show(dcd) == DialogResult.OK)
{
// load tables
using (SqlConnection connection = new SqlConnection(dcd.ConnectionString))
{
connection.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM sys.Tables", connection);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader.HasRows);
}
}
}
}
dcs.SaveConfiguration(dcd);
}
Here source code also available. we can integrate and redistribute the source code with our application according to license.
Yes and no.
Yes, it is technically possible, but I urge you not to; that dialog is part of Visual Studio and is lot listed in "redist". My interpretation is that you are not free to redistribute this dll.
I think all the other answers here are out-of-date, but I found a current solution at code.msdn.microsoft.com:
Using Microsoft Visual Studio Connection Dialog at runtime
In Visual Studio when a developer wants to create strong typed classes for database tables either for the conventional TableAdapter or Entity Framework there is a place in the process where a dialog is displayed as shown below. I will show you how to do this at runtime and a bit more.
The download is a solution that builds the following dlls:
Microsoft.Data.ConnectionUI.Dialog.dll
Microsoft.Data.ConnectionUI.dll
Microsoft.Data.DataConnectionConfiguration.dll
The solution also contains a sample application showing how to use them.
Worked a treat for me and it is super easy.
You can use UDL file.
Configuring Data Controls to Use Universal Data Link (.udl) Files
You can use SQLConnectionStringUI Nuget package.
I created some code that will do this. The code is in GitHub and you can learn about it here: https://csharpdeveloper.wordpress.com/2020/05/07/a-c-net-dialog-for-connecting-to-sql-server/
Lin
Create your own form similar to Server Explorer Connection Setting window, and implement it. You cannot use that form meant for VS
Related
I've encountered a problem when I try to retrieve the valid states of all features within an MSI package using the Microsoft.Deployment.WindowsInstaller.Installer class.
I want to copy the ValidStates property of each FeatureInfo within a Session. However when doing so I get a "Handle is in an invalid state." exception.
If I print each of these values out using Console.WriteLine() or step through the code in Visual Studio there is no exception.
I am at a loss as to what is preventing me from doing this.
Thanks in advance!
My Code:
var featureDictionary = new Dictionary<string, string[]>();
if (string.IsNullOrWhiteSpace(mPath))
return featureDictionary;
try
{
Installer.SetInternalUI(InstallUIOptions.Silent);
using (var session = Installer.OpenPackage(mPath, true))
{
foreach (var feature in session.Features)
{
try
{
var states = feature.ValidStates.Select((state) => state.ToString());
featureDictionary.Add(feature.Name, states.ToArray());
}
catch (InstallerException ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}
catch (InstallerException) { }
return featureDictionary;
The basic problem appears to be that you are opening the MSI as a file. Since you haven't posted its declaration, or how it is set, I'm assuming that mpath means it's a path to the file. Your OpenPackage method parameters seem to indicate this too. You're getting that error because you are trying to open the MSI file as a file during the actual install, and failing.
The way to get hold of the database for the running install is to use Session.Database.
You can't open the running MSI as a file during the install perhaps for the same reason you can't run an MSI file that you have open with Orca, a simple file sharing violation. When you step through with Visual Studio you're simply accessing the static file and getting default values and the file isn't being used for an install. The other issue is that there can only be one Session object per process (as the OpenPackage docs say) and you are attempting to get a second one while there is already a Session object associated with the handle of the install.
As a custom action it needs to be sequenced after CostFinalize.
Windows Installer conditional expressions such as !feature-state will tell you what state the feature is in, because it's usually better to avoid code where Windows Installer will just give you the answer.
I am new in C# and I have a problem connecting to a Firebird database. I want my program to access a Firebird Database [FDB format file]. I have problem, see the code below:
File.Copy(pathway, new_pathway, true);
FbConnection addDetailsConnection = new FbConnection("User=sysdba;Password=masterkey;Dialect=3;Database= " + new_pathway +
";DataSource=localhost;" );
string SQLCOMMAND = " SELECT UOM FROM ST_ITEM_UOM WHERE CODE = 'ANT'";
addDetailsConnection.Open();
FbCommand readCommand = new FbCommand(SQLCOMMAND, addDetailsConnection);
FbDataReader myreader = readCommand.ExecuteReader();
while (myreader.Read())
{
MessageBox.Show(myreader[0].ToString());
}
myreader.Close();
readCommand.Dispose();
addDetailsConnection.Close();
addDetailsConnection.Dispose();
This code lets me read my FDB file and extract the data. When the code executes for the first time, there is no error or problem, However when when I execute it again, this error is shown:
The process cannot access the file 'C:\Users\ACC-0001.FDB' because it is being used by another process.
You can use Handle to check which program is locking the file. It might be caused by your code or by another process running on your machine.
The tool identifies the process, for example:
C:>handle.exe c:\test.xlsx
Handle v3.46 Copyright (C) 1997-2011 Mark Russinovich Sysinternals -
www.sysinternals.com
EXCEL.EXE pid: 3596 type: File 414: C:\test.xlsx
As found here.
If the problem lies within your code, make sure you dispose and close all connections, preferably by using them within using sections:
using (FbConnection addDetailsConnection = new FbConnection("..."))
{
// do work
}
More details on using using can be found here.
You might have bumped into this Firebird issue: FB server reports that DB file is used by another application on secondary attachment attempt through a symlink
It only happens on Windows and only when two non-embedded connections use different path names of which one or both have a symlink in their path so they effectively point to the same location.
Both handle.exe and Process Explorer will only show the canonical (final) filename that fbserver.exe actually opens.
The only way to find out is to:
compare connection strings.
verify with handle.exe or Process Explorer that the files are indeed opened by fbserver.exe (and not by your process itself using an embedded connection)
UPDATE: The code example below works. I changed the connection string. That was the problem. For an alternative (non-ADO) solution, see Mike Wills's link in the comments.
I have a c# class that (if I ever get it working) runs a program written in RPG code on AS/400 - JD Edwards. I know next to nothing about AS/400 and/or JD Edwards.
I've got other classes in my (intranet) web app that connect to JD Edwards, running SQL queries and setting/getting data. All of these are using the IBM.Data.DB2.iSeries dll and are working great.
For this, I wrote a similar class using the aforementioned dll, but it wasn't working. I even read somewhere online that you can't run a program using this dll. I found that a little fishy, but on suggestion from my JD Edwards co-worker, I scrapped the class and re-wrote it using the adodb dll. No data need be returned from this program run. I just want the program to run.
Here is a dummified version of the class:
private void runJDEProgram() {
ADODB.Connection cn = new ADODB.Connection();
cn.ConnectionString = "Provider=ABABAB;Data Source=111.111.111";
ADODB.Command cmdDetail = new ADODB.Command();
cn.Open(); //has to be open before setting an active connection.
cmdDetail.ActiveConnection=cn;
cmdDetail.CommandType = ADODB.CommandTypeEnum.adCmdText;
cmdDetail.CommandText = "{{CALL BLAH.BLAH(?,?)}}";
cmdDetail.Prepared = true;
cmdDetail.Parameters.Append(cmdDetail.CreateParameter("P1", ADODB.DataTypeEnum.adChar, ADODB.ParameterDirectionEnum.adParamInput, 10, "BLAH123"));
cmdDetail.Parameters.Append(cmdDetail.CreateParameter("P2", ADODB.DataTypeEnum.adChar, ADODB.ParameterDirectionEnum.adParamInput, 10, "BLAH456"));
object dummy = Type.Missing; //otherwise, we couldn't get past this.
cmdDetail.Execute(out dummy, ref dummy, 0);
cn.Close();
}
Here's the error I get when it runs:
{"[Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified"}
Where am I screwing up? Thanks!
EDIT: The connection string works when querying the AS/400 to get/set data. Does it need to be modified for an operation like this, or for use with ADO?
The connection string has to be different for this, for some reason. I don't use the same connection string for the other classes that just run queries. The above connection string worked fine (with the appropriate values, of course).
It will prompt for password, but the JDE folks here wanted that.
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.
Is it possible to retrieve data from chrome/firefox local storage using C#?
Disclaimer: I have tested this on my Windows 7 x64 running Google Chrome 13.0.782.220 at the moment. The information provided here is a result of my own research and is not any official way or API to retrieve this information. Use at your own risk. Also the technique presented here might break with any future release if Chrome changes the way to store this information.
So, Google Chrome uses SQLite to persist local storage data. You could use the System.Data.SQLite managed driver to read it from your .NET application. If you are running on Windows 7 (don't know for others as that's the one I have and can test), you will have the following folder:
c:\Users\SOMEUSERNAME\AppData\Local\Google\Chrome\User Data\Default\Local Storage\
This folder will contain multiple files with the .localstorage extension. Each file is for different site. For example for StackOverflow I have http_stackoverflow.com_0.localstorage but of course this naming is totally arbitrary and you cannot rely upon it. Each file represents a SQLite database.
I have noticed that this database contains a table called ItemTable with 2 string columns called key and value.
So to read the values it's a simple matter of sending a SQL query:
class Program
{
static void Main()
{
using (var conn = new SQLiteConnection("Data Source=http_stackoverflow.com_0.localstorage;Version=3;"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT key, value FROM ItemTable";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(
"key: {0}, value: {1}",
reader.GetString(reader.GetOrdinal("key")),
reader.GetString(reader.GetOrdinal("value"))
);
}
}
}
}
}
When using Chromium Embedded Framework I found that the above solution has many limitations. It seems like Chromium have moved to using leveldb instead.
I ended up with a solution where I inject JS code that modify local storage in FrameLoadStart. (it should be easy to read values as well - JavascriptResponse.Result can be casted to a IDictionary when using this script: "window.localStorage;" instead)
// writing local storage in FrameLoadStart
foreach (var entry in LocalStorage)
{
script += $"window.localStorage.{entry.Key} = '{entry.Value}';";
}
IFrame frame = chromeBrowser.GetMainFrame();
var result = await frame.EvaluateScriptAsync(script , frame.Url, 0);
if(!result.Success)
{
throw new Exception(result.Message);
}