none
Isa中断 函数dll调用 (急) RRS feed

  • 问题

  • 刚刚学C#没多久,碰到平台调用的问题,急死了~dll是用C++编写的,函数如下:

    /*********************************************************************************************************
    ** Function name:           IsaInitIntrrupt
    ** Descriptions:               初始化中断
    ** Input parameters:        dwIRQNumber             中断号
    **                                                                      IRQ3、IRQ4...
    **                                   hIntrEvent              中断对应的事件                         
    ** Output parameters:       pdwSysIntr              系统分配的逻辑中断号
    ** Returned value:          ISA_NO_ERR              中断初始化成功
    **                                  ISA_NO_IRQ_NUM          PC/104总线不能使用该中断号
    **                                  ISA_INIT_INTR_FAIL      中断初始化失败
    *********************************************************************************************************/
    epcIsa_API DWORD epcIsaInitIntrrupt( DWORD   dwIRQNumber,
                                         HANDLE  hIntrEvent,
                                         PDWORD  pdwSysIntr);

    /*********************************************************************************************************
    ** Function name:           epcIsaIntrruptDone
    ** Descriptions:                重新使能中断   
    ** Input parameters:        dwSysIntrNumber         逻辑中断号
    ** Output parameters:            
    ** Returned value:          ISA_NO_ERR              重新使能中断成功             
    **                                  ISA_INTR_UNINIT         中断还没有初始化
    *********************************************************************************************************/
    epcIsa_API DWORD epcIsaIntrruptDone(    DWORD dwSysIntrNumber);

    C++调用如下:

    //定义全局变量

    BOOL __GbExitIST; /* 中断服务线程是否退出 */
    HANDLE __GhIrqEvent; /* 中断事件 */
    DWORD __GdwIrqNum = IRQ9; /* 用户使用的IRQ 号 */
    DWORD __GdwSysIntr; /* 系统分配的逻辑中断号 */
    HANDLE __GhIst; /* 指向中断服务线程的句柄 */
    DWORD __GdwIstID; /* 中断服务线程的ID */

    //添加中断线程

    DWORD IntrruptServiceThread (PVOID pArg)
    {
    CPC104Dlg *dlg = (CPC104Dlg*)pArg;
    DWORD dwRetVaule; /* 函数返回值 */

    while(__GbExitIST == FALSE) { /* 判断是否退出中断服务线程 */
    ret = WaitForSingleObject(__GhIrqEvent, INFINITE); /* 等待中断事件发生 */
    if(ret == WAIT_OBJECT_0) { /* 等到中断事件 */
    /*
    * 中断处理代码
    */
    MessageBox(_T("Message From Intrrupt Service Thread!"));
    epcIsaIntrruptDone(__GdwSysIntr); /* 处理完中断重新使能中断 */
    }
    }
    return 0;
    }

    //按钮点击事件

    void CPC104Dlg::OnIntr()
    {
    DWORD dwRetVaule; /* 函数返回值 */
    CButton *pBnTmp = NULL;
    MessageBox(_T("This is An Example Of Intrrupt Service Thread!"));
    __GhIrqEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    /* 创建中断处理事件 */
    if(__GhIrqEvent == INVAILID_HANDLE_VAULE) { /* 创建事件失败 */
    MessageBox(_T("Create Event Fail!"));
    return;
    }
    /*
    * 初始化中断
    */
    dwRetVaule = epcIsaInitIntrrupt( __GdwIrqNum, /* 中断号,这里为IRQ9 */
                                                     __GhIrqEvent, /* 用户创建的中断事件 */                    
                                                   &__GdwSysIntr); /* 系统分配的逻辑中断号 */
    if(dwRetVaule != ISA_NO_ERR) { /* 初始化中断失败 */                
    MessageBox(_T("Initialize Intrrupt Fail!"));
    return;
    }
    __GbExitIST = FALSE; /* 设置不退出中断处理线程 */

    __GhIst = CreateThread( 0,
                                          0,
                                          (LPTHREAD_START_ROUTINE)IntrruptServiceThread,
                                         this,
                                         0,
                                         &__GdwIstID);
    if(__GhIst == INVAILID_HANDLE_VAULE) { /* 创建中断服务线程失败 */
    MessageBox(_T("Create IST FAIL!"));
    return;
    }
    pBnTmp = (CButton*)GetDlgItem(IDC_EXIT);
    pBnTmp->EnableWindow(TRUE); /* 使能ExitIST 按扭 */
    }

    请问在C#中如何调用以上DLL中的函数,以及初始化中断的主函数~~


    • 已编辑 杰心 2012年3月16日 2:18
    2012年3月16日 2:14

