欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据

程序员文章站 2022-05-26 11:13:20
...

0.1.1.     目的

为什么要做?

在做接口的时候,多个系统的数据交互,要求对各种字段和表关联比较熟悉,比如这个字段来自哪张表,它使用的数据元素是什么,它是否有固定值,是否有搜索帮助,对应的表有哪些主键。如果对表和字段不熟悉,就要频繁的使用SE11去查询和验证每一个字段是否在对应的表中存在,对于初学者而言,如果不了解SAP系统,则会花费很多时间在找表、验证表等毫无意义和重复性工作之中。

做了什么?

为了解决这个问题,我用C#写了一个内嵌EXCEL的应用程序,通过微软提供的OFFICE类库创建了内嵌的EXCEL,可以直接像操作EXCEL一样操作内嵌的EXCEL,操作EXCEL的每一个事件几乎都能在程序中捕捉到,该程序具有很大的可扩展性。

怎么做的?

将需要查询的表名、字段名、数据元素名、域名填在程序自动生成的模板EXCEL中,点击“获取”,程序会获取EXCEL输入的数据并转换为JSON,将构建好的动态程序JSON结构和参数JSON组成二重JSON传到SAP系统;SAP对二重JSON进行解析,生成对应的类,方法和表结构,并动态调用类方法,将执行的结果重装为二重JSON传回C#;C#对回传的二重JSON进行解析,获取输出参数,并写入到内嵌EXCEL,然后可以对EXCEL数据进行二次操作并保存备份。

具体实现

 

0.1.1.    ABAP创建一个类,并正常调用

REPORT z14143_14.
CLASS da DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS: getrelationship IMPORTING i_json TYPE string
                                   EXPORTING o_json TYPE string.
ENDCLASS.

CLASS da IMPLEMENTATION.
  METHOD getrelationship.
*定义类型ty_field创建时间06.05.2018 01:28:21
    TYPES: BEGIN OF ty_field,
             tablename   TYPE dd03l-tabname,     "表名
             istable     TYPE dd03l-tabletype,     "是表?
             fieldname   TYPE dd03l-fieldname,    "字段名
             iskey       TYPE dd03l-keyflag,      "主键?
             elementname TYPE dd03l-rollname,  "数据元素
             checktable  TYPE dd03l-checktable, "检查表
             datatype    TYPE dd03l-datatype,     "数据类型
             length      TYPE dd03l-leng,           "长度
             decimals    TYPE dd03l-decimals,     "精度
             domainname  TYPE dd03l-domname,       "域名
             shlporigin  TYPE dd07t-ddtext,
             comptype    TYPE dd07t-ddtext,
           END OF ty_field.

    DATA:lt_field TYPE TABLE OF ty_field,
         ls_field TYPE ty_field.

    DATA:rt_tab TYPE RANGE OF dd03l-tabname,
         rt_fid TYPE RANGE OF dd03l-fieldname,
         rt_ele TYPE RANGE OF dd03l-rollname,
         rt_dom TYPE RANGE OF dd03l-domname.
    DATA:rs_tab LIKE LINE OF rt_tab,
         rs_fid LIKE LINE OF  rt_fid,
         rs_ele LIKE LINE OF  rt_ele,
         rs_dom LIKE LINE OF rt_dom.

    /ui2/cl_json=>deserialize( EXPORTING json = i_json pretty_name = /ui2/cl_json=>pretty_mode-none CHANGING data = lt_field ).
    LOOP AT lt_field INTO ls_field.
      IF ls_field-tablename IS NOT INITIAL.
        rs_tab-low = ls_field-tablename.
        TRANSLATE rs_tab-low TO UPPER CASE.
        rs_tab-option = 'EQ'.
        rs_tab-sign = 'I'.
        APPEND rs_tab TO rt_tab.
      ENDIF.

      IF ls_field-fieldname IS NOT INITIAL.
        rs_fid-low = ls_field-fieldname.
        TRANSLATE rs_fid-low TO UPPER CASE.
        rs_fid-option = 'EQ'.
        rs_fid-sign = 'I'.
        APPEND rs_fid TO rt_fid.
      ENDIF.

      IF ls_field-elementname IS NOT INITIAL.
        rs_ele-low = ls_field-elementname..
        TRANSLATE rs_ele-low TO UPPER CASE.
        rs_ele-option = 'EQ'.
        rs_ele-sign = 'I'.
        APPEND rs_ele TO rt_ele.
      ENDIF.

      IF ls_field-domainname IS NOT INITIAL.
        rs_dom-low = ls_field-domainname..
        TRANSLATE rs_dom-low TO UPPER CASE.
        rs_dom-option = 'EQ'.
        rs_dom-sign = 'I'.
        APPEND rs_dom TO rt_dom.
      ENDIF.
    ENDLOOP.

