当C#遇到函数指针及相关结构体——请教关于C#调用C编写的DLL时头文件重新申明的问题

时间:2022-04-26 12:41:02
C#中不包含函数指针的概念,而函数指针又是在C头文件中常使用的接口封装模式。因为刚刚接触C#不久,对于“委托”的理解尚属浅薄,近期接触的一个问题令我纠结了很久。从网上查找了许多相关文档,但知识点有些纷乱,还是到这里来寻求一下帮助。


#ifdef __cplusplus
extern "C" {
#endif

typedef HDISCFILE (*Open )(HDISC hDisc, const wchar_t *filename, A_UINT32 dwOpenMethod, A_UINT32 dwNodeType, A_UINT64 llFileSize);

typedef A_INT32 (*Read )(const HDISCFILE hDiscFile, A_UINT8 *buffer, A_UINT32 count);

typedef A_INT32 (*Write )(const HDISCFILE  hDiscFile, A_UINT8 *buffer, A_UINT32 count);

typedef  A_UINT64 (*Seek )(const HDISCFILE  hDiscFile, A_INT64 offset, A_INT32 origin);

typedef  A_UINT64 (*Size )(const HDISCFILE  hDiscFile);

typedef  A_INT32 (*Close )(const HDISCFILE  hDiscFile);

typedef  HFIND (*FindFirstFile )(HDISC hDisc, const wchar_t *filename, FindFileData *pFileData);

typedef  A_INT32 (*FindNextFile )(HDISC hDisc, HFIND hFind, FindFileData *pFileData);

typedef  A_INT32 (*FindClose )(HDISC hDisc,  HFIND hFind);

typedef  A_INT32 (*DeleteFile)(HDISC hDisc, wchar_t * FileName);

typedef A_INT32 (*CreateDir )(HDISC hDisc, const wchar_t *pathname);

typedef  A_INT32 (*DeleteDirectory)(HDISC hDisc, wchar_t * PathName);

typedef  A_INT32 (*FileIsExist)(HDISC hDisc, wchar_t * FileName);

typedef  A_INT32 (*DirectoryIsExist)(HDISC hDisc, wchar_t * PathName);

typedef  A_INT32 (*GetFreeCapacity)(HDISC hDisc, A_UINT32 * dwTotal, A_UINT32 * dwMaxSequential);


typedef struct tagIOParam
{
A_UINT32 cbSize;
Open open;
Read read;
Write write;
Seek seek;
Size size;
Close close;

CreateDir createdir;
FindFirstFile findfirstfile;
FindNextFile findnextfile;
FindClose findclose;
DeleteFile deletefile;
DeleteDirectory deletedirectory;
FileIsExist fileexist;
DirectoryIsExist dirextoryexist;
GetFreeCapacity getfreecapacity;
HDISC hDisc;
A_UINT32 Reseved1;
}IOParam, *HIOParam;

MEIDUM_IO_API A_BOOL InitIOParam(wchar_t * lptPath, HIOParam *phParam, wchar_t *lptVolumeName);

MEIDUM_IO_API void UninitIOParam(HIOParam hParam);

#ifdef __cplusplus
}
#endif

这是我需要使用的C语言编写的DLL的其中一个头文件,主要控制文件在硬盘及光盘上的读写操作,其中大量使用函数指针来进行操作,希望各位C#高人给予指导,在我的上层app中如需调用该DLL,对此头文件应进行怎样的重新申明。

8 个解决方案

#1


函数指针可以用delegate来代替;结构体还是可以用的,要注意声明类型及对齐方式;

#2


可否给出个例子说明一下如何用delegate来代替函数指针?
结构体是否不需要修改就可以直接放入C#的重新申明代码中?
没有在相关资料中看到关于对齐方式的问题,这个指的是什么?

#3


C#调用C++动态链接库中的函数指针与函数指针结构
http://www.dreamdu.com/blog/2008/04/25/cs_cpp_functionpointer/

#4


指针用delegate,数据结构需要自己声明

#5


 用delegate来代替函数指针:
public delegate int capErrorCallback(
IntPtr hWnd,  
int nID,    
string lpsz 
);
capErrorCallback m_errorCallBack = new capErrorCallback(this.capErrorCallback);

 SendMessage(m_hwnd, WM_CAP_SET_CALLBACK_ERRORA, 0, m_errorCallBack);

[DllImport("USER32.DLL")]
        static extern int SendMessage(
            IntPtr hwnd,
            int wMsg,
            int wParam,
            capErrorCallback lParam
            );

结构体要修改能与C的结构体一样的类型.

#6


C#一般不使用指针,只有在不安全代码里使用指针.

#7


[DllImport("USER32.DLL")] 
        static extern int SendMessage( 
            IntPtr hwnd, 
            int wMsg, 
            int wParam, 
            capErrorCallback lParam 
            ); 

