【发布时间】:2016-03-06 00:14:43
【问题描述】:
我正在尝试在 C# 中重新创建一些 C++ 示例 API 使用代码。
看起来我可能需要创建一个 C++/CLI 包装器以使托管世界可以访问 API 函数,但如果可能的话,我想避免这种情况。 API 库本身只有一个导出函数:data_api_func_tab。
这是 C++ API 用法的样子:
//
// .h file
//
typedef struct _DATA_API_FUNC_TAB {
short (*api_init)();
// ... lots of other methods ...
} DATA_API_FUNC_TAB
extern "C" typedef short (* MAPIINIT)(short);
// ... lots of other methods ...
#undef EXTERN
#ifdef _MAIN
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN MAPIINIT ncm_api_init;
// ... lots of other methods ...
public:
UCHAR SomeVariable;
void SomeMethod( arguments );
//
// .cpp file
//
/// Constructor
CWidgetDataApi::CWidgetDataApi()
{
SomeVariable = 0;
m_hInstHdl = ::LoadLibrary(_T(".\\NATIVEAPI.dll"));
if( NULL != m_hInstHdl )
{
DATA_API_FUNC_TAB* p_data_api_func_tab =
(DATA_API_FUNC_TAB*) ::GetProcAddress(m_hInstHdl, "data_api_func_tab");
SomeVariable = 1;
if( p_data_api_func_tab == NULL )
{
::FreeLibrary(m_hInstHdl);
m_hInstHdl = NULL;
SomeVariable = 0;
}
else
{
api_init = (MAPINIT) p_data_api_func_tab->api_init;
// ... lots of other methods ...
short Ret = api_init(index);
}
}
}
/// Method
void CWidgetDataApi::SomeMethod( arguments )
{
// ... Makes use of the various other methods ...
}
//
// Usage in another class
//
DataAPI = new CWidgetDataApi;
if( DataAPI->SomeVariable == 1 )
{
DataAPI->SomeMethod( arguments );
...
}
由于我不能在本机库上使用反射(更不用说它会很慢),PInvoke 似乎是唯一的方法。
我在 C# 中重新创建了适当的结构并尝试了以下 PInvoke 签名,
[DllImport("NATIVEAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern struct data_api_func_tab { };
[DllImport("NATIVEAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern short api_init([In, Out] ref _DATA_API_FUNC_TAB data_api_func_tab);
但它们会产生异常
在 NATIVEAPI.dll 中找不到名为“...whatever I try...”的入口点
我已经四处寻找一种方法来做到这一点,但似乎只找到不受 C++/CLI 管理的解决方案。我正在尝试做的事情是否可能(考虑到结构中包含的各个方法未导出)?
【问题讨论】:
-
用C#完整定义struct,只声明要导入的native函数。
-
@Felix 没有要导入的函数
-
data_api_func_tab() 声明需要 CallingConvention.Cdecl 和 ExactSpelling = true 因为函数名没有被修饰。返回类型为 IntPtr,使用 Marshal.PtrToStructure 恢复结构。将结构体的 app_init 成员声明为委托,需要 [UnmanagedFunctionPointer] 声明为 Cdecl。
-
@Hans No.
data_api_func_tab是数据导出而不是函数导出。 -
api_init是一个函数。