IF rt_tab is INITIAL and rt_fid is INITIAL and rt_ele is INITIAL and rt_dom is INITIAL.
      o_json = '请输入数据'.
      RETURN.
    ENDIF.

    SELECT dd03l~tabname AS tablename
    tabletype AS istable
    fieldname
    keyflag AS iskey
    rollname AS elementname
    checktable
    datatype
    leng AS length
    decimals
    dd03l~domname AS domainname
    dd07t_1~ddtext AS shlporigin
    dd07t_2~ddtext AS comptype
    FROM dd03l
    LEFT JOIN dd07t AS dd07t_1 ON dd07t_1~domname =  'SHLPORIGIN' AND dd07t_1~ddlanguage =  '1' AND dd07t_1~domvalue_l = dd03l~shlporigin
    LEFT JOIN dd07t AS dd07t_2 ON dd07t_2~domname =  'COMPTYPE' AND dd07t_2~ddlanguage =  '1' AND dd07t_2~domvalue_l = dd03l~comptype
    INTO TABLE lt_field
    WHERE dd03l~tabname IN rt_tab
    AND dd03l~fieldname IN rt_fid
    AND dd03l~rollname IN rt_ele
    AND dd03l~domname IN rt_dom
    AND dd03l~as4local = 'A'.

    IF lt_field IS NOT INITIAL.
      o_json = /ui2/cl_json=>serialize( data = lt_field compress = '' pretty_name = /ui2/cl_json=>pretty_mode-none ).
    ENDIF.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  DATA i_json TYPE string.
  DATA o_json TYPE string.
  i_json = '[{"tablename":"makt","istable":"","fieldname":"","iskey":"","elementname":"","checktable":"",' &&
      '"datatype":"","length":"","decimals":"","domainname":"","shlporigin":"","comptype":""}]'.

  CALL METHOD da=>getrelationship
    EXPORTING
      i_json = i_json
    IMPORTING
      o_json = o_json.
cl_demo_output=>display_json( o_json ).

实现的功能就是表名,字段名,数据元素名,域名的联合查询,

0.1.2.    改写成JSON

C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据

0.1.3.    C#主要程序

0.1.3.1.    创建一个连接SAP系统的类

usingSAP.Middleware.Connector;

using System;

usingSystem.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace SAPconnector