结构体,在C# 里面可以用类或者结构体实现

如果是指针

传入参数面前加ref

#8


我给个例子给你
这个是C++里面的函数指针以及调用定义:

typedef void (__stdcall *delegate_GetPtr)(const void*);
typedef void (__stdcall *delegate_OnRequest)(const char* info);
typedef void (__stdcall *delegate_OnCancel)();
typedef void (__stdcall *delegate_OnError)();
typedef void (__stdcall *delegate_OnComplete)();
typedef void (__stdcall *delegate_OnProgress)(int percent);


void __stdcall SetEvents
(
   delegate_GetPtr          ptr,
   delegate_OnRequest req,
   delegate_OnCancel can,
   delegate_OnError err,
   delegate_OnComplete cmpl,
   delegate_OnProgress prg
)
{
  //这里实现内容省略
}



下面是C#函数指针变成delegate的例子


        delegate void delegate_GetWrapperPtr(IntPtr ptr);

        delegate void delegate_OnRequest(string Info);

        /// <summary>
        /// 无参函数指针
        /// </summary>
        delegate void delegate_NoParamFuncPtr();

        delegate void delegate_OnProgress(int percent);

       //下面是调用SetEvents,注意和上面C++原型的对比
       [DllImport(_dll_path_,
            CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall,
            EntryPoint = "SetEvents")]
        private static extern void SetEvents(
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_GetWrapperPtr ptr,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_OnRequest req,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_NoParamFuncPtr can,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_NoParamFuncPtr err,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_NoParamFuncPtr cmp,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_OnProgress prg
            );



怎么样,看出名堂没?

#1


函数指针可以用delegate来代替;结构体还是可以用的,要注意声明类型及对齐方式;

#2


可否给出个例子说明一下如何用delegate来代替函数指针?
结构体是否不需要修改就可以直接放入C#的重新申明代码中?
没有在相关资料中看到关于对齐方式的问题,这个指的是什么?

#3


C#调用C++动态链接库中的函数指针与函数指针结构
http://www.dreamdu.com/blog/2008/04/25/cs_cpp_functionpointer/

#4


指针用delegate,数据结构需要自己声明

#5


 用delegate来代替函数指针:
public delegate int capErrorCallback(
IntPtr hWnd,  
int nID,    
string lpsz 
);
capErrorCallback m_errorCallBack = new capErrorCallback(this.capErrorCallback);

 SendMessage(m_hwnd, WM_CAP_SET_CALLBACK_ERRORA, 0, m_errorCallBack);

[DllImport("USER32.DLL")]
        static extern int SendMessage(
            IntPtr hwnd,
            int wMsg,
            int wParam,
            capErrorCallback lParam
            );

结构体要修改能与C的结构体一样的类型.

#6


C#一般不使用指针,只有在不安全代码里使用指针.

#7


[DllImport("USER32.DLL")] 
        static extern int SendMessage( 
            IntPtr hwnd, 
            int wMsg, 
            int wParam, 
            capErrorCallback lParam 
            ); 

结构体,在C# 里面可以用类或者结构体实现

如果是指针

传入参数面前加ref

#8


我给个例子给你
这个是C++里面的函数指针以及调用定义:

typedef void (__stdcall *delegate_GetPtr)(const void*);
typedef void (__stdcall *delegate_OnRequest)(const char* info);
typedef void (__stdcall *delegate_OnCancel)();
typedef void (__stdcall *delegate_OnError)();
typedef void (__stdcall *delegate_OnComplete)();
typedef void (__stdcall *delegate_OnProgress)(int percent);


void __stdcall SetEvents
(
   delegate_GetPtr          ptr,
   delegate_OnRequest req,
   delegate_OnCancel can,
   delegate_OnError err,
   delegate_OnComplete cmpl,
   delegate_OnProgress prg
)
{
  //这里实现内容省略
}



下面是C#函数指针变成delegate的例子


        delegate void delegate_GetWrapperPtr(IntPtr ptr);

        delegate void delegate_OnRequest(string Info);

        /// <summary>
        /// 无参函数指针
        /// </summary>
        delegate void delegate_NoParamFuncPtr();

        delegate void delegate_OnProgress(int percent);

       //下面是调用SetEvents,注意和上面C++原型的对比
       [DllImport(_dll_path_,
            CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall,
            EntryPoint = "SetEvents")]
        private static extern void SetEvents(
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_GetWrapperPtr ptr,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_OnRequest req,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_NoParamFuncPtr can,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_NoParamFuncPtr err,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_NoParamFuncPtr cmp,
            [MarshalAs(UnmanagedType.FunctionPtr)]
            delegate_OnProgress prg
            );



怎么样,看出名堂没?