Managed C++/CLI 프로젝트 설정
공용 언어 런타임 지원
code : https://github.com/EomTaeWook/Cpp-CLI-Marshalling
Native -> Managed C++/CLI 메시지를 전파를 할시엔 OutGoingMessage를 사용
Managed C++/CLI -> C# event 로 Notify가 나감
C# -> Managed C++/CLI -> Native InCommingMessage으로 사용
Dll Loading을 통한 Runtime Class 생성 예제
Managed C++/CLI
CppInterface.h
#pragma once
namespace Cpp
{
public interface class CppInterface
{
public:
delegate void OnNotifyHandler(System::Object^ sender, System::String^ message);
public:
void Init();
void Run();
void Stop();
void InCommingMessage(System::String^ inCommingMessage);
event OnNotifyHandler^ OnNotify;
};
}
CppInterface.cpp
#include "CppInterface.h"
Dll을 뽑기위해 Cpp 파일은 헤더 추가만
Managed C++/CLI
CppWrapper.h
Native.h
#pragma once
#include <string>
//C++ Native 이며 Lib로 빌드가 되어야함.
class Native
{
public:
typedef void(__stdcall *OutGoingCallback)(std::string);
public:
Native();
~Native();
private:
//Wrapping 되는 C++/cli 함수 포인터 저장
OutGoingCallback _onNotify;
public:
void Init(OutGoingCallback onNotify);
void InCommingMessage(std::string inCommingMessage);
void Stop();
private:
void OutGoingMessage(std::string outGoingMessage);
};
Native.cpp
#include "Native.h"
#include <stdio.h>
Native::Native()
{
}
Native::~Native()
{
}
void Native::Init(OutGoingCallback onNotify)
{
_onNotify = onNotify;
OutGoingMessage("Cpp UnManaged class Init Complete");
}
void Native::OutGoingMessage(std::string outGoingMessage)
{
//printf("Cpp UnManaged class -> Managed class -> C# Outgoing Message\n");
_onNotify(outGoingMessage);
}
void Native::InCommingMessage(std::string inCommingMessage)
{
//printf("C#-> Managed class -> Cpp UnManaged class -> inComming Message\n");
printf("Cpp Notify InCommingMessage:: %s\n", inCommingMessage.c_str());
}
void Native::Stop()
{
printf("Cpp Native Stop\n");
}
C#
Entry.cs
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace ProtoType
{
public class Entry :IDisposable
{
private ConcurrentDictionary<string, ProcessObject> _processes;
private bool _disposed;
public Entry()
{
_processes = new ConcurrentDictionary<string, ProcessObject>();
}
protected void Dispose(bool isDispose)
{
foreach(var p in _processes)
{
p.Value.CancellationToken.Cancel();
}
_processes.Clear();
_disposed = isDispose;
}
public void Dispose()
{
if (_disposed)
return;
Dispose(true);
}
//각 DLL로 부터 Notify가 들어오는 구간
private void OnNotify(object sender, string message)
{
Console.WriteLine($"Center Notify Recive : {message}");
//등록되어 있는 Dll 클래스에게 Notify 전달
foreach (var item in _processes)
{
var method = item.Value.DllProcess.GetType().GetMethod("InCommingMessage", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
method?.Invoke(item.Value.DllProcess, new object[] { message });
}
}
private void ProcessStart(object process)
{
ProcessObject state = process as ProcessObject;
var stopMethod = state.DllProcess.GetType().GetMethod("Stop", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
while (!state.CancellationToken.IsCancellationRequested)
{
try
{
if (state.Started)
continue;
var initMethod = state.DllProcess.GetType().GetMethod("Init", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
initMethod?.Invoke(state.DllProcess, null);
var runMethod = state.DllProcess.GetType().GetMethod("Run", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
runMethod?.Invoke(state.DllProcess, null);
state.Started = true;
}
catch(Exception ex)
{
stopMethod?.Invoke(state.DllProcess, null);
state.Started = false;
Trace.WriteLine(ex.Message);
}
finally
{
Thread.Sleep(1000);
}
}
if (state.DllProcess is CS.CSInterface)
{
var p = state.DllProcess as CS.CSInterface;
p.OnNotify -= OnNotify;
}
else if (state.DllProcess is Cpp.CppInterface)
{
var p = state.DllProcess as Cpp.CppInterface;
p.OnNotify -= OnNotify;
}
stopMethod? .Invoke(state.DllProcess, null);
Console.WriteLine($"Thread Close");
}
public void Start()
{
var files = Directory.GetFiles(Environment.CurrentDirectory).Where(r=>r.EndsWith("dll")).ToList();
foreach(var file in files)
{
var assem = Assembly.LoadFile(file);
var types = assem.GetExportedTypes().Where(r => r.IsClass &&
r.GetInterfaces().Any(i => i.Equals(typeof(Cpp.CppInterface))) ||
r.GetInterfaces().Any(i => i.Equals(typeof(CS.CSInterface)))
).ToList();
foreach (var type in types)
{
var process = new ProcessObject();
process.CancellationToken = new CancellationTokenSource();
process.DllProcess = Activator.CreateInstance(type);
if (process.DllProcess is CS.CSInterface)
{
var p = process.DllProcess as CS.CSInterface;
p.OnNotify += OnNotify; //옵저버 패턴 생각하면 됨
}
else if (process.DllProcess is Cpp.CppInterface)
{
var p = process.DllProcess as Cpp.CppInterface;
p.OnNotify += OnNotify; //옵저버 패턴 생각하면 됨
}
_processes.TryAdd(type.Name, process);
}
}
foreach (var process in _processes)
{
ThreadPool.QueueUserWorkItem(ProcessStart, process.Value);
}
}
}
}
'개발관련 > C#' 카테고리의 다른 글
.net core 패킷 데이터가 30K 바이트보다 큰 경우 디스크에 저장 (0) | 2022.04.06 |
---|---|
소켓 비정상 종료 처리 TcpKeepAlive (0) | 2018.09.13 |
sql compact 4.0 설정 (2) | 2018.07.30 |
SignalR MessageFormat 및 구동 시퀸스 (0) | 2018.07.14 |
네트워크 공유 폴더 접근 (0) | 2018.05.09 |