{

    classConnectSAP

    {

        RfcDestination rfcDest;

        RfcConfigParameters Parms;

        RfcRepository rfcrep;

        IRfcFunction func;

        string FFMName;

        string InputName;

        string OutputName;

        publicclassConnectStruct

        {

            public ConnectStruct(bool p_isconnect, bool p_isconnectsuccessful,string p_connectinfo)

            {

                isconnect = p_isconnect;

                isconnectsuccessful =p_isconnectsuccessful;

                connectinfo = p_connectinfo;

            }

            publicbool isconnect =false;//连接状态:true正在连接,false连接结束

            publicbool isconnectsuccessful =false;//是否成功连接,ture成功,false失败

            publicstring connectinfo ="Without Connection";//连接信息

        };

 

        ConnectStruct connstru;

        delegatevoidSetTextCallback(ConnectStruct info);//具有一个传入参数的委托

        Func<ConnectStruct> func_sys;

        Func<ConnectStruct> func_rfm;

        IAsyncResult cookie;

 

        Form1 form1;

        public ConnectSAP(Form1 form1)

        {

            this.form1 = form1;

        }

        publicvoid XXXXXSystem()

        {

            form1.label1.Text ="Wait...";

            connstru =newConnectStruct(false,false,"Without Connection");

 

            RfcConfigParameters parms =newRfcConfigParameters();

 

            parms.Add(RfcConfigParameters.Name,"XXX");

            parms.Add(RfcConfigParameters.AppServerHost,"XXXXXXXXXXXXXX");

            parms.Add(RfcConfigParameters.SystemNumber,"XX");

            parms.Add(RfcConfigParameters.Client,"XXX");

            parms.Add(RfcConfigParameters.User,"XXXXXXXX");

            parms.Add(RfcConfigParameters.Password,"XXXXXXXXXXXX");

            parms.Add(RfcConfigParameters.Language,"XX");

            parms.Add(RfcConfigParameters.PoolSize,"X");

            parms.Add(RfcConfigParameters.PeakConnectionsLimit,"XX");

            parms.Add(RfcConfigParameters.IdleTimeout,"X");

            parms.Add(RfcConfigParameters.MaxPoolWaitTime,"X");

            parms.Add(RfcConfigParameters.SAPRouter,"XXXXXXXXXXXXXX");

            FFMName ="ZZTEST_WEBSERVICE_02";

            InputName ="ZZIMSEG";

            OutputName ="ZZEMSEG";

            this.SetConnectandRFM(parms);

        }

 

        publicstring 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);

            //return func.GetValue(1).ToString();

            return func.GetString(OutputName);

        }

        publicvoid SetRFM(string name,string inputname,string outputname)

        {

            if (rfcrep ==null)//如果没有创建数据对象仓库

            {

                return;

            }

            if (rfcrep.CachedFunctionMetadata.Count == 0)//如果数据仓库中没有添加函数对象

            {

                return;

            }

            if (rfcrep.CachedFunctionMetadata.Find(s =>s.Name.Equals(name)) !=null)//如果数据仓库中找到函数名为name的对象,则不设置函数

            {

                return;

            }

            FFMName = name;

            InputName = inputname;

            OutputName = outputname;

            func_rfm = SetRFM;//泛型func<out ConnectStruct>设置了一个返回参数,不能用Acion

            cookie = func_rfm.BeginInvoke((IAsyncResult res) => {this.SetLableText(func_rfm.EndInvoke(cookie));},null);//回调函数,当异步调用完成之后触发,第二个参数是传入参数

        }

        privateConnectStruct SetRFM()

        {

            try

            {

                func =rfcrep.CreateFunction(FFMName);//RFM名称

            }

            catch (Exception ex)

            {

                returnnewConnectStruct(true,false, ex.ToString());

            }

            returnnewConnectStruct(true,true,"Connect RFM successful!");

        }

        publicvoid SetConnectandRFM(RfcConfigParameters param)

        {

            Parms = param;

            func_sys = SetConnectandRFM;//泛型func<out string>设置了一个返回参数,不能用Acion

            cookie = func_sys.BeginInvoke((IAsyncResult res) => {this.SetLableText(func_sys.EndInvoke(cookie));},null);//回调函数,当异步调用完成之后触发,第二个参数是传入参数

        }

        privateConnectStruct SetConnectandRFM()

        {

            try

            {

                rfcDest =RfcDestinationManager.GetDestination(Parms);

                rfcrep = rfcDest.Repository;

                func =rfcrep.CreateFunction(FFMName);//RFM名称

            }

            catch (Exception ex)

            {

                returnnewConnectStruct(true,false, ex.ToString());

            }

            returnnewConnectStruct(true,true,"Connect successful!");

        }

        privatevoid SetLableText(ConnectStruct info)

        {

            // InvokeRequired required compares the thread IDof the

            // calling thread to the thread ID of the creatingthread.

            // If these threads are different, it returns true.

            if (this.form1.label1.InvokeRequired)

            {

                SetTextCallback d =newSetTextCallback(SetLableText);

                this.form1.Invoke(d,newobject[] { info });

            }

            else

            {

                this.form1.label1.Text +="\r\n"+ info.connectinfo;

                connstru = info;

            }

        }

    }

}


0.1.3.2.    在主类的载入事件中连接系统和获取数据仓库指定RFM

privatevoid Form1_Load(object sender, EventArgs e)

        {

            connectSAP =newConnectSAP(this);

            connectSAP.XXXXXSystem();

          System.Threading.Thread.Sleep(100);

          connectSAP.SetRFM("ZZTEST_WEBSERVICE_03","I_JSON","O_JSON");

            System.Threading.Thread.Sleep(100);

        }


