1.根据SAPGUI应用程序名动态读取登录配置文件的绝对路径,如果应用程序未安装,则提示相应消息。
2. 根据获取的路径得到配置文件的XML文本字符串,其中包含所有的登录信息,调用上一篇日志解析XML的类方法,得到登录界面结构的文档实例
3.通过文档实例利用控件类动态生成控件的实例TreeView和ListView,作为窗体面板控件的子节点
4.TreeView和ListView联动控制,点击TreeView叶子节点动态加载ListView,点ListView中某一行项目,则根据该项的信息关联配置文件获的的数据信息,动态生成一个*.sap图标文件,并将相关信息构造成结构化字符串写入到*.sap登录文件中,
5.调用SapGui.exe可执行程序打开刚创建好的 *.sap文件,从而实现GUI动态登录;当然这个功能强大的地方不在于此,而是找到了一种不用修改底层数据文件和代码,直接通过前端UI操作来修改底层数据,实现想要的功能的方法
class Registry
{
public enum SoftName : short
{
SAPgui
}
public enum ConfigKeyName : short
{
ConnectionConfigFile, //D:\ProgramFiles\Java\Common\saplogon.ini
MessageServerConfigFile, //C:\WINDOWS\SAPMSG.INI
RouterConfigFile, //C:\WINDOWS\SAPROUTE.INI
ShortcutConfigFile, //D:\ProgramFiles\Java\Common\sapshortcut.ini
TreeConfigFile //D:\ProgramFiles\Java\Common\SapLogonTree.xml
}
private static int index;
public static string findApplicaiton(SoftName softName)
{
string strKeyName = string.Empty;
string softPath;
try
{
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.LocalMachine;
switch(softName)
{
case SoftName.SAPgui:
softPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\AppPaths\";
Microsoft.Win32.RegistryKey regSubKey = regKey.OpenSubKey(softPath +softName + ".exe", false);
object objResult = regSubKey.GetValue(strKeyName);
Microsoft.Win32.RegistryValueKind regValueKind =regSubKey.GetValueKind(strKeyName);
if (regValueKind == Microsoft.Win32.RegistryValueKind.String)
{
return objResult.ToString();
}
break;
default:
break;
}
}
catch
{
return "";
}
return "";
}
public static string findApplicationFile(SoftName softName, ConfigKeyName fileName)
{
index = 0;
if (findApplicaiton(softName) == "")
{
return "";
}
else
{
switch(softName)
{
case SoftName.SAPgui:
return getApplicationKeyInfo(softName, fileName);
//break;
default:
break;
}
}
return "";
}
private static string getApplicationKeyInfo(SoftName softName, ConfigKeyName fileName)
{
Microsoft.Win32.RegistryKey KeyNode;
string path;
string[] keyName;
switch (softName)
{
case SoftName.SAPgui:
KeyNode = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\SAP\SAPLogon");
keyName = KeyNode.GetSubKeyNames();
for (int i = index; i < keyName.Length; i++)
{
index = i;
if (keyName[i].Contains("ConfigFiles"))
{
path = (string)KeyNode.OpenSubKey(keyName[i]).GetValue(fileName.ToString());
if (path == null || path == "")
{
continue;
}
else
{
return path;
}
}
}
break;
default:
break;
}
return "";
}
}
class AnalyseKeyValueString
{
static Dictionary[]source;
static int index = 0;
static Regex regex = newRegex(@"[a-zA-Z0-9-\s]+?=(""(\s|\S)*?""|[^""]*?$)");
static MatchCollection matchCollection;
public static Dictionary[]getStruct(string str)
{
string[] keyvalue = new string[2];
string lable = "";
int num = getNum(str);
source = new Dictionary[num];
for (int i = 0;i < num; i++)
{
source[i] = new Dictionary();
}
string[] lines = str.Split(new char[] { '\r', '\n' },StringSplitOptions.RemoveEmptyEntries);
for (int i = 0;i < lines.Length; i++)
{
if(lines[i][0]=='[')
{
index = 0;
lable = lines[i].Substring(1, lines[i].Length - 2);
continue;
}
matchCollection = regex.Matches(lines[i]);
if(matchCollection.Count == 1)
{
keyvalue =matchCollection[0].Value.Split(newchar[] { '=' }, 2);
source[index].Add(lable, keyvalue[1]);
}
else if(matchCollection.Count > 1)
{
for (int j = 0; j < matchCollection.Count; j++)
{
keyvalue =matchCollection[j].Value.Split(newchar[] { '=' }, 2);
source[index].Add(keyvalue[0].Trim(), keyvalue[1].Replace("\"",""));
}
}
index++;
}
return source;
}
private static int getNum(string str)
{
return new Regex(@"([a-zA-Z0-9-\s]+?=(""(\s|\S)*?""|[^""^\[]*?\r\n)){2,}").Match(str).Value.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
1通过递归的方式将偏平的链表结构转为树状的深度链表结构
private List getNest(List ltag)
{
Listntag = new List();
tagNest subtag;
for (int i = 0;i < ltag.Count; i++)
{
subtag = new tagNest();
subtag.tagName = ltag[i].tagName;
subtag.Attribute = ltag[i].Attribute;
subtag.subtag = getNest(Ltag.FindAll(s =>s.parentKey.Equals(ltag[i].Key)));
ntag.Add(subtag);
}
return ntag;
}
public void plain2nest()
{
Ntag = getNest(new List() { Ltag[0] });
}
2.根据获取的深度链表动态创建TreeView节点
///
/// 初始化时用
///
///
public void addToAplicationViewTree()
{
getStruct();
plain2nest();
TreeNode node;
TreeNode subNode;
ListNodes = Ntag[0].subtag[1].subtag[1].subtag;
for (int i = 0;i < Nodes.Count; i++)
{
node = aplicationView.treeView1.Nodes.Add(Nodes[i].tagName);
node.SelectedImageIndex = node.ImageIndex = 2; //设置选中后的图片和选中前的一致
for (int j = 0; j < Nodes[i].subtag.Count; j++)
{
Nodes[i].subtag[j].tagName= Nodes[i].subtag[j].Attribute["name"].ToString().Replace("\"","");
subNode = node.Nodes.Add(Nodes[i].subtag[j].tagName);
subNode.SelectedImageIndex = subNode.ImageIndex = 3;
}
}
}
3.根据点击TreeView不同层级的节点响应不同的方法,叶子动态加载ListView
///
/// 点击Tree Node时调用
///
/// 要展示的地方,提前已经创建好了Header
/// Node节点名称
internal void addToAplicationViewList(TreeNode treeNode)
{
Dictionary detail;
if (treeNode.Level == 0)
{
if(treeNode.IsExpanded)
{
treeNode.Collapse();
treeNode.ImageIndex = 2;
treeNode.SelectedImageIndex = 2;
}
else
{
treeNode.Expand();
treeNode.ImageIndex = 1;
treeNode.SelectedImageIndex = 1;
}
}else if (treeNode.Level == 1)
{
aplicationView.listView1.Items.Clear();
tagNestnodes = Ntag[0].subtag[1].subtag[1].subtag.Find(s =>s.tagName.Equals(treeNode.Parent.Text)).subtag.Find(j =>j.tagName.Equals(treeNode.Text));
aplicationView.listView1.BeginUpdate(); //数据更新,UI暂时挂起,直到EndUpdate绘制控件,可以有效避免闪烁并大大提高加载速度
switch(treeNode.Parent.Text)
{
case "Favorites":
aplicationView.nodeStyle = AplicationView.NodeStyle.Favorites;
break;
case "Shortcuts":
aplicationView.nodeStyle = AplicationView.NodeStyle.Shortcuts;
//tagNest nodes =Ntag[0].subtag[1].subtag[1].subtag.Find(s=>s.Attribute.First(q=>q.Value== ""))
aplicationView.listView1.Columns.Clear();
aplicationView.listView1.Columns.Add("名称", 120, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("描述", 150, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("系统", 60, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("集团", 60, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("账号", 100, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("事务代码", 60, HorizontalAlignment.Left);
for (int i = 0; i < nodes.subtag.Count; i++)
{
nodes.subtag[i].tagName = nodes.subtag[i].Attribute["name"].ToString().Replace("\"", "");
ListViewItem lvi = new ListViewItem();
lvi.ImageIndex = 4; //通过与imageList绑定,显示imageList中第i项图标
lvi.Text =nodes.subtag[i].tagName;
detail =aplicationView.listViewDetailShortcuts.First((s) => s["Label"] == lvi.Text);
lvi.SubItems.Add(detail["-desc"]);
lvi.SubItems.Add(detail["-sid"]);
lvi.SubItems.Add(detail["-clt"]);
lvi.SubItems.Add(detail["-u"]);
lvi.SubItems.Add(detail["-cmd"]);
aplicationView.listView1.Items.Add(lvi);
}
break;
case "Connections":
aplicationView.nodeStyle = AplicationView.NodeStyle.Connections;
aplicationView.listView1.Columns.Clear();
aplicationView.listView1.Columns.Add("名称", 180, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("服务器地址", 180, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("系统编号", 60, HorizontalAlignment.Left);
aplicationView.listView1.Columns.Add("系统标识", 60, HorizontalAlignment.Left);
for (int i = 0; i < nodes.subtag.Count; i++)
{
nodes.subtag[i].tagName = nodes.subtag[i].Attribute["name"].ToString().Replace("\"", "");
ListViewItem lvi = new ListViewItem();
lvi.ImageIndex = 4; //通过与imageList绑定,显示imageList中第i项图标
lvi.Text =nodes.subtag[i].tagName;
detail =aplicationView.listViewDetailConnections.First((s) => s["Description"] == lvi.Text);
lvi.SubItems.Add(detail["Server"]);
lvi.SubItems.Add(detail["Database"]);
lvi.SubItems.Add(detail["MSSysName"]);
aplicationView.listView1.Items.Add(lvi);
}
break;
default:
break;
}
aplicationView.listView1.EndUpdate(); //结束数据处理,UI界面一次性绘制。
}
}
public partial class AplicationView : Form
{
AnalyseXML analyseXML;
Form1 form1;
string configfilename="";
int edition = 0;
Dictionary items;
public Dictionary[]listViewDetailShortcuts;
public Dictionary[]listViewDetailConnections;
public enum NodeStyle
{
None,
Favorites,
Shortcuts,
Connections,
}
public NodeStyle nodeStyle;
public AplicationView(Form1 form1)
{
this.form1 = form1;
InitializeComponent();
}
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
analyseXML.addToAplicationViewList(e.Node);
}
private void AplicationView_Load(object sender, EventArgs e)
{
this.listView1.View = View.Details;
this.listView1.MultiSelect = false;
this.listView1.HeaderStyle = ColumnHeaderStyle.Clickable;
this.listView1.LabelEdit = false;
this.listView1.FullRowSelect = true;
string txtpath = Registry.findApplicationFile(Registry.SoftName.SAPgui, Registry.ConfigKeyName.TreeConfigFile);
//MessageBox.Show(FileProcess.readContent(a));
analyseXML = new AnalyseXML(FileProcess.readContent(txtpath,Encoding.UTF8),this);
analyseXML.addToAplicationViewTree();
listViewDetailShortcuts = AnalyseKeyValueString.getStruct(FileProcess.readContent(Registry.findApplicationFile(Registry.SoftName.SAPgui, Registry.ConfigKeyName.ShortcutConfigFile),Encoding.GetEncoding("GB2312")));
listViewDetailConnections = AnalyseKeyValueString.getStruct(FileProcess.readContent(Registry.findApplicationFile(Registry.SoftName.SAPgui, Registry.ConfigKeyName.ConnectionConfigFile),Encoding.GetEncoding("GB2312")));
}
//ConnectSAPconnectSAP;
string fileContent;
private void listView1_Click(object sender, EventArgs e)
{
string[] paths =null;
int selectCount = this.listView1.SelectedItems.Count;
if (selectCount > 0)
{
switch(nodeStyle)
{
case NodeStyle.None:
break;
case NodeStyle.Favorites:
break;
case NodeStyle.Shortcuts:
items =listViewDetailShortcuts.First(s => s["-desc"].Equals(this.listView1.SelectedItems[0].SubItems[1].Text));
FileProcess.SubFolderCheckOrCreate(Application.StartupPath, "LoginConfig");
try
{
configfilename = Regex.Replace(items["-desc"], "[/:*?\"<>|]", match => { return "_";}) + this.listView1.SelectedItems[0].SubItems[3].Text;
paths = Directory.GetFiles(Application.StartupPath + "\\LoginConfig", configfilename + "*.sap", SearchOption.TopDirectoryOnly);
}
catch (Exception)
{
}
if (null != paths && paths.Length > 0)
{
edition = Convert.ToInt32(Path.GetFileNameWithoutExtension(paths[0]).Substring(configfilename.Length+ 1)) + 1;
File.Delete(paths[0]);
}
else
{
edition = 1;
}
fileContent = "[System]\r\nName=" + this.listView1.SelectedItems[0].SubItems[2].Text+ "\r\nDescription=" + this.listView1.SelectedItems[0].SubItems[1].Text+ "\r\nClient=" + this.listView1.SelectedItems[0].SubItems[3].Text+ "\r\n[User]\r\nName=" + this.listView1.SelectedItems[0].SubItems[4].Text+ "\r\nLanguage=" + items["-l"] + "\r\nPassword=" + items["-pwenc"] + "\r\n[Function]\r\nTitle=" + configfilename + "_" + edition + "\r\nCommand=" + items["-cmd"] + "\r\n[Configuration]\r\nWorkDir=" + items["-wd"] + "\r\n[Options]\r\nReuse=1\r\n";
FileProcess.CreateFormatplainFile("LoginConfig\\" + configfilename + "_" + edition + ".sap", fileContent);
break;
case NodeStyle.Connections:
break;
default:
break;
}
Process.Start(Application.StartupPath + "\\LoginConfig\\" + configfilename + "_"+ edition + ".sap");
//connectSAP = new ConnectSAP(this.form1);
//connectSAP.ShiLianSystem();
}
}
using SAP.Middleware.Connector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WritePlane
{
class ConnectSAP
{
RfcDestination rfcDest;
RfcConfigParameters Parms;
RfcRepository rfcrep;
IRfcFunction func;
string FFMName;
string InputName;
string OutputName;
public class ConnectStruct
{
public ConnectStruct(bool p_isconnect, bool p_isconnectsuccessful, string p_connectinfo)
{
isconnect = p_isconnect;
isconnectsuccessful = p_isconnectsuccessful;
connectinfo = p_connectinfo;
}
public bool isconnect = false;//连接状态:true正在连接,false连接结束
public bool isconnectsuccessful = false;//是否成功连接,ture成功,false失败
public string connectinfo = "WithoutConnection";//连接信息
};
ConnectStruct connstru;
delegate void SetTextCallback(ConnectStruct info);//具有一个传入参数的委托
Funcfunc_sys;
Funcfunc_rfm;
IAsyncResult cookie;
Form1 form1;
public ConnectSAP(Form1form1)
{
this.form1 = form1;
}
public void ShiLianSystem()
{
form1.toolStripStatusLabel1.Text = "Wait...";
connstru = new ConnectStruct(false, false, "WithoutConnection");
RfcConfigParameters parms = new RfcConfigParameters();
parms.Add(RfcConfigParameters.Name, "ED1");
parms.Add(RfcConfigParameters.AppServerHost, "XX.XX.XX.XXX");
parms.Add(RfcConfigParameters.SystemNumber, "XX");
parms.Add(RfcConfigParameters.Client, "XXX");
parms.Add(RfcConfigParameters.User, "XXXXXXX");
parms.Add(RfcConfigParameters.Password, "XXXXXXXXXX");
parms.Add(RfcConfigParameters.Language, "ZH");
parms.Add(RfcConfigParameters.PoolSize, "1");
//parms.Add(RfcConfigParameters.,"10");
parms.Add(RfcConfigParameters.IdleTimeout, "1");
parms.Add(RfcConfigParameters.MaxPoolWaitTime, "1");
parms.Add(RfcConfigParameters.SAPRouter, "XXXXXXXXXXXXX");
FFMName = "ZZTEST_WEBSERVICE_02";
InputName = "ZZIMSEG";
OutputName = "ZZEMSEG";
this.SetConnectandRFM(parms);
//this.SetRFM("ZZTEST_WEBSERVICE_02");
//RfcDestinationrfcDest;
//rfcDest =RfcDestinationManager.GetDestination(parms);
//RfcRepository rfcrep= rfcDest.Repository;
//IRfcFunction func =rfcrep.CreateFunction("ZPPRFM005");//RFM名称
//func.SetValue("I_USAGE","1");//SAP里面的传入参数
//func.SetValue("I_STATUS","4");
//func.SetValue("I_UNIT","EA");
//func.SetValue("I_ACTION","1");
//func.Invoke(rfcDest);
//IRfcTable IrfTable =func.GetTable("IT_ROUTING"); //提前实例化一个空的表结构出来
//IRfcStructure IrfStru =func.GetStructure("E_MESSAGE"); //提前实例化一个空的表结构出来
//string a=IrfStru.GetString("ID");
//DataTable dt = newDataTable();
//dt.Columns.Add("ID");
//dt.Columns.Add("ZBX");
//dt.Columns.Add("MESSAGE");
循环把IRfcTable里面的数据放入Table里面,因为类型不同,不可直接使用。
//for (int i = 0; i< IrfStru.Count; i++)
//{
// IrfTable.CurrentIndex = i;
// DataRow dr = dt.NewRow();
// dr["ID"] =IrfStru.GetString("ID");
// dr["ZBX"] =IrfStru.GetString("ZBX");
// dr["MESSAGE"] =IrfStru.GetString("MESSAGE");
// dt.Rows.Add(dr);
//}
将重新生成的Table赋值给数据控件DataGridView。
//dataGridView1.DataSource= dt;
}
public string ExecuteRFM( string i_param)
{
//先检查服务器是否连接成功(需要检查服务器是否真正连接),不成功不允许调用参数
if (connstru.isconnect == false)
{
return "正在连接RFM中,请勿重复点击,当然我也不会处理!";//正在连接中,直接返回,不让调用RFC函数
}
else
{
if(connstru.isconnectsuccessful == false)
{
return "连接RFM失败,请勿重复点击,当然我也不会处理!";//连接失败,直接返回,不让调用RFC函数
}
}
func.SetValue(InputName, i_param);//SAP里面的传入参数
func.Invoke(rfcDest);
//returnfunc.GetValue(1).ToString();
return func.GetString(OutputName);
}
//public DataTableGetSAPData(DataTable dt)
//{
// DataTable dtSAPData = new DataTable();
// String str1, str2, str3;
// try
// {
// //向数据库中添加字段
// dtSAPData.Columns.Add("DATA1", typeof(string));
// dtSAPData.Columns.Add("DATA2", typeof(string));
// dtSAPData.Columns.Add("DATA3", typeof(string));
// string strOrder = null;
// IRfcTable tSAP =func.GetTable("IT_ROUTING");
// for (int i = 0; i < dt.Rows.Count;i++)
// {
// str1 = dt.Rows[i][0].ToString();
// str2 = dt.Rows[i][1].ToString();
// str3 = dt.Rows[i][2].ToString();
// IRfcStructure struSAP =tSAP.Metadata.LineType.CreateStructure();
// struSAP.SetValue("str1",str1);
// struSAP.SetValue("str2",str2);
// struSAP.SetValue("str3",str3);
// tSAP.Append(struSAP);
// }
// func.SetValue("INPUT_TABLE",tSAP); //table 参数
// func.SetValue("WERKS","A"); //单个参数
// func.SetValue("STATUS","B"); //单个参数
// func.Invoke(_rfcDest);
// IRfcTable SAPDataTable =func.GetTable("RETURN_TABLE");
// for (int i = 0; i s.Name.Equals(name)) != null)//如果数据仓库中找到函数名为name的对象,则不设置函数
{
return;
}
FFMName = name;
InputName = inputname;
OutputName = outputname;
func_rfm = SetRFM;//泛型func设置了一个返回参数,不能用Acion
cookie = func_rfm.BeginInvoke((IAsyncResult res) => { this.SetLableText(func_rfm.EndInvoke(cookie)); }, null);//回调函数,当异步调用完成之后触发,第二个参数是传入参数
}
private ConnectStruct SetRFM()
{
try
{
func = rfcrep.CreateFunction(FFMName);//RFM名称
}
catch (Exceptionex)
{
return new ConnectStruct(true, false, ex.ToString());
}
return new ConnectStruct(true, true, "ConnectRFM successful!");
}
public void SetConnectandRFM(RfcConfigParameters param)
{
Parms = param;
func_sys = SetConnectandRFM;//泛型func设置了一个返回参数,不能用Acion
cookie = func_sys.BeginInvoke((IAsyncResult res) => { this.SetLableText(func_sys.EndInvoke(cookie)); }, null);//回调函数,当异步调用完成之后触发,第二个参数是传入参数
}
private ConnectStruct SetConnectandRFM()
{
try
{
rfcDest = RfcDestinationManager.GetDestination(Parms);
rfcrep = rfcDest.Repository;
func = rfcrep.CreateFunction(FFMName);//RFM名称
}
catch (Exceptionex)
{
return new ConnectStruct(true, false, ex.ToString());
}
return new ConnectStruct(true, true, "Connectsuccessful!");
}
private void SetLableText(ConnectStruct info)
{
// InvokeRequiredrequired compares the thread ID of the
// calling thread tothe thread ID of the creating thread.
// If these threadsare different, it returns true.
if (this.form1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetLableText);
this.form1.Invoke(d,new object[] { info });
}
else
{
this.form1.toolStripStatusLabel1.Text+= "\r\n" + info.connectinfo;
connstru = info;
}
}
}
}