需要在 C# 应用中使用C++代码'block'
Need to use a 'block' of C++ code in C# app
我得到了一个 c++ 代码块,看起来像是来自一个使用用于向其他程序发送消息的共享内存。
c ++代码还没有 #include 或任何东西。我得到了在我的 C# 应用程序中使用的代码,我被困住了。我有点了解代码的作用,但我不太了解它,无法将其转换为 C#,因为我对编码很陌生。
我的问题是,能够在项目中使用代码功能的最简单方法是什么?最终结果是将消息发送到另一个程序,这反过来又会做一些我不担心的事情。
我尝试在我的解决方案中创建不同的 c++ 项目和文件类型,以便稍后使用引用链接它们,但我永远无法让它正确编译。
如果您有一些建议或好地方,请告诉我。我总是可以提供更多信息。
代码(我不得不删除评论,对不起(:
UINT WM_HELO_ZOOM_XYZ = RegisterWindowMessage("WM_HELO_ZOOM_XYZ");
int HELO_Broadcast_Zoom_Message(
double dbX,
double dbY,
double dbZ,
UINT uMessage=WM_HELO_ZOOM_XYZ) {
#ifndef HELO_
typedef struct {
UINT uMajVersion;
UINT uMinVersion;
DWORD dwReserved;
double dbX;
double dbY;
double dbZ;
} HELOCoordsStruct;
#endif
char *szSharedMemory = "HELO-_Coords";
char szErr[_MAX_PATH*3];
HANDLE hMem = OpenFileMapping(FILE_MAP_WRITE, FALSE, szSharedMemory);
if (NULL == hMem) {
return(0);
}
void *pvHead = MapViewOfFile(hMem, FILE_MAP_WRITE, 0,0,0);
if (NULL == pvHead) {
CloseHandle(hMem);
sprintf(szErr, "Unable to view", szSharedMemory);
AfxMessageBox(szErr, MB_OK|MB_ICONSTOP);
return(0);
}
HELOCoordsStruct *pHELOCoords = (HELOCoordsStruct *)pvHead;
BOOL bVersionOk=FALSE;
if (1 == pHELOCoords->uMajorVersion) {
if (WM_HELO_ZOOM_XYZ==uMessage) {
pHELOCoords->dbX = dbX;
pHELOCoords->dbY = dbY;
pHELOCoords->dbZ = dbZ;
}
bVersionOk=TRUE;
}
else {
sprintf(szErr, "Unrecognized HELO- shared memory version: %d.%d", pHELOCoords->uMajVersion, pHELOCoords->uMinVersion);
AfxMessageBox(szErr, MB_OK);
}
if (NULL != hMem) CloseHandle(hMem);
UnmapViewOfFile(pvHead);
if (bVersionOk) {
PostMessage(HWND_BROADCAST,uMessage,0,0);
return(1);
}
else return(0);
}
编辑:反馈完全不真实。我必须说,社区肯定会宠坏这里的人们。
谢谢Kevin
我认为你有三个选择:
- 创建一个类库类型的托管C++项目,将代码放入其中,从主应用引用此项目。
- 创建一个非托管C++ DLL 项目,将代码放入一个或多个函数中,导出函数(使用 .def 文件(,然后生成项目。使用
[DllImport]
属性使用该 dll 中的函数。(见这里和这里( - 将代码转换为 C#。这将需要一些非托管代码、Win32 和 P/Invoke 的知识(请参阅此处和此处(。当我看到你的代码时,这需要一点时间!
这是您转换后的代码(选项 3(:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace UnmanagedBlock
{
public class ConvertedClass
{
public uint WM_HELO_ZOOM_XYZ = RegisterWindowMessageA("WM_HELO_ZOOM_XYZ"); // Your code uses the ANSI string
int HELO_Broadcast_Zoom_Message(
double dbX, double dbY, double dbZ, uint uMessage) // Porting the default value for 'uMessage' is not possible
{
string szSharedMemory = "HELO-_Coords";
IntPtr hMem = OpenFileMapping(FileMapAccessRights.Write, FALSE, szSharedMemory);
if (IntPtr.Zero == hMem)
return 0;
IntPtr pvHead = MapViewOfFile(hMem, FileMapAccessRights.Write, 0, 0, UIntPtr.Zero);
if (IntPtr.Zero == pvHead)
{
CloseHandle(hMem);
MessageBox.Show(
"Unable to view " + szSharedMemory, // Your code does not concat these two strings.
"Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return 0;
}
HELOCoordsStruct pHELOCoords = new HELOCoordsStruct();
Marshal.PtrToStructure(pvHead, pHELOCoords);
int bVersionOk = FALSE;
if (1 == pHELOCoords.uMajVersion) // I think it had a typo (it was uMajorVersion)
{
if (WM_HELO_ZOOM_XYZ == uMessage)
{
pHELOCoords.dbX = dbX;
pHELOCoords.dbY = dbY;
pHELOCoords.dbZ = dbZ;
}
Marshal.StructureToPtr(pHELOCoords, pvHead, false);
bVersionOk = TRUE;
}
else
{
MessageBox.Show(
"Unrecognized HELO- shared memory version: " +
pHELOCoords.uMajVersion.ToString() + "." + pHELOCoords.uMinVersion.ToString());
}
if (IntPtr.Zero != hMem)
CloseHandle(hMem);
UnmapViewOfFile(pvHead);
if (bVersionOk == TRUE)
{
PostMessage(HWND_BROADCAST, uMessage, 0, 0);
return 1;
}
else
return 0;
}
[StructLayout(LayoutKind.Sequential)]
private class HELOCoordsStruct
{
public uint uMajVersion;
public uint uMinVersion;
public uint dwReserved;
public double dbX;
public double dbY;
public double dbZ;
}
[DllImport("user32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public static extern uint RegisterWindowMessageW([In]string lpString);
[DllImport("user32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern uint RegisterWindowMessageA([In]string lpString);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern IntPtr OpenFileMapping(FileMapAccessRights dwDesiredAccess, int bInheritHandle, [In]String lpName);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccessRights dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall)]
public static extern int UnmapViewOfFile(IntPtr lpBaseAddress);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall)]
public static extern int CloseHandle(IntPtr hObject);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
public const int FALSE = 0, TRUE = 1;
public enum FileMapAccessRights : uint
{
Write = 0x2,
Read = 0x4,
Execute = 0x20,
}
public const IntPtr HWND_BROADCAST = (IntPtr)0xffff;
}
}
我已经进行了精确的转换,我认为它应该可以正常工作,但是我还没有对其进行测试。
让我知道它是否有效。
可以将C++代码转储到 Visual C++ 项目中并生成该项目。 构建它时,进入项目设置并选择生成 tlb 文件的选项(它是 c++/.net 互操作的代理类,我不记得选项的名称了(。
完成此操作后,可以从 C# 项目添加对 tlb 互操作程序集的引用。
另外,请在此处查找Microsoft示例 http://msdn.microsoft.com/en-us/library/fx82zhxa.aspx
如果您在此处发布代码,可能会有一些好人为您将代码从 C++ 移植到 C#。但是,为了将来在处理从 .NET 应用程序中使用本机C++代码时参考,可以使用 .NET 框架的互操作服务来引用本机 dll 中的本机函数。
为此,需要在 C++ 和 C# 方面执行一些步骤。首先,您需要将入口点构建为C++中的导出函数。
例如,假设我想编写一个简单的C++函数将 2 个数字相加,然后从 C# 应用调用它,我必须执行以下操作:
第 1 步:编写 C++ 函数。为了让外部源找到您的函数,您需要让编译器知道该函数将被"导出"。需要注意的一点是,如果要从导出的函数中调用其他函数,则无需将它们全部标记为已导出。
因此,让我们在C++中编写"add"函数:
#define DLLEXPORT extern "C" declspec(dllexport)
DLLEXPORT int __cdecl add(int x, int y)
{
return (x + y);
}
第一行定义我们将用于标记导出方法的宏。extern "C"
部分告诉编译器避免修改函数的导出名称(因此它将始终是"add",而不是类似@YZadd_(,接下来是标记为DLLEXPORT的函数定义。在我继续之前,还有一点关于导出函数中的"名称重整",那就是声明__stdcall
或其任何变体的函数(WINAPI(。等(。标记为导出并使用调用约定__stdcall extern "C"
声明的函数将始终附加@X
其中X
是函数参数的字节数(因此对于上面的示例,如果add
声明为__stdcall
则导出的函数名称将add@8
。如果 C# 在查找函数时遇到问题,请记住这一点。
现在,事情的C++方面已经完成,将其编译为 DLL 并转移到 C#。
在 C# 中,导入外部函数相当简单。首先,您需要引用 InteropServices
命名空间:
using System.Runtime.InteropServices;
然后你需要做一个[DllImport]
声明:
[DllImport(@"path to your C++ dll here")]
public static extern int add(int x, int y) //make sure the function definition matches.
如果函数名称匹配,则导入函数所需的全部内容应为该函数。现在,您可以像调用 C# 中的任何普通函数一样调用add
int x = 5;
int y = 10;
int z = add(x, y); //z should be 10
以上总结了如何简单地导出C++函数并从 C# 应用程序调用它们。
如果无法使C++代码按原样工作,则尝试将其移植到 C# 应用中是没有意义的。
首先找出C++代码(阅读所用 API 的 MSDN 文档,询问为您提供代码的人员,发布特定问题(。一旦你更好地理解它并可以使其工作,那么你将有更好的机会找出在 C# 中执行所需操作的最佳方法。
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么在这个代码结束循环中没有得到结束
- 在c代码之间共享数据的最佳方式
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值