0.1.3.3.    载入内嵌EXCEL的方法

        

private void载入表字段关联模板ToolStripMenuItem_Click(object sender, EventArgs e)

        {

            app =new Microsoft.Office.Interop.Excel.Application();

            if (app ==null)

            {

                return;

            }

            Workbooks workbooks = app.Workbooks;

            Workbook workbook = workbooks.Add(Type.Missing);

            worksheet = (Worksheet)workbook.Sheets[1];

            worksheet.Select();

           Range range1 =worksheet.get_Range("A1","L1");

            if (range1 ==null)

            {

                return;

            }

            object[,] tabdata =newobject[1, 12];

            tabdata[0, 0] ="表名";

            tabdata[0, 1] ="是表?";

            tabdata[0, 2] ="字段名";

            tabdata[0, 3] ="主键?";

            tabdata[0, 4] ="数据元素";

            tabdata[0, 5] ="检查表";

            tabdata[0, 6] ="数据类型";

            tabdata[0, 7] ="长度";

            tabdata[0, 8] ="精度";

            tabdata[0, 9] ="域名";

            tabdata[0, 10] ="搜索帮助类型";

            tabdata[0, 11] ="数据元素类型";

            range1.Value2 = (dynamic)tabdata;

            range1.Activate();

            IntPtr hwnd = (IntPtr)app.Hwnd;

           SetParent(hwnd,this.Filltable.Handle);

            MoveWindow((IntPtr)app.Hwnd,this.Filltable.ClientRectangle.Left,this.Filltable.ClientRectangle.Top+ 25, this.Filltable.ClientRectangle.Width,this.Filltable.ClientRectangle.Height- 25, false);

            app.EditDirectlyInCell =true;//设置单元格直接可编辑,无意中发现,否者只能双击单元格,十分麻烦

            app.DisplayAlerts =false;

            app.Visible =true;

        }

0.1.3.4.    内嵌EXCEL大小随着父容器大小变化而变化

private void Filltable_Resize(object sender, EventArgs e)

        {

            if (app !=null && (IntPtr)app.Hwnd !=IntPtr.Zero)

            {

                MoveWindow((IntPtr)app.Hwnd,this.Filltable.ClientRectangle.Left,this.Filltable.ClientRectangle.Top+ 25, this.Filltable.ClientRectangle.Width,this.Filltable.ClientRectangle.Height- 25, false);

           }

           

        }


0.1.3.5.    构建动态类方法的类结构

namespace SAPconnector

{

    classProgramStru

    {

        [JsonProperty("METHODS")]

        publicList<METHODSTRU> METHODS { get;set; }

        publicstructMETHODSTRU

        {

            publicstring METHODNAME {get;set; }

            publicList<PARAM> INPUTDATA { get;set; }

            publicList<PARAM> OUTPUTDATA { get;set; }

            publicstring BODY {get;set; }

        }

        publicstructPARAM

        {

            public string DATATYPE {get;set; }

            public string DATANAME {get;set; }

            publicstring DATAVALUE {get;set; }

        }

    }

}


 

0.1.3.6.    获取和处理内嵌EXCEL数据并调用RFM回写EXCEL

