Обработка событий C # в неуправляемом коде C ++ с помощью COM-Interop - PullRequest
1 голос
/ 15 января 2012

У меня есть TcpSocketServer, написанный на C #, и я хочу использовать его на нативном C ++ без CLI.Класс вызывает события при подключении / отключении клиента и при получении данных.До сих пор сервер работал и принимает соединение, но я все еще не могу отправлять / получать данные.

Обратите внимание, что это один из нескольких классов, с которыми мне нужно работать, поэтому, пожалуйста, не предлагайте мне использоватьродные сокеты C ++.

(соответствующий) код C # ниже:

[ComVisible(true)]
public delegate void TcpClientConnectedEventHandler(Socket s);

[ComVisible(true)]
public delegate void TcpClientDisconnectedEventHandler(EndPoint ep);

[ComVisible(true)]
public delegate void TcpDataReceivedEventHandler(TcpPacket p);

[ComVisible(true)]
[Guid("7cf49dcd-c11b-4e94-9f73-d5a24fe027c3")]
public interface ISocketTcpServer
{
    event TcpClientConnectedEventHandler ClientConnected;
    event TcpClientDisconnectedEventHandler ClientDisconnected;
    event TcpDataReceivedEventHandler DataReceived;

    [ComVisible(true)]
    int SendToAll(byte[] buffer);
}

Теперь в C ++ у меня есть следующий (соответствующий) код:

// Function Prototypes
void onClientConnected();
void onClientDisconnected();
void onDataReceived(ITcpPacket *packet);
VARIANT_BOOL started(ISocketTcpServer *server);
long send(ISocketTcpServer *server, char *s);

int main(int argc, char* argv[])
{
    ISocketTcpServer *server = NULL;
    _TcpDataReceivedEventHandler *dataReceivedPtr = NULL;
    _TcpClientConnectedEventHandler *clientConnectedPtr = NULL;
    _TcpClientDisconnectedEventHandler *clientDisconnectedPtr = NULL;
    char sInput[1024];

    std::cout << "C# Sockets Interop example.\r\n";

    // Initialize COM.
    CoInitialize(NULL);

    // Create the interface pointers.
    HRESULT hr = CoCreateInstance(__uuidof(SocketTcpServer), NULL,
        CLSCTX_INPROC_SERVER, __uuidof(ISocketTcpServer), (void **)&server);

    if((hr != S_OK) || (server == NULL))
    {
        std::cout << "Create instance failed\r\n";
        CoUninitialize();
        return 0;
    }

    // Configure TCP Server
    server->put_Port(2000);
    dataReceivedPtr = (_TcpDataReceivedEventHandler *)&onDataReceived;
    clientConnectedPtr = (_TcpClientConnectedEventHandler *)&onClientConnected;
    clientDisconnectedPtr =
        (_TcpClientDisconnectedEventHandler *)&onClientDisconnected;

    /* HERE IS WHERE I SET UP THE EVENTS */
    server->add_ClientConnected(clientConnectedPtr);
    server->add_ClientDisconnected(clientDisconnectedPtr);
    server->add_DataReceived(dataReceivedPtr);

    // Start TCP Server
    std::cout << "Starting TCP Server on port 2000.\r\n";
    server->Start();
    while(!started(server)) Sleep(100);
    while(started(server))
    {
        std::cin >> sInput;
        send(server, sInput);
    }

    // Uninitialize COM.
    CoUninitialize();
    return 0;
}

long send(ISocketTcpServer *server, char *s)
{
    long result = 0;
    server->SendToAll((SAFEARRAY *) s, &result);
    return result;
}

Все остальные функции имеют свое определение и работают нормально, поэтому я их не включил.

Основной вопрос: как должны быть объявлены функции, которые будут обрабатывать события, чтобы это работало.Я предполагаю, что они не работают, потому что они не соответствуют ассоциированному делегату, но я не могу получить доступ к классам Socket и EndPoint .NET Framework.

Также сопоставлен метод

SendToAll(byte[] buffer):int

к функции

SendToAll(SAFEARRAY *buffer, long *pRetVal):HRESULT

, но, может быть, это проблема приведения.

Любая помощь или совет, которые вы можете мне дать, будут полезны.

Заходите заранее.

1 Ответ

0 голосов
/ 15 января 2012

Предполагая, что вы знаете, как обрабатывать события от стандартного COM-компонента в VC ++ (я не разработчик C ++, поэтому не могу помочь с этой частью), тогда лучше всего сделать так, чтобы ваш C # выгляделкак будто это стандартный COM-компонент, использующий ComSourceInterfacesAttribute .MSDN имеет упрощенный How To при выполнении этого.

Ваш код C # в конечном итоге будет выглядеть примерно так (обратите внимание, я удалил атрибуты [ComVisible(true)], так как они не нужны, если ваша сборкапомечено):

public delegate void TcpClientConnectedEventHandler(Socket s);
public delegate void TcpClientDisconnectedEventHandler(EndPoint ep);
public delegate void TcpDataReceivedEventHandler(TcpPacket p);

public interface ISocketTcpServerEvents
{
    void ClientConnected;
    void ClientDisconnected;
    void DataReceived;
}

[ComSourceInterfaces(typeof(ISocketTcpServerEvents))]
public class SocketTcpServer
{   
    public event TcpClientConnectedEventHandler ClientConnected;
    public event TcpClientDisconnectedEventHandler ClientDisconnected;
    public event TcpDataReceivedEventHandler DataReceived;

    int SendToAll(byte[] buffer);
}
...