首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 关于C#调用带有回调参数的API [已结帖,结帖人:phyloinker]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 结帖率:
    发表于:2008-11-04 08:52:35 楼主
    这几天使用C#调用PB API来分析pb的源代码文件,(在此严重鄙视PB,人家的源码都是文本,就你的非要自己捣鼓),其中一个API原型是这样的

    int PBORCA_LibraryDirectory ( HPBORCA hORCASession, LPSTR lpszLibName, LPSTR lpszLibComments, int iCmntsBuffSize, PBORCA_LISTPROC pListProc, LPVOID pUserData );


    参数说明


    hORCASession
    Handle to previously established ORCA session

    lpszLibName
    Pointer to a string whose value is the filename of the library for which you want directory information

    lpszLibComments
    Pointer to a buffer in which ORCA will put comments stored with the library

    iCmntsBuffSize
    Size of the buffer pointed to by lpszLibComments

    pListProc
    Pointer to the PBORCA_LibraryDirectory callback function. The callback function is called for each entry in the library
    The information ORCA passes to the callback function is entry name, comments, size of entry, and modification time, stored in a structure of type PBORCA_DIRENTRY


    pUserData
    Pointer to user data to be passed to the PBORCA_LibraryDirectory callback function
    The user data typically includes the buffer or a pointer to the buffer in which the callback function formats the directory information as well as information about the size of the buffer

    其中pListProc作为回调函数,定义如下

    typedef void (FAR PASCAL *PBORCA_LISTPROC) ( PPBORCA_DIRENTRY, LPVOID );

    参数说明
    PPBORCA_DIRENTRY
    Pointer to the structure PBORCA_DIRENTRY, described next

    LPVOID
    Long pointer to user data 
    结构体PBORCA_DIRENTRY structure如下
    typedef struct pborca_direntry
    {
    CHAR szComments[PBORCA_MAXCOMMENT + 1];
    LONG lCreateTime;
    LONG lEntrySize;
    LPSTR lpszEntryName;
    PBORCA_TYPE otEntryType;}
    PBORCA_DIRENTRY, FAR *PPBORCA_DIRENTRY;

    以上的详细参考资料在
    http://manuals.sybase.com/onlinebooks/group-pb/adt0650e/orca/@Generic__BookTextView/7001;pt=4344;lang=zh#X


    100  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 08:55:551楼 得分:0
    然后我市这样声名的

    函数
    [DllImport("pborc90.dll", EntryPoint = "PBORCA_LibraryDirectory")]
            public static extern int EntryList(uint sessionId, string libName, StringBuilder libComents, int comentSize, dele_test treatFunc, uint UserData);
       
    两个结构体   
    [StructLayout(LayoutKind.Sequential)]
        public struct ORCA_UserDataInfo
        {
          //  public char[] entryInfo; // Buffer for entry info
            public uint dwCallCount; // # of entries in lib
            public uint dwBufferSize; // size of buffer
            public uint dwBufferOffset; // current offset in buffer
        }
        [StructLayout(LayoutKind.Sequential)]
      public struct PBORCA_DIRENTRY
        {
        public  char[] szComments; // Buffer for entry info
            public int lCreateTime; // # of entries in lib
            public int lEntrySize; // size of buffer
            public string lpszEntryName; // current offset in buffer
            public uint otEntryType;

        }

    委托
        public delegate void dele_test(PBORCA_DIRENTRY entryInfo, uint udInfo);

    调用过程
    uint sessionId;
                    sessionId = OpenSession();
                    int returnValue;
                StringBuilder sbComment=new StringBuilder (5000);
                dele_test dele_t1 = new dele_test(treatEntryInfo);
                ORCA_UserDataInfo udi=new ORCA_UserDataInfo ();
                      PBORCA_DIRENTRY pd = new PBORCA_DIRENTRY();
              returnValue= EntryList(sessionId, "c:\\ihatepb.pbl", sbComment, sbComment.Length, dele_t1,0);

    结果出来各种奇怪的错误,有什么数组与元数据不符,或者数组类型错误,或者内存不能写等等。
    总之就是数据类型对照有错误。
    请各位老师不吝赐教,谢谢


    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • palmax
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 08:57:592楼 得分:0
    回调函数在C#里要定义成委托类型
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 09:06:113楼 得分:0
    [StructLayout(LayoutKind.Sequential)]
        public struct ORCA_UserDataInfo
        {
          //  public char[] entryInfo; // Buffer for entry info
            public uint dwCallCount; // # of entries in lib
            public uint dwBufferSize; // size of buffer
            public uint dwBufferOffset; // current offset in buffer
        }
        [StructLayout(LayoutKind.Sequential)]
      public struct PBORCA_DIRENTRY
        {
        public  char[] szComments; // Buffer for entry info
            public int lCreateTime; // # of entries in lib
            public int lEntrySize; // size of buffer
            public string lpszEntryName; // current offset in buffer
            public uint otEntryType;

        }
    =====================
    这两个结构里面的 char[]  都要定义长度
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 09:07:544楼 得分:0
    public static extern int EntryList(uint sessionId, string libName, StringBuilder libComents, int comentSize, dele_test treatFunc, uint UserData);

    这里的 LPSTR 你知道用 StringBuilder

    那public struct PBORCA_DIRENTRY 这里的public string lpszEntryName;为啥不用
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zswang
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

      7

    发表于:2008-11-04 09:12:555楼 得分:40
    C\C++ 中的 char是类型一个字节

    C# 中的 char类型,所以转换的时候要用byte取代C\C++中的char

    大概是这样:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = PBORCA_MAXCOMMENT + 1)]
    public byte[] szComments; // Buffer for entry info

    参考EnumWindows标准API回调的使用:
    C# code
    using System.Runtime.InteropServices; public delegate bool WNDENUMPROC(IntPtr hwnd, int lParam); [DllImport("user32.dll")] public static extern int EnumWindows(WNDENUMPROC lpEnumFunc, int lParam); public static bool EnumFunc(IntPtr hwnd, int lParam) { Console.WriteLine("Window handle is " + hwnd); return true; } private void button1_Click(object sender, EventArgs e) { EnumWindows(EnumFunc, 0); }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zswang
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

      7

    发表于:2008-11-04 09:13:256楼 得分:0
    C# 中的 char类型两个字节。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 09:22:157楼 得分:0
    十分感谢大家的积极回复。
    现就大家提出的方法解释一下
    eglic
    你提出的问题,第一,我在结构体里面定义char[]entry=new char[50];地时候,编译提示结构体中不允许初始化(我是英文vs,可能翻译的不准确)
    第二,我第一次用stringbuilder,但是运行时提示stringbuilder 不能用在结构体中,让我用初始化的string代替,我想string肯定不行了,那就只好用char凑合

    zswang 我先回复,然后再详细看你的例子。
    感谢各位的帮助
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 09:26:248楼 得分:0
    提出的问题,第一,我在结构体里面定义char[]entry=new char[50];地时候,编译提示结构体中不允许初始化(我是英文vs,可能翻译的不准确)

    用Marshal....
    C# code
    public struct PBORCA_DIRENTRY { [MarshalAs(SizeConst=50)] public char[] szComments; // Buffer for entry info public int lCreateTime; // # of entries in lib public int lEntrySize; // size of buffer public string lpszEntryName; // current offset in buffer public uint otEntryType; }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 09:28:559楼 得分:0
    using System.Runtime.InteropServices;

    public delegate bool WNDENUMPROC(IntPtr hwnd, int lParam);

    [DllImport("user32.dll")]
    public static extern int EnumWindows(WNDENUMPROC lpEnumFunc, int lParam);

    public static bool EnumFunc(IntPtr hwnd, int lParam)
    {
        Console.WriteLine("Window handle is " + hwnd);
        return true;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        EnumWindows(EnumFunc, 0);
    }

    这段代码我基本看懂了,但是有几个地方跟我预期的有出入
    1声名的时候声名的是一个委托WNDENUMPROC ,传递的时候是传函数名。
    我声明的时候也是一个委托,但是传的时候使用的是委托的实例。不知道我这种有没有问题
    2intptr字面意思应该是整数指针的意思,那么他跟ulong是不是可以互换?有什么特殊性?
    3 我觉得关键是那几个struct怎么声明和调用。

    再次感谢您。

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 09:31:2910楼 得分:60
    int PBORCA_LibraryDirectory ( HPBORCA hORCASession, LPSTR lpszLibName, LPSTR lpszLibComments, int iCmntsBuffSize, PBORCA_LISTPROC pListProc, LPVOID pUserData );

    从函数原型的字面意思很难猜出 LPSTR lpszLibName, LPSTR lpszLibComments
    这两个是传入还是传出了

    传入用 string就可以了
    传出用 StringBuilder

    PBORCA_DIRENTRY这个结构里面的 LPSTR lpszEntryName;
    这个可能会有点麻烦,这个应该是传出一个字符串
    如果文档中没有定义的话,那这个应该是传出一个指针

    你可以尝试定义为 IntPtr,然后用
    Marshal.PtrToStringAnsi
    或者 PtrToStringAuto 或者 PtrToStringBSTR  或者 PtrToStringUni 转换一下
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 09:33:3311楼 得分:0
    eglic

    Error 2 'System.Runtime.InteropServices.MarshalAsAttribute' does not contain a constructor that takes '0' arguments E:\My Document\Visual Studio 2008\Projects\PBORCATry\PBORCATry\Program.cs 160 10 PBORCATry
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 09:37:1812楼 得分:0
    引用 11 楼 phyloinker 的回复:
    eglic

    Error 2 'System.Runtime.InteropServices.MarshalAsAttribute' does not contain a constructor that takes '0' arguments E:\My Document\Visual Studio 2008\Projects\PBORCATry\PBORCATry\Program.cs 160 10 PBORCATry


    楼上已经有人给出完整的了

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = PBORCA_MAXCOMMENT + 1)]
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 09:38:1013楼 得分:0
    int PBORCA_LibraryDirectory ( HPBORCA hORCASession, LPSTR lpszLibName, LPSTR lpszLibComments, int iCmntsBuffSize, PBORCA_LISTPROC pListProc, LPVOID pUserData );

    从函数原型的字面意思很难猜出 LPSTR lpszLibName, LPSTR lpszLibComments
    这两个是传入还是传出了

    hORCASession,传入 lpszlibName,lpszLibComments 传出 iCmntsBuffSize 传入 pListProc回调函数
    pUserData

    Pointer to user data to be passed to the PBORCA_LibraryDirectory callback function
    The user data typically includes the buffer or a pointer to the buffer in which the callback function formats the directory information as well as information about the size of the buffer

    我英文不好,硬是没看到这个字段时干吗用的。感觉上应该是一个传出的。用来保存directory infomation的。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 09:47:3614楼 得分:0
    楼上各位的指教我会好好消化
    现在还有一个问题
    就是

    int PBORCA_LibraryDirectory ( HPBORCA hORCASession, LPSTR lpszLibName, LPSTR lpszLibComments, int iCmntsBuffSize, PBORCA_LISTPROC pListProc, LPVOID pUserData );
    LPVOID pUserData 这个东西我声明的时候市声明称
    uint UserData

    还是我自定义的结构体类型
    ORCA_UserDataInfo UserData?

    还有那个回调函数的原型
    typedef void (FAR PASCAL *PBORCA_LISTPROC) ( PPBORCA_DIRENTRY, LPVOID );
    PPBORCA_DIRENTRY  //定义的结构体

    LPVOID //刚才那个ORCA_UserDataInfo结构体

    这两个参数我在定义的时候是定义成


    public delegate void dele_test(PBORCA_DIRENTRY entryInfo, ORCA_UserDataInfo udInfo);
    还是
    public delegate void dele_test(uint entryInfo, uint udInfo);
    或者是
    public delegate void dele_test(intptr entryInfo, intptr udInfo);

    第一次正儿八经的写API的应用,请包涵
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 09:50:2515楼 得分:0
    哈哈,按照大家的指示
    char改撑byte
    传委托的实例改成传函数名
    还有那个marshell
    虽然结果还不正确,但是起码不抱错了。十分感谢各位指导!尤其感谢eglic 
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 09:57:2516楼 得分:0
    声明的时候尽量接近原型

    用IntPtr是万不得已的情况,遇上了变态的API。。。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 09:58:0517楼 得分:0
    这个只能你自己多实验了,反正就那么几种办法,一个不行换一个再试试
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • hyruur
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 09:59:4218楼 得分:0
    引用 5 楼 zswang 的回复:
    C\C++ 中的 char是类型一个字节

    C# 中的 char类型,所以转换的时候要用byte取代C\C++中的char

    大概是这样:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = PBORCA_MAXCOMMENT + 1)]
    public byte[] szComments; // Buffer for entry info

    参考EnumWindows标准API回调的使用:

    C# code
    using System.Runtime.InteropServices;

    public delegate bool WNDENUMPROC(IntPtr hwnd, int lParam);

    [Dll…



    帮顶
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 10:05:5119楼 得分:0
    运行时不抱错了,但是传给回调函数的都是空值………………
    痛苦啊!
    知识到用时方恨少
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • long_xiao
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 10:06:4620楼 得分:0
    哇  高手!!!!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 10:07:3421楼 得分:0
    而且倒了回调函数运行完毕之后,没有返回主调用那个地方继续运行,直接停在那里了………………是不是关于回调我还有什么没注意的…………
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 10:22:3322楼 得分:0
    typedef struct ORCA_UserDataInfo
    {
    LPSTR lpszBuffer; // Buffer for entry info
    DWORD dwCallCount; // # of entries in lib
    DWORD dwBufferSize; // size of buffer
    DWORD dwBufferOffset; // current offset in buffer
    } ORCA_USERDATAINFO, FAR *PORCA_USERDATAINFO;

    这是例子中的结构体的定义
    我转成了
    [StructLayout(LayoutKind.Sequential)]
        public struct ORCA_UserDataInfo
        {

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)]
            public byte[] entryInfo; // Buffer for entry info
            public uint dwCallCount; // # of entries in lib
            public uint dwBufferSize; // size of buffer
            public uint dwBufferOffset; // current offset in buffer
        }

    结果是我调整那个SizeConst = 200,就会得到不同的结果,有时候是写保护,有时候时空,有时候能有值但是不知道对不对。

    这四个成员应该都是输出方向的,是不是要加ref或者out之类的?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • eglic
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 2

    发表于:2008-11-04 10:24:5423楼 得分:0
    原文中是这样的

    CHAR szComments[PBORCA_MAXCOMMENT + 1];

    所以你应该先找到 PBORCA_MAXCOMMENT 这个的定义
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 10:33:4124楼 得分:0
    坦白的说,我没找到PBORCA_MAXCOMMENT
    但是我估计他是指得comment的最大值,我只要把它设置成足够大应该就可以了。

    他给了一个例子
    ORCA_USERDATAINFO UserDataBuffer;
    PORCA_USERDATAINFO lpUserDataBuffer;
    CHAR InfoBuffer[60000];
    LPSTR pszLibraryName;
    CHAR szComments[PBORCA_MAXCOMMENT];

    // Set library name
    pszLibraryName = "c:\\myapp\\ver1\\datamod.pbl";

    // Initialize UserDataBuffer
    lpUserDataBuffer = &UserDataBuffer;

    lpUserDataBuffer->dwCallCount = 0;
    lpUserDataBuffer->dwBufferOffset = 0;
    lpUserDataBuffer->dwBufferSize = 60000;
    lpUserDataBuffer->lpszBuffer = (LPSTR) InfoBuffer;

    // Initialize all of InfoBuffer to 0
    memset(lpUserDataBuffer->lpszBuffer,
    0x00, (size_t) lpUserDataBuffer->dwBufferSize);

    // Get the proc address of callback function
    lpListProc = MakeProcInstance(
    (FARPROC)LibraryList, hInst);

    // Call ORCA function
    lpORCA_Info->lReturnCode = PBORCA_LibraryDirectory(
    lpORCA_Info->hORCASession, pszLibraryName,
    (LPSTR) szComments, PBORCA_MAXCOMMENT,
    (PBORCA_LISTPROC) lpListProc, lpUserDataBuffer);

    //Release the proc instance resource
    FreeProcInstance(lpListProc);


    不过C语言的我看得不是很明白。但是我注意到
    lpUserDataBuffer->lpszBuffer = (LPSTR) InfoBuffer;
    也就是说结构体里面的第一个成员
    LPSTR lpszBuffer; // Buffer for entry info

    实际上应该是一个指针,这样的话,我是不时就不应该定义成byte了?而应该定义成ulong或者inptr?
    然后把它赋值到一个byte[]的首地址?
    但是怎么取byte[]的首地址呢?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • phyloinker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-04 10:34:5025楼 得分:0
    PBORCA_MAXCOMMENT 是第一个结构体的,我刚才说的是第二个结构体,所以不牵扯PBORCA_MAXCOMMENT
    修改 删除