提问人:신성영 提问时间:9/22/2023 更新时间:10/12/2023 访问量:42
如何使用 p/invoke 将 C++ TCP 通信数据传递给 C#
how to passing c++ tcp communication data to c# with p/invoke
问:
我想继续通过TCP通信将从C++(不是C++ / CLI)接收的数据发送到C#。
我写了这样的代码:
C++
LibMain.h
#pragma once
#include <string.h>
#include <oleauto.h>
extern "C"
{
__declspec(dllexport) BSTR __stdcall cpp_test(char* str);
__declspec(dllexport) SAFEARRAY* cpp_test2(char** str_arr, int i);
}
LibMain.cpp
BSTR __stdcall cpp_test(char* str)
{
wchar_t* pStr;
int strSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, NULL);
pStr = new WCHAR[strSize];
MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, pStr, strSize);
return SysAllocString(pStr);
}
SAFEARRAY* cpp_test2(char** str_arr, int len)
{
SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, len);
BSTR HUGEP* arr = NULL;
SafeArrayAccessData(psa, reinterpret_cast<void HUGEP**>(&arr));
for (int i = 0; i < len; i++) {
char* str = str_arr[i];
wchar_t* pStr;
int strSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, NULL);
pStr = new WCHAR[strSize];
MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, pStr, strSize);
arr[i] = SysAllocString(pStr);
}
SafeArrayUnaccessData(psa);
return psa;
}
c#
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
[DllImport(@"CPPSampleLibDll.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string cpp_test(string str);
[DllImport(@"CPPSampleLibDll.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.SafeArray)]
static extern string[] cpp_test2(string[] str_arr, int iSize);
string rootPath = Path.GetFullPath(@".");
SetDllDirectory(rootPath);
string[] test = new string[2];
test[0] = "test0";
test[1] = "test1";
string[] test2 = cpp_test2(test, test.Length);
cpp_test("test2");
foreach (string s in test2)
{
MessageBox.Show(s);
}
MessageBox.Show(cpp_test("test2"));
此代码按预期传递字符串和字符串数组,并显示一个消息框。
我想继续通过TCP通信将从C++(不是C++ / CLI)接收的数据发送到C#。
答:
0赞
신성영
10/12/2023
#1
xx.h
#pragma once
#include <string.h>
#include <oleauto.h>
#include <iostream>
#include <string>
#include <Winsock2.h>
extern "C"
{
__declspec(dllexport) int InitializeWinsock();
__declspec(dllexport) void CleanupWinsock();
__declspec(dllexport) int StartServer(int port);
__declspec(dllexport) void CloseServer();
SOCKET serverSocket;
typedef void(__stdcall* CallbackDelegate)(const char* message);
__declspec(dllexport) void WaitForConnections(CallbackDelegate callback);
}
xx.cpp
#include "pch.h"
#include "LibMain.h"
#pragma comment(lib, "Ws2_32.lib")
int InitializeWinsock()
{
WSADATA wsaData;
return WSAStartup(MAKEWORD(2, 2), &wsaData);
}
void CleanupWinsock()
{
WSACleanup();
}
int StartServer(int port)
{
struct sockaddr_in serverAddr;
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
return -1;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(port);
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
closesocket(serverSocket);
return -1;
}
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
closesocket(serverSocket);
return -1;
}
return 0;
}
SOCKET clientSocket;
void WaitForConnections(CallbackDelegate callback)
{
while (true) {
clientSocket = accept(serverSocket, NULL, NULL);
if (clientSocket != INVALID_SOCKET) {
char buffer[1024];
int recvResult = recv(clientSocket, buffer, sizeof(buffer), 0);
if (recvResult > 0) {
buffer[recvResult] = '\0';
callback(buffer); // Call the provided callback with the received message
}
}
}
}
void CloseServer()
{
closesocket(clientSocket);
}
C#
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Wpf.Ui.Mvvm.Contracts;
using Wpf.Ui.Mvvm.Services;
using WpfSampleViewerApp.Commons;
using WpfSampleViewerApp.ViewModels;
using WpfSampleViewerApp.ViewModels.Pages;
using WpfSampleViewerApp.Views;
using WpfSampleViewerApp.Views.Pages;
namespace WpfSampleViewerApp
{
public partial class App : Application
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
Process _process;
[DllImport(@"CPPSampleLibDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int InitializeWinsock();
[DllImport(@"CPPSampleLibDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void CleanupWinsock();
[DllImport(@"CPPSampleLibDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int StartServer(int port);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void CallbackDelegate(string message);
[DllImport(@"CPPSampleLibDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void WaitForConnections(CallbackDelegate callback);
static void TCPMessageReceivedCallback(string message)
{
MessageBox.Show("Received message from client: " + message);
}
[DllImport(@"CPPSampleLibDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void CloseServer();
void OnStartup(object sender, StartupEventArgs e)
{
try
{
string rootPath = Path.GetFullPath(@".");
SetDllDirectory(rootPath);
Thread tcpThread = new Thread(new ThreadStart(tcpRun));
tcpThread.Start();
_process = new Process();
_process.StartInfo.FileName = @"WebAPISampleApp.exe";
_process.StartInfo.Arguments = null;
_process.Start();
MainWindow mainWindow = new MainWindow();
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel(mainWindow);
mainWindow.DataContext = mainWindowViewModel;
mainWindow.ShowDialog();
}
catch (Exception err)
{
Log log = new Log();
log.Write("err_log", err.StackTrace);
Environment.Exit(0);
}
}
void tcpRun()
{
int TCP_result = InitializeWinsock();
if (TCP_result != 0)
{
MessageBox.Show("Winsock initialization failed. Error code: " + TCP_result);
return;
}
try
{
int TCP_port = 8888;
TCP_result = StartServer(TCP_port);
if (TCP_result != 0)
{
MessageBox.Show("Failed to start server.");
return;
}
CallbackDelegate callbackDelegate = new CallbackDelegate(TCPMessageReceivedCallback);
GCHandle.Alloc(callbackDelegate);
WaitForConnections(callbackDelegate);
}
finally
{
CleanupWinsock();
}
}
}
}
评论