全部回复

  • Hi 杰心,

    欢迎来到C#论坛。

    若要声明一个方法使其具有来自 DLL 导出的实现,请执行下列操作:

    • 使用 C# 关键字 staticextern 声明方法。
    • DllImport 属性附加到该方法。DllImport 属性允许您指定包含该方法的 DLL 的名称。通常的做法是用与导出的方法相同的名称命名 C# 方法,但也可以对 C# 方法使用不同的名称。
    • 还可以为方法的参数和返回值指定自定义封送处理信息,这将重写 .NET Framework 的默认封送处理。

    例子:使用 DllImport 属性通过调用 msvcrt.dll 中的 puts 输出消息。

    using System;
    using System.Runtime.InteropServices;
    
    class PlatformInvokeTest
    {
        [DllImport("msvcrt.dll")]
        public static extern int puts(string c);
        [DllImport("msvcrt.dll")]
        internal static extern int _flushall();
    
        public static void Main() 
        {
            puts("Test");
            _flushall();
        }
    }
    

    C# 与 C++ 数据类型对照

    C++                 C#
     =====================================
     WORD            ushort
     DWORD            uint
     UCHAR            int/byte   大部分情况都可以使用int代替,而如果需要严格对齐的话则应该用bytebyte
    UCHAR*            string/IntPtr
     unsigned char*         [MarshalAs(UnmanagedType.LPArray)]byte[]/?(Intptr)
     char*            string
     LPCTSTR            string
     LPTSTR            [MarshalAs(UnmanagedType.LPTStr)] string
     long            int
     ulong               uint
     Handle            IntPtr
     HWND            IntPtr
     void*            IntPtr
     int            int
     int*            ref int
     *int            IntPtr
     unsigned int        uint
     COLORREF                uint

    更多的信息请参考MSDN平台调用教程http://msdn.microsoft.com/zh-cn/library/aa288468(v=vs.71).aspx

    祝你愉快!


    Bob Shen [MSFT]
    MSDN Community Support | Feedback to us

    2012年3月19日 9:12
    版主
  • 你好,谢谢你的回答,这个问题已经解决了~

    请问一下结构体的地址怎么表示啊?

    比如struct Mystruct

    {//Code}

    C++函数调用格式为:func Myfunc(...,&Mystruct,...);

    如何移植到C#上?


    任何杀不死我的困难只会让我更强大!!

    2012年3月20日 1:08
  • Hi 杰心,

    在C#声明结构体之前需要加上
    [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]
    在C# 里声明函数的时候,参数前面加上ref 表示传地址。


    Bob Shen [MSFT]
    MSDN Community Support | Feedback to us

    2012年3月20日 3:30
    版主
  • 谢谢你的回答,能帮我看看下面这段程序错在哪么?主程序到调用ZWA_DeviceOpen时总是弹出NotSupportedException!!

    引用的DLL文件是C++写的:

    ZWAPCM8208BTBSDRV_API DWORD ZWA_DeviceOpen(LPZWADEVINFO pstDevInfo,LPZWAPFN pstIsaFn,HANDLE *phDevHandle);

    C#中调用为:

    [System.Runtime.InteropServices.DllImport("ZwaPCM8208BTBSDrv.dll", SetLastError = true,EntryPoint ="ZWA_DeviceOpen")]
    public static extern uint ZWA_DeviceOpen(ref ZWADEVINFO pstDevInfo, ref ZWAPFN pstIsaFn, out uint phDevHandle);

    主程序调用:

            private void deviceOpenButton_Click(object sender, EventArgs e)
            {
                uint dwRet = 0;
                ZWADEVINFO stDevInfo = new ZWADEVINFO();/* 设备信息结构体变量 */
                ZWAPFN stpFnTmp = new ZWAPFN();/* PC/104总线操作函数指针结构体 */
                uint m_hPCM8208BT = 0;/* 接收设备操作句柄 */
    
    
                stDevInfo.dwDevType = (uint)DeviceType.PCM8208BTBS; /* 设备类型号 */
                stDevInfo.dwDevAddr = (uint)0x300; /* 设备基地址 */
                stDevInfo.dwIrqNo = (uint)DeviceIRQ.IRQ3; /* 设备使用的IRQ 物理中断号 */
                stpFnTmp.lpfnIsaIoByteR = new pfnIsaIobyteR(epcIsaLib.epcIsaIoByteR); /* 初始化PC/104 总线操作 */
                stpFnTmp.lpfnIsaIoByteW = new pfnIsaIobyteW(epcIsaLib.epcIsaIoByteW); /* 接口函数指针 */
                stpFnTmp.lpfnIsaIoWordR = new pfnIsaIoWordR(epcIsaLib.epcIsaIoWordR);
                stpFnTmp.lpfnIsaIoWordW = new pfnIsaIoWordW(epcIsaLib.epcIsaIoWordW);
                stpFnTmp.lpfnIsaInitSysIrq = new pfnIsaInitSysIrq(epcIsaLib.epcIsaInitIntrrupt);
                stpFnTmp.lpfnIsaDisableSysIrq = new pfnIsaDisableSysIrq(epcIsaLib.epcIsaIntrruptDisable);
                stpFnTmp.lpfnIsaReEnableSysIrq = new pfnIsaReEnableSysIrq(epcIsaLib.epcIsaIntrruptDone);
    
                dwRet = ZwaPCM8208BTBSDrvLib.ZWA_DeviceOpen(ref stDevInfo, ref stpFnTmp, out m_hPCM8208BT);
    //一到这句就会弹出NotSupportedException!!!
    
                if (dwRet != (uint)DeviceErrorCode.ERR_SUCCESS)
                {
                    MessageBox.Show("打开设备失败!");
                }
            }


    任何杀不死我的困难只会让我更强大!!

    2012年3月20日 4:44