privatevoid获取ToolStripMenuItem_Click(object sender, EventArgs e)

        {

            try

            {

                connectSAP.SetRFM("ZZTEST_WEBSERVICE_03","I_JSON","O_JSON");

                System.Threading.Thread.Sleep(100);

                Range range1 = ((_Worksheet)app.Workbooks.get_Item(1).Worksheets.get_Item(1)).UsedRange;

                range1 = ((_Worksheet)app.Workbooks.get_Item(1).Worksheets.get_Item(1)).UsedRange;

                object[,] data = range1.get_Value();

                TabTableStru.Clear();

                for (int i = 2; i <= data.GetLength(0); i++)

                {

                    indexTableStru = newTableFieldStru();

                    indexTableStru.tablename =convertStr(data[i, 1]);

                    indexTableStru.istable =convertStr(data[i, 2]);

                    indexTableStru.fieldname =convertStr(data[i, 3]);

                    indexTableStru.iskey =convertStr(data[i, 4]);

                    indexTableStru.elementname= convertStr(data[i, 5]);

                    indexTableStru.checktable =convertStr(data[i, 6]);

                    indexTableStru.datatype =convertStr(data[i, 7]);

                    indexTableStru.length =convertStr(data[i, 8]);

                    indexTableStru.decimals =convertStr(data[i, 9]);

                    indexTableStru.domainname =convertStr(data[i, 10]);

                    indexTableStru.shlporigin =convertStr(data[i, 11]);

                    indexTableStru.comptype =convertStr(data[i, 12]);

                   TabTableStru.Add(indexTableStru);

                }

                if (TabTableStru.Count == 0)

                {

                    this.label1.Text +="\r\n" +"获取Excel数据失败";

                    return;

                }

                string AAA =JsonConvert.SerializeObject(TabTableStru);

               

                this.label1.Text = AAA;

                ProgramStru programStru =newProgramStru();

                ProgramStru.PARAM param;

                List<ProgramStru.METHODSTRU> TABMETHODSTRU = newList<ProgramStru.METHODSTRU>();

                ProgramStru.METHODSTRU methods =newProgramStru.METHODSTRU();

                methods.METHODNAME = "METHOD1";

                param =newProgramStru.PARAM();

                param.DATANAME = "I_JSON";

                param.DATATYPE = "STRING";

                param.DATAVALUE = AAA;

                List<ProgramStru.PARAM> TABPARAM = newList<ProgramStru.PARAM>();

                TABPARAM.Clear();

                TABPARAM.Add(param);

                methods.INPUTDATA = TABPARAM;

                param = newProgramStru.PARAM();

                param.DATANAME = "O_JSON";

                param.DATATYPE = "STRING";

                param.DATAVALUE ="";

                TABPARAM = newList<ProgramStru.PARAM>();

                TABPARAM.Clear();

                TABPARAM.Add(param);

                methods.OUTPUTDATA = TABPARAM;

                methods.BODY = "TYPES: BEGIN OFty_field, tablename TYPE dd03l-tabname, istable TYPE dd03l-tabletype, fieldnameTYPE dd03l-fieldname, iskey TYPE dd03l-keyflag, elementname TYPEdd03l-rollname, checktable TYPEdd03l-checktable, datatype TYPE dd03l-datatype, length TYPE dd03l-leng, decimalsTYPE dd03l-decimals, domainname  TYPEdd03l-domname, shlporigin  TYPEdd07t-ddtext, comptype TYPE dd07t-ddtext, END OF ty_field. DATA:lt_field TYPETABLE OF ty_field, ls_field TYPE ty_field. DATA:rt_tab TYPE RANGE OFdd03l-tabname, rt_fid TYPE RANGE OF dd03l-fieldname, rt_ele TYPE RANGE OFdd03l-rollname, rt_dom TYPE RANGE OF dd03l-domname. DATA:rs_tab LIKE LINE OFrt_tab, rs_fid LIKE LINE OF rt_fid, rs_ele LIKE LINE OF  rt_ele, rs_dom LIKE LINE OF rt_dom. /ui2/cl_json=>deserialize(EXPORTING json = i_json pretty_name = /ui2/cl_json=>pretty_mode-noneCHANGING data = lt_field ). LOOP AT lt_field INTO ls_field. IFls_field-tablename IS NOT INITIAL. rs_tab-low = ls_field-tablename. TRANSLATErs_tab-low TO UPPER CASE. rs_tab-option = 'EQ'. rs_tab-sign = 'I'. APPENDrs_tab TO rt_tab. ENDIF. IF ls_field-fieldname IS NOT INITIAL. rs_fid-low =ls_field-fieldname. TRANSLATE rs_fid-low TO UPPER CASE. rs_fid-option = 'EQ'.rs_fid-sign = 'I'. APPEND rs_fid TO rt_fid. ENDIF. IF ls_field-elementname ISNOT INITIAL. rs_ele-low = ls_field-elementname. TRANSLATE rs_ele-low TO UPPERCASE. rs_ele-option = 'EQ'. rs_ele-sign = 'I'. APPEND rs_ele TO rt_ele. ENDIF.IF ls_field-domainname IS NOT INITIAL. rs_dom-low = ls_field-domainname.TRANSLATE rs_dom-low TO UPPER CASE. rs_dom-option = 'EQ'. rs_dom-sign = 'I'.APPEND rs_dom TO rt_dom. ENDIF. ENDLOOP. IF rt_tab IS INITIAL AND rt_fid ISINITIAL AND rt_ele IS INITIAL AND rt_dom IS INITIAL. o_json = '请输入数据'. RETURN. ENDIF. SELECTdd03l~tabname AS tablename tabletype AS istable fieldname keyflag AS iskeyrollname AS elementname checktable datatype leng AS length decimalsdd03l~domname AS domainname dd07t_1~ddtext AS shlporigin dd07t_2~ddtext AScomptype FROM dd03l LEFT JOIN dd07t AS dd07t_1 ON dd07t_1~domname =  'SHLPORIGIN' AND dd07t_1~ddlanguage =  '1' AND dd07t_1~domvalue_l = dd03l~shlporiginLEFT JOIN dd07t AS dd07t_2 ON dd07t_2~domname = 'COMPTYPE' ANDdd07t_2~ddlanguage = '1' AND dd07t_2~domvalue_l = dd03l~comptype INTO TABLElt_field WHERE dd03l~tabname IN rt_tab AND dd03l~fieldname IN rt_fid ANDdd03l~rollname IN rt_ele AND dd03l~domname IN rt_dom AND dd03l~as4local = 'A'.IF lt_field IS NOT INITIAL. o_json = /ui2/cl_json=>serialize( data =lt_field compress = ' ' pretty_name = /ui2/cl_json=>pretty_mode-none ).ENDIF.";

                TABMETHODSTRU.Add(methods);

                programStru.METHODS =TABMETHODSTRU;

                string sss =JsonConvert.SerializeObject(programStru);

                string str_SAPOutput = connectSAP.ExecuteRFM(sss);

                this.label1.Text = str_SAPOutput;

                dynamic model =JsonConvert.DeserializeObject(str_SAPOutput);

                string outstring = model[0].OUTPUTDATA[0].DATAVALUE.ToString();

                model = JsonConvert.DeserializeObject(outstring);

                int row = model.Count;

                Range range2 = worksheet.get_Range("A2","L" + (row+1));

                if (range2 ==null)

                {

                    return;

                }

                object[,] tabdata =newobject[model.Count, 12];

                for (int i = 0; i < model.Count; i++)

                {

                    tabdata[i, 0] =model[i].TABLENAME.ToString();

                    tabdata[i, 1] =model[i].ISTABLE.ToString();

                    tabdata[i, 2] =model[i].FIELDNAME.ToString();

                    tabdata[i, 3] =model[i].ISKEY.ToString();

                    tabdata[i, 4] =model[i].ELEMENTNAME.ToString();

                    tabdata[i, 5] =model[i].ELEMENTNAME.ToString();

                    tabdata[i, 6] =model[i].DATATYPE.ToString();

                    tabdata[i, 7] =model[i].DATATYPE.ToString();

                    tabdata[i, 8] =model[i].DECIMALS.ToString();

                    tabdata[i, 9] =model[i].DOMAINNAME.ToString();

                    tabdata[i, 10] =model[i].SHLPORIGIN.ToString();

                    tabdata[i, 11] =model[i].COMPTYPE.ToString();

                }

 

                range2.Value2 = (dynamic)tabdata;

            }

            catch (Exception)

            {

            }

        }


0.1.3.7.    关闭应用程序同时注销EXCEL进程

//关闭窗体触发

        protectedoverridevoid OnHandleDestroyed(EventArgs e)

        {

            // Stop the application

            if (app !=null )

            {

                // Post a colse message

                //PostMessage((IntPtr)app.Hwnd,WM_CLOSE, 0, 0);

                app.DisplayAlerts = false;

                app.Quit();

                // Delay for it to get the message

                System.Threading.Thread.Sleep(1000);

                // Clear internal handle

           }

            base.OnHandleDestroyed(e);

        }


0.1.4.    结果

C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据

C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据

C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据

C#窗体内嵌EXCEL应用程序,构造二重JSON通过RFC获取SAP系统数据