如何使用p/invoke将c++ tcp通信数据传递给c#

问题描述 投票:0回答:1

我想继续通过 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#。

c# c++ tcp pinvoke
1个回答
0
投票

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();
            }
        }

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.