学习研究Godot 4,很爽,虽然很庞杂,但相对于自己的水平来说,很强大,尤其是vulkan这块直接打包可用,省得自己从头琢磨。
一点一点地消化、优化与完善,最终才能成为自己的。
这段时间就在Godot的基础上,增加管道通信,实现Godot与本机已有程序进行通信,以备后续的无缝集成整合。
其实,Godot支持各种网络通信,支持UDP、TCP等。为什么非要实现管道通信,本质上还是想看看改造效果。最终目标是实现Godot软件与自己的DrGraph软件的管道通信
DrGraph端处理
为实现管道通信,根据Windows命名管道通信原理进行相应模块化实现。
class TDllData {
void __fastcall CheckType(unsigned char destType);
public:
__fastcall TDllData(unsigned char t = DRGRAPH_DLL_TYPE_NULL);
__fastcall TDllData(const TDllData& copy);
__fastcall ~TDllData();
bool __fastcall IsEof() { return type == DRGRAPH_DLL_TYPE_NULL; };
UnicodeString __fastcall GetHint();
unsigned char type;
union {
bool value_bool;
char value_char;
unsigned char value_uchar;
wchar_t value_wchar;
short value_short;
unsigned short value_ushort;
int value_int;
unsigned int value_uint;
long value_long;
unsigned long value_ulong;
double value_double;
long long value_longlong;
unsigned long long value_ulonglong;
} value ;
UnicodeString value_string;
TDllData * __fastcall operator = (const TDllData & equal);
operator bool();
operator char();
operator unsigned char();
operator wchar_t();
operator short();
operator unsigned short();
operator int();
operator unsigned int();
operator long();
operator unsigned long();
operator double();
operator long long();
operator unsigned long long();
operator UnicodeString();
};
class TDllStream : public CbwStream {
typedef CbwStream inherited;
TMemoryStream * FMemoryStream;
DRGRAPH_PROPERTY(bool, Finished);
DRGRAPH_PROPERTY(bool, WCharFlag);
DRGRAPH_PROPERTY(int, WCharSize);
public:
__fastcall TDllStream();
__fastcall TDllStream(BYTE * datas, int len);
__fastcall TDllStream(wchar_t * datas, int len);
__fastcall ~TDllStream();
void __fastcall Finish();
TDllData __fastcall Next();
void __fastcall Reset();
UnicodeString __fastcall GetHint(UnicodeString desc = L"");
int __fastcall NextFunType();
__fastcall operator BYTE *();
__fastcall operator wchar_t *();
virtual bool __fastcall writeBytes(const void * p, int len) {
CbwStream::writeBytes(p, len);
FFinished = false;
}
//#ifdef DRGRAPH_USE_OPENCV
// friend TDllStream & operator << (TDllStream & cofs, cv::Mat& mat);
// friend TDllStream & operator >> (TDllStream & cifs, cv::Mat& mat);
//#endif
friend TDllStream & operator << (TDllStream & cofs, NStreamIOControl ctrl) {
if(ctrl == ioReset)
cofs.Reset();
if(ctrl == ioRewind)
cofs.Rewind();
if(ctrl == ioFinish)
cofs.Finish();
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, bool value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_BOOL);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %s", DllType2String(dlltype), TTypeConvert::Bool2String(value));
unsigned char b = value ? 1 : 0;
cofs.writeBytes(&b, sizeof(unsigned char));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, char value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_CHAR);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %d[0X%02X, %c]", DllType2String(dlltype), int(value), value, value);
cofs.writeBytes(&value, sizeof(char));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, unsigned char value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_UCHAR);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %d[0X%02X, %c]", DllType2String(dlltype), int(value), value, value);
cofs.writeBytes(&value, sizeof(unsigned char));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, wchar_t value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_WCHAR);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %s", DllType2String(dlltype), UnicodeString(value));
cofs.writeBytes(&value, sizeof(wchar_t));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, short value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_SHORT);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %d", DllType2String(dlltype), int(value));
cofs.writeBytes(&value, sizeof(short));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, unsigned short value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_USHORT);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %d", DllType2String(dlltype), int(value));
cofs.writeBytes(&value, sizeof(unsigned short));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, int value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_INT);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %d", DllType2String(dlltype), int(value));
cofs.writeBytes(&value, sizeof(int));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, unsigned int value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_UINT);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %d", DllType2String(dlltype), int(value));
cofs.writeBytes(&value, sizeof(unsigned int));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_LONG);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %ld", DllType2String(dlltype), value);
cofs.writeBytes(&value, sizeof(long));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, unsigned long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_ULONG);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %lu", DllType2String(dlltype), value);
cofs.writeBytes(&value, sizeof(unsigned long));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, long long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_LONGLONG);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %lld", DllType2String(dlltype), value);
cofs.writeBytes(&value, sizeof(long long));
return cofs;
}
//
friend TDllStream & operator << (TDllStream & cofs, unsigned long long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_ULONGLONG);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %llu", DllType2String(dlltype), value);
cofs.writeBytes(&value, sizeof(unsigned long long));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, float value) {
double d = value;
cofs << d;
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, double value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_DOUBLE);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %s", DllType2String(dlltype), TTypeConvert::Double2String(value, 3));
cofs.writeBytes(&value, sizeof(double));
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, char*str) {
UnicodeString string = str;
cofs << string;
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, wchar_t*str) {
UnicodeString string = str;
cofs << string;
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, UnicodeString value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_STRING);
if(cbw_debug_flag)
THelper::Logi(L"写入[%s]类型 > %s", DllType2String(dlltype), value);
int iTextLen = WideCharToMultiByte(CP_UTF8, 0, value.w_str(), -1, NULL, 0, NULL, NULL);
char * chBuffer = new char[iTextLen + 1];
WideCharToMultiByte(CP_UTF8, 0, value.w_str(), -1, chBuffer, iTextLen, NULL, NULL);
cofs.writeBytes(&iTextLen, sizeof(int));
cofs.writeBytes(chBuffer, iTextLen);
delete[]chBuffer;
return cofs;
}
friend TDllStream & operator >> (TDllStream & cifs, UnicodeString & q) {
int length;
cifs >> length;
char * chBuffer = new char[length + 1];
cifs.readBytes(chBuffer, length);
chBuffer[length] = '\0';
if(cifs.WCharFlag == false) {
int wLength = length + 1;
wchar_t *wcBuffer = new wchar_t[wLength];
MultiByteToWideChar(CP_UTF8, 0, chBuffer, wLength, wcBuffer, wLength);
wcBuffer[length] = L'\0';
q = UnicodeString(wcBuffer);
delete wcBuffer;
} else
q = UnicodeString(chBuffer);
delete chBuffer;
return cifs;
}
friend TDllStream & operator << (TDllStream & cofs, Variant& data) {
switch(data.Type()) {
case varBoolean: cofs << bool(data); break;
case varEmpty:
case varNull: cofs << 0; break;
case varSingle: cofs << float(data); break;
case varDouble: cofs << double(data); break;
case varString:
case varUString: cofs << (wchar_t *)(data); break;
case varSmallint:
case varInteger:
case varWord: cofs << int(data); break;
case varInt64: cofs << __int64(data); break;
case varUInt64: cofs << (unsigned __int64)(data); break;
case varByte: cofs << (unsigned char)(data); break;
case 0x10: cofs << short(data); break; // varShortInt
case varLongWord: cofs << long(data); break;
default: cofs << (wchar_t *)(data); break;
}
return cofs;
}
friend TDllStream & operator << (TDllStream & cofs, TDllData & data) {
if(data.type == DRGRAPH_DLL_TYPE_STRING)
cofs << data.value_string;
else if(data.type == DRGRAPH_DLL_TYPE_INT)
cofs << data.value.value_int;
else if(data.type == DRGRAPH_DLL_TYPE_DOUBLE)
cofs << data.value.value_double;
else if(data.type == DRGRAPH_DLL_TYPE_BOOL)
cofs << data.value.value_bool;
else if(data.type == DRGRAPH_DLL_TYPE_UCHAR)
cofs << data.value.value_uchar;
else if(data.type == DRGRAPH_DLL_TYPE_CHAR)
cofs << data.value.value_char;
else if(data.type == DRGRAPH_DLL_TYPE_WCHAR)
cofs << data.value.value_wchar;
else if(data.type == DRGRAPH_DLL_TYPE_SHORT)
cofs << data.value.value_short;
else if(data.type == DRGRAPH_DLL_TYPE_LONG)
cofs << data.value.value_long;
else if(data.type == DRGRAPH_DLL_TYPE_USHORT)
cofs << data.value.value_ushort;
else if(data.type == DRGRAPH_DLL_TYPE_UINT)
cofs << data.value.value_uint;
else if(data.type == DRGRAPH_DLL_TYPE_ULONG)
cofs << data.value.value_ulong;
else if(data.type == DRGRAPH_DLL_TYPE_LONGLONG)
cofs << data.value.value_longlong;
else if(data.type == DRGRAPH_DLL_TYPE_ULONGLONG)
cofs << data.value.value_ulonglong;
else if(data.type == DRGRAPH_DLL_TYPE_NULL)
cofs.Finish();
return cofs;
}
///**************************************************************
friend TDllStream & operator >> (TDllStream & cifs, TDllData & data) {
if(data.type == DRGRAPH_DLL_TYPE_STRING)
cifs >> data.value_string;
else if(data.type == DRGRAPH_DLL_TYPE_INT)
cifs.readBytes(&data.value, sizeof(int));
else if(data.type == DRGRAPH_DLL_TYPE_DOUBLE)
cifs.readBytes(&data.value, sizeof(double));
else if(data.type == DRGRAPH_DLL_TYPE_BOOL)
cifs.readBytes(&data.value, sizeof(unsigned char));
else if(data.type == DRGRAPH_DLL_TYPE_UCHAR)
cifs.readBytes(&data.value, sizeof(unsigned char));
else if(data.type == DRGRAPH_DLL_TYPE_CHAR)
cifs.readBytes(&data.value, sizeof(char));
else if(data.type == DRGRAPH_DLL_TYPE_WCHAR)
cifs.readBytes(&data.value, sizeof(wchar_t));
else if(data.type == DRGRAPH_DLL_TYPE_SHORT)
cifs.readBytes(&data.value, sizeof(short));
else if(data.type == DRGRAPH_DLL_TYPE_LONG)
cifs.readBytes(&data.value, sizeof(long));
else if(data.type == DRGRAPH_DLL_TYPE_USHORT)
cifs.readBytes(&data.value, sizeof(unsigned short));
else if(data.type == DRGRAPH_DLL_TYPE_UINT)
cifs.readBytes(&data.value, sizeof(unsigned int));
else if(data.type == DRGRAPH_DLL_TYPE_ULONG)
cifs.readBytes(&data.value, sizeof(unsigned long));
else if(data.type == DRGRAPH_DLL_TYPE_LONGLONG)
cifs.readBytes(&data.value, sizeof(long long));
else if(data.type == DRGRAPH_DLL_TYPE_ULONG)
cifs.readBytes(&data.value, sizeof(unsigned long long));
else if(data.type == DRGRAPH_DLL_TYPE_NULL)
return cifs;
return cifs;
}
friend TDllStream & operator << (TDllStream & cofs, TPoint point) {
cofs << point.x;
cofs << point.y;
return cofs;
}
friend TDllStream & operator >> (TDllStream & cifs, TPoint& point) {
cifs >> point.x;
cifs >> point.y;
return cifs;
}
friend TDllStream & operator << (TDllStream & cofs, TRect rect) {
cofs << rect.left;
cofs << rect.top;
cofs << rect.right;
cofs << rect.bottom;
return cofs;
}
friend TDllStream & operator >> (TDllStream & cifs, TRect& rect) {
cifs >> rect.left;
cifs >> rect.top;
cifs >> rect.right;
cifs >> rect.bottom;
return cifs;
}
};
#define PIPE_CONNECTING_STATE 0
#define PIPE_READING_STATE 1
#define PIPE_WRITING_STATE 2
#define PIPE_INSTANCES 4
#define PIPE_TIMEOUT 5000
#define PIPE_BUFSIZE 4096
#define DRSTREAM_FUNCTION_NONE 0
#define DRSTREAM_FUNCTION_SET 1
#define DRSTREAM_FUNCTION_GET 2
#define DRSTREAM_FUNCTION_STATUS 3
typedef struct {
OVERLAPPED oOverlap;
HANDLE hPipeInst;
TCHAR wRequestBuffer[PIPE_BUFSIZE];
DWORD cbRead;
char wResponseBuffer[PIPE_BUFSIZE];
DWORD cbWrite;
DWORD dwState;
BOOL fPendingIO;
} PIPEINST, *LPPIPEINST;
class TPipeStream : public TDllStream {
class TPipeThread : public TThread {
friend class TPipeStream;
PIPEINST Pipe[PIPE_INSTANCES];
HANDLE hEvents[PIPE_INSTANCES];
private:
HANDLE hPipe;
TPipeStream * FOwnerStream;
void __fastcall Execute();
public:
__fastcall TPipeThread(TPipeStream * stream);
__fastcall ~TPipeThread();
void __fastcall DisconnectAndReconnect(DWORD);
bool __fastcall ConnectToNewClient(HANDLE, LPOVERLAPPED);
bool __fastcall GetAnswerToRequest(LPPIPEINST pipe, int index);
};
DRGRAPH_PROPERTY(TObjectByNameEvent, OnFindObject);
public:
__fastcall TPipeStream(UnicodeString pipeName);
__fastcall ~TPipeStream();
void __fastcall ReportError(UnicodeString desc);
void __fastcall WritePipe(TDllStream& os, int destPipeIndex = -1);
TPipeThread * PipeThread;
DRGRAPH_PROPERTY(UnicodeString, PipeName);
DRGRAPH_PROPERTY(UnicodeString, Prefix);
DRGRAPH_PROPERTY(int, LastPipeIndex);
};
源程序实现:
UnicodeString __fastcall TDllData::GetHint() {
UnicodeString result = FORMAT(L"[%s]类型 > 值 = ", DllType2String(type));
result +=
type == DRGRAPH_DLL_TYPE_BOOL ? TTypeConvert::Bool2String(value.value_bool) :
type == DRGRAPH_DLL_TYPE_CHAR ? FORMAT(L"%d[0X%02X, %c]", value.value_char, value.value_char, value.value_char) :
type == DRGRAPH_DLL_TYPE_UCHAR ? FORMAT(L"%d[0X%02X, %c]", value.value_uchar, value.value_uchar, value.value_uchar) :
type == DRGRAPH_DLL_TYPE_WCHAR ? FORMAT(L"%s", UnicodeString(value.value_wchar)) :
type == DRGRAPH_DLL_TYPE_SHORT ? FORMAT(L"%d", value.value_short) :
type == DRGRAPH_DLL_TYPE_USHORT ? FORMAT(L"%d", value.value_ushort) :
type == DRGRAPH_DLL_TYPE_INT ? FORMAT(L"%d", value.value_int) :
type == DRGRAPH_DLL_TYPE_UINT ? FORMAT(L"%d", value.value_uint) :
type == DRGRAPH_DLL_TYPE_LONG ? FORMAT(L"%ld", value.value_long) :
type == DRGRAPH_DLL_TYPE_ULONG ? FORMAT(L"%lu", value.value_ulong) :
type == DRGRAPH_DLL_TYPE_LONGLONG ? FORMAT(L"%lld", value.value_longlong) :
type == DRGRAPH_DLL_TYPE_ULONGLONG ? FORMAT(L"%llu", value.value_ulonglong) :
type == DRGRAPH_DLL_TYPE_DOUBLE ? FORMAT(L"%s", TTypeConvert::Double2String(value.value_double, 3)) :
type == DRGRAPH_DLL_TYPE_STRING ? FORMAT(L"%s", value_string) :
UnicodeString(L"已结束");
return result;
}
void __fastcall TDllData::CheckType(unsigned char destType) {
if(destType != type)
THelper::Logw(L"类型不正确,转换可能会出现偏差,请检查协议 > 当前类型: %s, 目标类型: %s", DllType2String(type), DllType2String(destType));
}
TDllData::operator bool() {
CheckType(DRGRAPH_DLL_TYPE_BOOL);
return value.value_bool;
}
TDllData::operator char() {
CheckType(DRGRAPH_DLL_TYPE_CHAR);
return value.value_char;
}
TDllData::operator unsigned char() {
CheckType(DRGRAPH_DLL_TYPE_UCHAR);
return value.value_uchar;
}
TDllData::operator wchar_t() {
CheckType(DRGRAPH_DLL_TYPE_WCHAR);
return value.value_wchar;
}
TDllData::operator short() {
CheckType(DRGRAPH_DLL_TYPE_SHORT);
return value.value_short;
}
TDllData::operator unsigned short() {
CheckType(DRGRAPH_DLL_TYPE_USHORT);
return value.value_ushort;
}
TDllData::operator int() {
CheckType(DRGRAPH_DLL_TYPE_INT);
return value.value_int;
}
TDllData::operator unsigned int() {
CheckType(DRGRAPH_DLL_TYPE_UINT);
return value.value_uint;
}
TDllData::operator long() {
CheckType(DRGRAPH_DLL_TYPE_LONG);
return value.value_long;
}
TDllData::operator unsigned long() {
CheckType(DRGRAPH_DLL_TYPE_ULONG);
return value.value_ulong;
}
TDllData::operator long long() {
CheckType(DRGRAPH_DLL_TYPE_LONGLONG);
return value.value_longlong;
}
TDllData::operator unsigned long long() {
CheckType(DRGRAPH_DLL_TYPE_ULONGLONG);
return value.value_ulonglong;
}
TDllData::operator double() {
CheckType(DRGRAPH_DLL_TYPE_DOUBLE);
return value.value_double;
}
TDllData::operator UnicodeString() {
CheckType(DRGRAPH_DLL_TYPE_STRING);
return value_string;
}
__fastcall TDllStream::TDllStream() : CbwStream() {
FMemoryStream = new TMemoryStream;
Stream = FMemoryStream;
FFinished = false;
WCharFlag = false;
}
__fastcall TDllStream::TDllStream(BYTE * datas, int len) : CbwStream() {
FMemoryStream = new TMemoryStream;
FMemoryStream->Write(datas, len);
FMemoryStream->Position = 0;
Stream = FMemoryStream;
FFinished = false;
WCharFlag = false;
}
__fastcall TDllStream::TDllStream(wchar_t * datas, int len) {
FMemoryStream = new TMemoryStream;
FMemoryStream->Write(datas, len);
FMemoryStream->Position = 0;
Stream = FMemoryStream;
FFinished = false;
WCharFlag = true;
}
__fastcall TDllStream::~TDllStream() {
}
void __fastcall TDllStream::Finish() {
if(cbw_debug_flag)
THelper::Logi(L"结束...");
if(FFinished)
return;
unsigned short value = DRGRAPH_DLL_TYPE_NULL;
writeBytes(&value, sizeof(unsigned short));
FFinished = true;
}
TDllData __fastcall TDllStream::Next() {
unsigned char type;
bool readed = readBytes(&type, sizeof(unsigned char));
TDllData result(type);
if(readed)
(*this) >> result;
return result;
}
int __fastcall TDllStream::NextFunType() {
if(Size - Position < (sizeof(int) - 1))
return 0;
GET_DLL_DATA(int, funType, this);
if(READING_DLL_DATA.type == DRGRAPH_DLL_TYPE_NULL)
funType = DRSTREAM_FUNCTION_NONE;
return funType;
}
__fastcall TDllStream::operator BYTE *() {
FMemoryStream->Position = 0;
int len = Stream->Size;
BYTE * result = new BYTE[len];
FMemoryStream->Read(result, len);
FMemoryStream->Position = 0;
return result;
}
__fastcall TDllStream::operator wchar_t *() {
FMemoryStream->Position = 0;
int len = Stream->Size;
BYTE * result = new BYTE[len];
FMemoryStream->Read(result, len);
FMemoryStream->Position = 0;
WCharSize = MultiByteToWideChar(CP_ACP, 0, result, -1, NULL, 0);
wchar_t * ws = new wchar_t[WCharSize];
MultiByteToWideChar(CP_ACP, 0, result, -1, ws, WCharSize);
delete[] result;
return ws;
}
void __fastcall TDllStream::Reset() {
CBW_DELETE(FMemoryStream);
FMemoryStream = new TMemoryStream;
Stream = FMemoryStream;
}
UnicodeString __fastcall TDllStream::GetHint(UnicodeString desc) {
UnicodeString result = FORMAT(L"%s中内容:", desc.Length() > 0 ? desc.w_str() : L"DllStream流");
do {
if(EOF_Flag)
break;
TDllData data = Next();
if(data.IsEof())
break;
result += FORMAT(L"\n\t%s", data.GetHint());
} while(true);
return result;
}
__fastcall TDllData::TDllData(unsigned char t) {
type = t;
}
__fastcall TDllData::TDllData(const TDllData& copy) {
type = copy.type;
value = copy.value;
value_string = copy.value_string;
}
TDllData * __fastcall TDllData::operator = (const TDllData & equal) {
type = equal.type;
value = equal.value;
value_string = equal.value_string;
return this;
}
__fastcall TDllData::~TDllData() {
}
__fastcall TPipeStream::TPipeStream(UnicodeString pipeName) {
FPipeName = pipeName;
FPrefix = FORMAT(L"管道服务 %s", PipeName);
OnFindObject = NULL;
PipeThread = new TPipeThread(this);
THelper::Logi(L"创建 %s", FPrefix);
}
__fastcall TPipeStream::~TPipeStream() {
}
void __fastcall TPipeStream::ReportError(UnicodeString desc) {
UnicodeString info = FORMAT(L"【%s.错误】 > %s", FPrefix, desc);
THelper::Loge(THelper::Util::GetSystemErrorInfo(false, info));
}
__fastcall TPipeStream::TPipeThread::TPipeThread(TPipeStream * stream) : TThread(true) {
FreeOnTerminate = true;
FOwnerStream = stream;
for (int i = 0; i < PIPE_INSTANCES; i++)
hEvents[i] = NULL;
Suspended = false;
}
__fastcall TPipeStream::TPipeThread::~TPipeThread() {
if(FOwnerStream->PipeThread == this)
FOwnerStream->PipeThread = NULL;
}
void __fastcall TPipeStream::TPipeThread::DisconnectAndReconnect(DWORD i)
{
if (!DisconnectNamedPipe(Pipe[i].hPipeInst))
FOwnerStream->ReportError("DisconnectNamedPipe 失败");
Pipe[i].fPendingIO = ConnectToNewClient(
Pipe[i].hPipeInst,
&Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
PIPE_CONNECTING_STATE : // still connecting
PIPE_READING_STATE; // ready to read
}
// ConnectToNewClient(HANDLE, LPOVERLAPPED)
// This function is called to start an overlapped connect operation.
// It returns TRUE if an operation is pending or FALSE if the
// connection has been completed.
bool __fastcall TPipeStream::TPipeThread::ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
bool fConnected, fPendingIO = false;
fConnected = ConnectNamedPipe(hPipe, lpo);
if (fConnected)
{
FOwnerStream->ReportError(L"调用ConnectToNewClient时,ConnectNamedPipe 失败 > fConnected == false");
return 0;
}
switch (GetLastError()) {
case ERROR_IO_PENDING: // The overlapped connection in progress.
fPendingIO = TRUE;
break;
case ERROR_PIPE_CONNECTED:// Client is already connected, so signal an event.
if (SetEvent(lpo->hEvent))
break;
default: // If an error occurs during the connect operation...
FOwnerStream->ReportError("调用ConnectToNewClient时,ConnectNamedPipe 失败 > GetLastError == default");
return 0;
}
return fPendingIO;
}
void __fastcall TPipeStream::TPipeThread::Execute() {
DWORD i, dwWait, cbRet, dwErr;
BOOL fSuccess;
THelper::Windows::DebugCurrentThread(ndttAdd, FORMAT(L"【%s】", FOwnerStream->Prefix));
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\drgraph");
// 创建多个命名管道
for (i = 0; i < PIPE_INSTANCES; i++) {
hEvents[i] = CreateEvent(
NULL, // default security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if (hEvents[i] == NULL) {
FOwnerStream->ReportError("CreateEvent failed");
return;
}
Pipe[i].oOverlap.hEvent = hEvents[i];
Pipe[i].hPipeInst = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_INSTANCES, // number of instances
PIPE_BUFSIZE*sizeof(TCHAR), // output buffer size
PIPE_BUFSIZE*sizeof(TCHAR), // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // default security attributes
if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE) {
FOwnerStream->ReportError("CreateNamedPipe failed");
Pipe[i].hPipeInst = NULL;
return;
}
Pipe[i].fPendingIO = ConnectToNewClient(Pipe[i].hPipeInst, &Pipe[i].oOverlap);
Pipe[i].dwState = Pipe[i].fPendingIO ?
PIPE_CONNECTING_STATE : // still connecting
PIPE_READING_STATE; // ready to read
}
// 监听各管道
while (!Terminated) {
dwWait = WaitForMultipleObjects(
PIPE_INSTANCES, // number of event objects
hEvents, // array of event objects
FALSE, // does not wait for all
50);
if( WAIT_TIMEOUT == dwWait)
continue;
i = dwWait - WAIT_OBJECT_0; // determines which pipe
if (i < 0 || i > (PIPE_INSTANCES - 1)) {
FOwnerStream->ReportError(FORMAT("WaitForMultipleObjects 监听结果下标[%d]越界: 有效范围区间 (0 ~ %d)", i, PIPE_INSTANCES - 1));
break;
}
if (Pipe[i].fPendingIO) { // Get the result if the operation was pending.
fSuccess = GetOverlappedResult(
Pipe[i].hPipeInst, // handle to pipe
&Pipe[i].oOverlap, // OVERLAPPED structure
&cbRet, // bytes transferred
FALSE); // do not wait
switch (Pipe[i].dwState) { // Pending connect operation
case PIPE_CONNECTING_STATE:
if (! fSuccess) {
FOwnerStream->ReportError(FORMAT("调用GetOverlappedResult后,Pipe[%d].dwState 值为 PIPE_CONNECTING_STATE > 不再监听,退出监听线程", i));
return;
}
Pipe[i].dwState = PIPE_READING_STATE;
break;
case PIPE_READING_STATE: // Pending read operation
if (! fSuccess || cbRet == 0) {
DisconnectAndReconnect(i);
continue;
}
Pipe[i].cbRead = cbRet;
Pipe[i].dwState = PIPE_WRITING_STATE;
break;
case PIPE_WRITING_STATE: // Pending write operation
if (! fSuccess || cbRet != Pipe[i].cbWrite) {
DisconnectAndReconnect(i);
continue;
}
Pipe[i].dwState = PIPE_READING_STATE;
break;
default:
FOwnerStream->ReportError(FORMAT("调用GetOverlappedResult后,Pipe[%d].dwState 值为未处理值[%d] > 不再监听,退出监听线程", Pipe[i].dwState));
return;
}
}
switch (Pipe[i].dwState) { // The pipe state determines which operation to do next.
case PIPE_READING_STATE: // The pipe instance is connected to the client
fSuccess = ReadFile( // and is ready to read a request from the client.
Pipe[i].hPipeInst,
Pipe[i].wRequestBuffer,
PIPE_BUFSIZE*sizeof(TCHAR),
&Pipe[i].cbRead,
&Pipe[i].oOverlap);
if (fSuccess && Pipe[i].cbRead != 0) { // The read operation completed successfully.
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = PIPE_WRITING_STATE;
continue;
}
// The read operation is still pending.
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING)) {
Pipe[i].fPendingIO = TRUE;
continue;
}
DisconnectAndReconnect(i); // An error occurred; disconnect from the client.
break;
case PIPE_WRITING_STATE: // The request was successfully read from the client.
GetAnswerToRequest(&Pipe[i], i); // Get the reply data and write it to the client.
fSuccess = true;
fSuccess = WriteFile( // true: 有返回数据内容
Pipe[i].hPipeInst,
Pipe[i].wResponseBuffer,
Pipe[i].cbWrite,
&cbRet,
&Pipe[i].oOverlap);
if (fSuccess && cbRet == Pipe[i].cbWrite) { // The write operation completed successfully.
Pipe[i].fPendingIO = FALSE;
Pipe[i].dwState = PIPE_READING_STATE;
continue;
}
// The write operation is still pending.
dwErr = GetLastError();
if (! fSuccess && (dwErr == ERROR_IO_PENDING)) {
Pipe[i].fPendingIO = TRUE;
continue;
}
DisconnectAndReconnect(i); // An error occurred; disconnect from the client.
break;
default:
FOwnerStream->ReportError("Invalid pipe state.");
return;
}
}
THelper::Windows::DebugCurrentThread(ndttRemove);
}
bool __fastcall TPipeStream::TPipeThread::GetAnswerToRequest(LPPIPEINST pipe, int index)
{
FOwnerStream->LastPipeIndex = index;
TDllStream is(pipe->wRequestBuffer, pipe->cbRead);
THelper::Logi(L"接收到pipe[%d]信息 > %s", index, is.GetHint());
THelper::Debug::DoLogOutput();
TDllStream os;
OnRequest_Stream(&is, &os, FOwnerStream->OnFindObject);
if(os.Size == 0)
os << DRSTREAM_FUNCTION_NONE;// << "ERROR" << "No Response";
if(os.Size > 0) {
os << ioFinish;
os.Rewind();
BYTE * data = (BYTE *)os;
pipe->cbWrite = os.Size;
memcpy(pipe->wResponseBuffer, data, os.Size);
THelper::Logi(L"发送 %d 字节 > %s", pipe->cbWrite, os.GetHint());
delete data;
return true; // 有返回内容
}
return false;
}
void __fastcall TPipeStream::WritePipe(TDllStream& os, int destPipeIndex) {
if(destPipeIndex == -1) {
destPipeIndex = LastPipeIndex;
if(destPipeIndex == -1)
destPipeIndex = 0;
}
if(os.Size == 0)
os << DRSTREAM_FUNCTION_NONE;
if(os.Size > 0) {
os << ioFinish;
os.Rewind();
BYTE * data = (BYTE *)os;
UnicodeString hint = THelper::Debug::GetHint(data, os.Size);
THelper::Logi(L"[Pipe.发送] > %s", hint);
LPPIPEINST pipe = &(PipeThread->Pipe[destPipeIndex]);
pipe->cbWrite = os.Size;
memcpy(pipe->wResponseBuffer, data, os.Size);
DWORD i, dwWait, cbRet, dwErr;
bool fSuccess = WriteFile( // true: 有返回数据内容
pipe->hPipeInst,
data,
os.Size,
&cbRet,
NULL);
if (fSuccess && cbRet == os.Size) { // The write operation completed successfully.
THelper::Logi(L"成功发送 %d 字节 > %s", os.Size, os.GetHint());
return;
}
THelper::Loge(L"失败发送 %d 字节 > %s", os.Size, os.GetHint());
delete data;
}
}
在调用时,简单声明即可访问其属性与方法。
void __fastcall TMainForm::Button_DebugTestClick(TObject *Sender)
{
if(PipeStreamServer == NULL) {
CBW_DELETE(PipeStreamServer);
PipeStreamServer = new TPipeStream(L"drgraph");
PipeStreamServer->OnFindObject = FindObjectByName;//FCurrentForm->FindMetaByName;
} else {
TDllStream dsStatus;
dsStatus << DRSTREAM_FUNCTION_STATUS << L"OK" << L"drgraph.姓名 = ArWen";
PipeStreamServer->WritePipe(dsStatus);
}
}
Godot端处理
直接在源码中增加CbwPipe.cpp与CbwPipe.h,基于使用方法习惯,相应编写实现
#pragma once
#include "core/os/os.h"
#include <stdarg.h>
#include <stdlib.h>
std::string String2std(String str);
wchar_t *char32ToWchar(const char32_t *char32Str);
typedef unsigned char BYTE;
#define __property(type, var, read, write) __declspec(property(read, write)) type var
#define DRSTREAM_FUNCTION_NONE 0
#define DRSTREAM_FUNCTION_SET 1
#define DRSTREAM_FUNCTION_GET 2
#define DRSTREAM_FUNCTION_STATUS 3
enum SEEK_ORIGIN {
SO_BEGINNING = 0,
SO_CURRENT = 1,
SO_END = 2
};
enum NStreamIOControl {
ioReset,
ioRewind,
ioFinish
};
extern bool cbw_debug_flag;
#define DRGRAPH_DLL_TYPE_NULL 0
#define DRGRAPH_DLL_TYPE_BOOL 1
#define DRGRAPH_DLL_TYPE_CHAR 2
#define DRGRAPH_DLL_TYPE_UCHAR 3
#define DRGRAPH_DLL_TYPE_WCHAR 4
#define DRGRAPH_DLL_TYPE_SHORT 5
#define DRGRAPH_DLL_TYPE_USHORT 6
#define DRGRAPH_DLL_TYPE_INT 7
#define DRGRAPH_DLL_TYPE_UINT 8
#define DRGRAPH_DLL_TYPE_LONG 9
#define DRGRAPH_DLL_TYPE_ULONG 10
#define DRGRAPH_DLL_TYPE_DOUBLE 11
#define DRGRAPH_DLL_TYPE_STRING 12
#define DRGRAPH_DLL_TYPE_LONGLONG 13
#define DRGRAPH_DLL_TYPE_ULONGLONG 14
#define DLL_WRITE(t) \
unsigned char dlltype = t; \
cofs.WriteBuffer(&dlltype, sizeof(unsigned char)); \
cofs.Finished = false;
std::string DllType2String(unsigned char type);
std::string Double2String(double value, int maxBits = 8, int fixedFlag = false, int width = 0);
std::string WChar2String(wchar_t *pwszSrc);
std::string WChar2String(const wchar_t *pwszSrc);
class TDllData {
void CheckType(unsigned char destType);
public:
TDllData(unsigned char t = DRGRAPH_DLL_TYPE_NULL);
TDllData(const TDllData ©);
~TDllData();
bool IsEof() { return type == DRGRAPH_DLL_TYPE_NULL; };
std::string GetHint();
unsigned char type;
union {
bool value_bool;
char value_char;
unsigned char value_uchar;
wchar_t value_wchar;
short value_short;
unsigned short value_ushort;
int value_int;
unsigned int value_uint;
long value_long;
unsigned long value_ulong;
double value_double;
long long value_longlong;
unsigned long long value_ulonglong;
} value;
std::string value_string;
TDllData *operator=(const TDllData &equal);
operator bool();
operator char();
operator unsigned char();
operator wchar_t();
operator short();
operator unsigned short();
operator int();
operator unsigned int();
operator long();
operator unsigned long();
operator double();
operator long long();
operator unsigned long long();
operator std::string();
};
class TDllStream {
public:
enum { DEFAULT_MEMORY_DELTA = 1024 }; // 默认内存步长
enum { MIN_MEMORY_DELTA = 256 }; // 最小内存步长
private:
char *m_pMemory; // 缓冲区指针
int m_nSize; // 当前流的大小
int m_nPosition; // 当前位置
int m_nCapacity; // 缓冲区大小.真正大大小.包含给未来分配的长度
int m_nMemoryDelta; // 增长的步长
bool Finished;
public:
void SetPointer(void *pMemory, int nSize);
void SetMemoryDelta(int nNewMemoryDelta);
void SetCapacity(int nNewCapacity);
char *Realloc(int &nNewCapacity);
int GetSize() const;
void SetSize(int nSize);
int GetPosition() const;
void SetPosition(int nPos);
int Read(void *pBuffer, int nCount);
int Write(const void *pBuffer, int nCount);
int Seek(int nOffset, SEEK_ORIGIN nSeekOrigin);
public:
explicit TDllStream(int nMemoryDelta = DEFAULT_MEMORY_DELTA) :
m_nCapacity(0), m_pMemory(NULL), m_nSize(0), m_nPosition(0) {
SetMemoryDelta(nMemoryDelta);
Finished = false;
}
TDllStream(BYTE *datas, int len);
~TDllStream();
public:
char *GetMemory() { return m_pMemory; }
void *GetCurrentPtr() { return m_pMemory + m_nPosition; }
bool ReadBuffer(void *pBuffer, int nCount);
bool WriteBuffer(void *pBuffer, int nCount);
void Clear();
bool IsEOF();
void Rewind();
void Finish();
TDllData Next();
void Reset();
int NextFunType();
operator BYTE *();
__property(int, Size, get = GetSize, put = SetSize);
__property(int, Position, get = GetPosition, put = SetPosition);
public:
friend TDllStream &operator<<(TDllStream &cofs, NStreamIOControl ctrl) {
if (ctrl == ioReset)
cofs.Reset();
if (ctrl == ioRewind)
cofs.Rewind();
if (ctrl == ioFinish)
cofs.Finish();
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, bool value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_BOOL);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %s\n", DllType2String(dlltype).c_str(), value ? "true" : "false");
unsigned char b = value ? 1 : 0;
cofs.WriteBuffer(&b, sizeof(unsigned char));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, char value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_CHAR);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %d[0X%02X, %c]\n", DllType2String(dlltype).c_str(), int(value), value, value);
cofs.WriteBuffer(&value, sizeof(char));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, unsigned char value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_UCHAR);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %d[0X%02X, %c]\n", DllType2String(dlltype).c_str(), int(value), value, value);
cofs.WriteBuffer(&value, sizeof(unsigned char));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, wchar_t value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_WCHAR);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %lc\n", DllType2String(dlltype).c_str(), value);
cofs.WriteBuffer(&value, sizeof(wchar_t));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, short value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_SHORT);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %d\n", DllType2String(dlltype).c_str(), int(value));
cofs.WriteBuffer(&value, sizeof(short));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, unsigned short value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_USHORT);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %d\n", DllType2String(dlltype).c_str(), int(value));
cofs.WriteBuffer(&value, sizeof(unsigned short));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, int value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_INT);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %d\n", DllType2String(dlltype).c_str(), int(value));
cofs.WriteBuffer(&value, sizeof(int));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, unsigned int value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_UINT);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %d\n", DllType2String(dlltype).c_str(), int(value));
cofs.WriteBuffer(&value, sizeof(unsigned int));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_LONG);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %ld\n", DllType2String(dlltype).c_str(), value);
cofs.WriteBuffer(&value, sizeof(long));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, unsigned long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_ULONG);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %lu\n", DllType2String(dlltype).c_str(), value);
cofs.WriteBuffer(&value, sizeof(unsigned long));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, long long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_LONGLONG);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %lld\n", DllType2String(dlltype).c_str(), value);
cofs.WriteBuffer(&value, sizeof(long long));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, unsigned long long value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_ULONGLONG);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %llu\n", DllType2String(dlltype).c_str(), value);
cofs.WriteBuffer(&value, sizeof(unsigned long long));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, float value) {
//DLL_WRITE(DRGRAPH_DLL_TYPE_DOUBLE);
double d = value;
cofs << d;
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, double value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_DOUBLE);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %s\n", DllType2String(dlltype).c_str(), Double2String(value, 3).c_str());
cofs.WriteBuffer(&value, sizeof(double));
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, char *str) {
std::string string = str;
cofs << string;
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, const char *str) {
std::string string = str;
cofs << string;
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, const char32_t *str) {
std::string result = String2std(str);
cofs << result;
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, wchar_t *str) {
std::string string = WChar2String(str);
cofs << string;
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, const wchar_t *str) {
std::string string = WChar2String(str);
cofs << string;
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, std::string value);
friend TDllStream &operator<<(TDllStream &cofs, String str) {
std::string string = String2std(str);
cofs << string;
return cofs;
}
friend TDllStream &operator<<(TDllStream &cofs, TDllData &data) {
if (data.type == DRGRAPH_DLL_TYPE_STRING)
cofs << data.value_string;
else if (data.type == DRGRAPH_DLL_TYPE_INT)
cofs << data.value.value_int;
else if (data.type == DRGRAPH_DLL_TYPE_DOUBLE)
cofs << data.value.value_double;
else if (data.type == DRGRAPH_DLL_TYPE_BOOL)
cofs << data.value.value_bool;
else if (data.type == DRGRAPH_DLL_TYPE_UCHAR)
cofs << data.value.value_uchar;
else if (data.type == DRGRAPH_DLL_TYPE_CHAR)
cofs << data.value.value_char;
else if (data.type == DRGRAPH_DLL_TYPE_WCHAR)
cofs << data.value.value_wchar;
else if (data.type == DRGRAPH_DLL_TYPE_SHORT)
cofs << data.value.value_short;
else if (data.type == DRGRAPH_DLL_TYPE_LONG)
cofs << data.value.value_long;
else if (data.type == DRGRAPH_DLL_TYPE_USHORT)
cofs << data.value.value_ushort;
else if (data.type == DRGRAPH_DLL_TYPE_UINT)
cofs << data.value.value_uint;
else if (data.type == DRGRAPH_DLL_TYPE_ULONG)
cofs << data.value.value_ulong;
else if (data.type == DRGRAPH_DLL_TYPE_LONGLONG)
cofs << data.value.value_longlong;
else if (data.type == DRGRAPH_DLL_TYPE_ULONGLONG)
cofs << data.value.value_ulonglong;
else if (data.type == DRGRAPH_DLL_TYPE_NULL)
cofs.Finish();
return cofs;
}
friend TDllStream &operator>>(TDllStream &cifs, bool &q) {
unsigned char b;
cifs >> b;
q = b;
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, char &q) {
cifs.ReadBuffer(&q, sizeof(char));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, signed char &q) {
cifs.ReadBuffer(&q, sizeof(signed char));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, unsigned char &q) {
cifs.ReadBuffer(&q, sizeof(unsigned char));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, signed short &q) {
cifs.ReadBuffer(&q, sizeof(signed short));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, unsigned short &q) {
cifs.ReadBuffer(&q, sizeof(unsigned short));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, signed int &q) {
cifs.ReadBuffer(&q, sizeof(signed int));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, unsigned int &q) {
cifs.ReadBuffer(&q, sizeof(unsigned int));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, signed long &q) {
cifs.ReadBuffer(&q, sizeof(signed long));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, unsigned long &q) {
cifs.ReadBuffer(&q, sizeof(unsigned long));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, float &q) {
cifs.ReadBuffer(&q, sizeof(float));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, double &q) {
cifs.ReadBuffer(&q, sizeof(double));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, long double &q) {
cifs.ReadBuffer(&q, sizeof(long double));
return cifs;
}
friend TDllStream &operator>>(TDllStream &cifs, std::string &q);
friend TDllStream &operator>>(TDllStream &cifs, TDllData &data) {
if (data.type == DRGRAPH_DLL_TYPE_STRING)
cifs >> data.value_string;
else if (data.type == DRGRAPH_DLL_TYPE_INT)
cifs.ReadBuffer(&data.value, sizeof(int));
else if (data.type == DRGRAPH_DLL_TYPE_DOUBLE)
cifs.ReadBuffer(&data.value, sizeof(double));
else if (data.type == DRGRAPH_DLL_TYPE_BOOL)
cifs.ReadBuffer(&data.value, sizeof(unsigned char));
else if (data.type == DRGRAPH_DLL_TYPE_UCHAR)
cifs.ReadBuffer(&data.value, sizeof(unsigned char));
else if (data.type == DRGRAPH_DLL_TYPE_CHAR)
cifs.ReadBuffer(&data.value, sizeof(char));
else if (data.type == DRGRAPH_DLL_TYPE_WCHAR)
cifs.ReadBuffer(&data.value, sizeof(wchar_t));
else if (data.type == DRGRAPH_DLL_TYPE_SHORT)
cifs.ReadBuffer(&data.value, sizeof(short));
else if (data.type == DRGRAPH_DLL_TYPE_LONG)
cifs.ReadBuffer(&data.value, sizeof(long));
else if (data.type == DRGRAPH_DLL_TYPE_USHORT)
cifs.ReadBuffer(&data.value, sizeof(unsigned short));
else if (data.type == DRGRAPH_DLL_TYPE_UINT)
cifs.ReadBuffer(&data.value, sizeof(unsigned int));
else if (data.type == DRGRAPH_DLL_TYPE_ULONG)
cifs.ReadBuffer(&data.value, sizeof(unsigned long));
else if (data.type == DRGRAPH_DLL_TYPE_LONGLONG)
cifs.ReadBuffer(&data.value, sizeof(long long));
else if (data.type == DRGRAPH_DLL_TYPE_ULONG)
cifs.ReadBuffer(&data.value, sizeof(unsigned long long));
else if (data.type == DRGRAPH_DLL_TYPE_NULL)
return cifs;
return cifs;
}
};
extern TDllData READING_DLL_DATA;
#define DRGRAPH_SOURCE_POS str_format("%s[%d] - %S()", \
std::string(__FILE__), __LINE__, __func__)
#define GET_DLL_DATA(T, varName, is) \
READING_DLL_DATA = (is)->Next(); \
T varName; \
if (READING_DLL_DATA.type != DRGRAPH_DLL_TYPE_NULL) { \
if (READING_DLL_DATA.IsEof()) { \
std::string msg = str_format("越界读取〖%S %S; > @%s〗,请检查协议...", typeid(T).name(), #varName, DRGRAPH_SOURCE_POS); \
throw(msg); \
} \
varName = READING_DLL_DATA; \
}
class TCbwPipe {
void *g_hNamedPipe; // 管道句柄
bool CreateNamePipeC(const char *iPipeName); // 创建命名管道客户端
std::string FPipeServerName;
static TCbwPipe *singleton;
public:
void ReadPipeData(BYTE *iBuffer, int &iBufferSize, int timeout = 1000); // 读取数据
bool WriteDllStream(TDllStream &os, int timeout = 1000);
public:
TCbwPipe();
~TCbwPipe();
bool ConnectToServer(std::string pipeServerName);
static TCbwPipe *get_singleton();
static void Free();
};
std::string String2std(String str);
#include "CbwPipe.h"
#include <stdarg.h>
#include <thread>
#include <locale.h>
#include <windows.h>
#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
#include <codecvt>
std::string String2std(String str) {
//std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
//std::string result = converter.to_bytes(str.ptr());
wchar_t *wchar = char32ToWchar(str.ptr());
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
std::string result = converter.to_bytes(wchar);
delete[] wchar;
return result;
}
wchar_t *char32ToWchar(const char32_t *char32Str) {
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
// 将 char32_t* 转换为 UTF-8 编码的 std::string
std::string utf8Str = converter.to_bytes(char32Str);
// 计算宽字符字符串所需的长度
size_t wideLen = mbstowcs(nullptr, utf8Str.c_str(), 0) + 1;
// 分配内存并转换为宽字符字符串
wchar_t *wcharStr = new wchar_t[wideLen];
mbstowcs(wcharStr, utf8Str.c_str(), wideLen);
return wcharStr;
}
TDllStream& operator<<(TDllStream& cofs, std::string value) {
DLL_WRITE(DRGRAPH_DLL_TYPE_STRING);
if (cbw_debug_flag)
OS::get_singleton()->print("[DllStream] > 写入[%s]类型 > %s\n", DllType2String(dlltype).c_str(), value.c_str());
int wideCharLen = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), value.length() + 1, nullptr, 0);
wchar_t *wideCharStr = new wchar_t[wideCharLen];
int multiByteLen = WideCharToMultiByte(CP_UTF8, 0, wideCharStr, wideCharLen, nullptr, 0, nullptr, nullptr);
char *multiByteStr = new char[multiByteLen];
WideCharToMultiByte(CP_UTF8, 0, wideCharStr, wideCharLen, multiByteStr, multiByteLen, nullptr, nullptr);
cofs.WriteBuffer(&multiByteLen, sizeof(int));
cofs.WriteBuffer((void *)multiByteStr, multiByteLen);
delete[] wideCharStr;
delete[] multiByteStr;
return cofs;
}
bool cbw_debug_flag = true;
TDllStream &operator>>(TDllStream &cifs, std::string &q) {
int length;
cifs >> length;
char *chBuffer = new char[length + 1];
cifs.ReadBuffer(chBuffer, length);
int wLength = length + 1;
wchar_t *wcBuffer = new wchar_t[wLength];
MultiByteToWideChar(CP_UTF8, 0, chBuffer, wLength, wcBuffer, wLength);
q = WChar2String(wcBuffer);
delete wcBuffer;
delete chBuffer;
return cifs;
}
template <typename... Args>
static std::string str_format(const std::string &format, Args... args) {
auto size_buf = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
std::unique_ptr<char[]> buf(new (std::nothrow) char[size_buf]);
if (!buf)
return std::string("");
std::snprintf(buf.get(), size_buf, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size_buf - 1);
}
std::string Double2String(double value, int maxBits, int fixedFlag, int width) {
std::string result = str_format("%f", value);
size_t pointPos = result.find(".");
if (pointPos > 0) {
size_t floatNumber = result.length() - pointPos;
if (floatNumber > maxBits)
result.erase(pointPos + maxBits + 1, result.length());
if (pointPos == 0)
result = str_format("0%s", result);
}
for (size_t i = result.length() - 1; i >= 0; --i) {
if (result.c_str()[i] == '0')
result.erase(i + 1, 1);
else
break;
}
if (result.length() > 0 && result.c_str()[result.length() - 1] == L'.')
result.erase(result.length(), 1);
if (fixedFlag) {
size_t pointPos = result.find(".");
if (pointPos == result.npos) {
result += ".";
pointPos = result.length();
}
int floatNumber = result.length() - pointPos;
while (floatNumber++ < maxBits)
result += "0";
}
int blankNumber = width - result.length();
if (blankNumber > 0) {
std::string pre;
pre.resize(blankNumber, ' ');
result = pre + result;
}
return result;
}
std::string WChar2String(wchar_t *pwszSrc) {
int nLen = WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, NULL, 0, NULL, NULL);
if (nLen <= 0)
return std::string("");
char *pszDst = new char[nLen];
if (NULL == pszDst)
return std::string("");
WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, pszDst, nLen, NULL, NULL);
pszDst[nLen - 1] = 0;
std::string strTemp(pszDst);
delete[] pszDst;
return strTemp;
}
std::string WChar2String(const wchar_t *pwszSrc) {
return WChar2String(const_cast<wchar_t *>(pwszSrc));
}
std::string DllType2String(unsigned char type) {
std::string result = type == DRGRAPH_DLL_TYPE_NULL ? "结束"
: type == DRGRAPH_DLL_TYPE_BOOL ? "bool"
: type == DRGRAPH_DLL_TYPE_CHAR ? "char"
: type == DRGRAPH_DLL_TYPE_UCHAR ? "BYTE"
: type == DRGRAPH_DLL_TYPE_WCHAR ? "wchar_t"
: type == DRGRAPH_DLL_TYPE_SHORT ? "short"
: type == DRGRAPH_DLL_TYPE_USHORT ? "unsigned short"
: type == DRGRAPH_DLL_TYPE_INT ? "int"
: type == DRGRAPH_DLL_TYPE_UINT ? "unsigned int"
: type == DRGRAPH_DLL_TYPE_LONG ? "long"
: type == DRGRAPH_DLL_TYPE_ULONG ? "unsigned long"
: type == DRGRAPH_DLL_TYPE_DOUBLE ? "double"
: type == DRGRAPH_DLL_TYPE_STRING ? "string"
: type == DRGRAPH_DLL_TYPE_LONGLONG ? "long long"
: type == DRGRAPH_DLL_TYPE_ULONGLONG ? "unsigned long long"
: "未知类型";
return result;
}
std::string VarType2String(Variant::Type t) {
switch (t) {
case Variant::NIL:
return "NIL";
case Variant::BOOL:
return "BOOL";
case Variant::INT:
return "INT";
case Variant::FLOAT:
return "FLOAT";
case Variant::STRING:
return "STRING";
case Variant::VECTOR2:
return "VECTOR2";
case Variant::VECTOR2I:
return "VECTOR2I";
case Variant::RECT2:
return "RECT2";
case Variant::RECT2I:
return "RECT2I";
case Variant::VECTOR3:
return "VECTOR3";
case Variant::VECTOR3I:
return "VECTOR3I";
case Variant::TRANSFORM2D:
return "TRANSFORM2D";
case Variant::VECTOR4:
return "VECTOR4";
case Variant::VECTOR4I:
return "VECTOR4I";
case Variant::PLANE:
return "PLANE";
case Variant::QUATERNION:
return "QUATERNION";
case Variant::AABB:
return "AABB";
case Variant::BASIS:
return "BASIS";
case Variant::TRANSFORM3D:
return "TRANSFORM3D";
case Variant::PROJECTION:
return "PROJECTION";
case Variant::COLOR:
return "COLOR";
case Variant::STRING_NAME:
return "STRING_NAME";
case Variant::NODE_PATH:
return "NODE_PATH";
case Variant::RID:
return "RID";
case Variant::OBJECT:
return "OBJECT";
case Variant::CALLABLE:
return "CALLABLE";
case Variant::SIGNAL:
return "SIGNAL";
case Variant::DICTIONARY:
return "DICTIONARY";
case Variant::ARRAY:
return "ARRAY";
case Variant::PACKED_BYTE_ARRAY:
return "PACKED_BYTE_ARRAY";
case Variant::PACKED_INT32_ARRAY:
return "PACKED_INT32_ARRAY";
case Variant::PACKED_INT64_ARRAY:
return "PACKED_INT64_ARRAY";
case Variant::PACKED_FLOAT32_ARRAY:
return "PACKED_FLOAT32_ARRAY";
case Variant::PACKED_FLOAT64_ARRAY:
return "PACKED_FLOAT64_ARRAY";
case Variant::PACKED_STRING_ARRAY:
return "PACKED_STRING_ARRAY";
case Variant::PACKED_VECTOR2_ARRAY:
return "PACKED_VECTOR2_ARRAY";
case Variant::PACKED_VECTOR3_ARRAY:
return "PACKED_VECTOR3_ARRAY";
case Variant::PACKED_COLOR_ARRAY:
return "PACKED_COLOR_ARRAY";
case Variant::VARIANT_MAX:
return "VARIANT_MAX";
default:
return "UNKNOWN";
}
}
TDllData READING_DLL_DATA;
TDllData::TDllData(unsigned char t) {
type = t;
}
TDllData::TDllData(const TDllData ©) {
type = copy.type;
value = copy.value;
value_string = copy.value_string;
}
TDllData::~TDllData() {
}
std::string TDllData::GetHint() {
std::string result = str_format("[%s]类型 > 值 = ", DllType2String(type));
result += type == DRGRAPH_DLL_TYPE_BOOL ? (value.value_bool ? "true" : "false")
: type == DRGRAPH_DLL_TYPE_CHAR ? str_format("%d[0X%02X, %c]", value.value_char, value.value_char, value.value_char)
: type == DRGRAPH_DLL_TYPE_UCHAR ? str_format("%d[0X%02X, %c]", value.value_uchar, value.value_uchar, value.value_uchar)
: type == DRGRAPH_DLL_TYPE_WCHAR ? str_format("%lc", value.value_wchar)
: type == DRGRAPH_DLL_TYPE_SHORT ? str_format("%d", value.value_short)
: type == DRGRAPH_DLL_TYPE_USHORT ? str_format("%d", value.value_ushort)
: type == DRGRAPH_DLL_TYPE_INT ? str_format("%d", value.value_int)
: type == DRGRAPH_DLL_TYPE_UINT ? str_format("%d", value.value_uint)
: type == DRGRAPH_DLL_TYPE_LONG ? str_format("%ld", value.value_long)
: type == DRGRAPH_DLL_TYPE_ULONG ? str_format("%lu", value.value_ulong)
: type == DRGRAPH_DLL_TYPE_LONGLONG ? str_format("%lld", value.value_longlong)
: type == DRGRAPH_DLL_TYPE_ULONGLONG ? str_format("%llu", value.value_ulonglong)
: type == DRGRAPH_DLL_TYPE_DOUBLE ? str_format("%s", Double2String(value.value_double, 3))
: type == DRGRAPH_DLL_TYPE_STRING ? str_format("%s", value_string)
: str_format("已结束");
return result;
}
void TDllData::CheckType(unsigned char destType) {
if (destType != type)
OS::get_singleton()->print("类型不正确,转换可能会出现偏差,请检查协议 > 当前类型: %s, 目标类型: %s",
DllType2String(type).c_str(), DllType2String(destType).c_str());
}
TDllData *TDllData::operator=(const TDllData &equal) {
type = equal.type;
value = equal.value;
value_string = equal.value_string;
return this;
}
TDllData::operator bool() {
CheckType(DRGRAPH_DLL_TYPE_BOOL);
return value.value_bool;
}
TDllData::operator char() {
CheckType(DRGRAPH_DLL_TYPE_CHAR);
return value.value_char;
}
TDllData::operator unsigned char() {
CheckType(DRGRAPH_DLL_TYPE_UCHAR);
return value.value_uchar;
}
TDllData::operator wchar_t() {
CheckType(DRGRAPH_DLL_TYPE_WCHAR);
return value.value_wchar;
}
TDllData::operator short() {
CheckType(DRGRAPH_DLL_TYPE_SHORT);
return value.value_short;
}
TDllData::operator unsigned short() {
CheckType(DRGRAPH_DLL_TYPE_USHORT);
return value.value_ushort;
}
TDllData::operator int() {
CheckType(DRGRAPH_DLL_TYPE_INT);
return value.value_int;
}
TDllData::operator unsigned int() {
CheckType(DRGRAPH_DLL_TYPE_UINT);
return value.value_uint;
}
TDllData::operator long() {
CheckType(DRGRAPH_DLL_TYPE_LONG);
return value.value_long;
}
TDllData::operator unsigned long() {
CheckType(DRGRAPH_DLL_TYPE_ULONG);
return value.value_ulong;
}
TDllData::operator long long() {
CheckType(DRGRAPH_DLL_TYPE_LONGLONG);
return value.value_longlong;
}
TDllData::operator unsigned long long() {
CheckType(DRGRAPH_DLL_TYPE_ULONGLONG);
return value.value_ulonglong;
}
TDllData::operator double() {
CheckType(DRGRAPH_DLL_TYPE_DOUBLE);
return value.value_double;
}
TDllData::operator std::string() {
CheckType(DRGRAPH_DLL_TYPE_STRING);
return value_string;
}
void TDllStream::SetPointer(void *pMemory, int nSize) {
m_pMemory = (char *)pMemory;
m_nSize = nSize;
}
void TDllStream::SetMemoryDelta(int nNewMemoryDelta) {
if (nNewMemoryDelta != DEFAULT_MEMORY_DELTA) {
if (nNewMemoryDelta < MIN_MEMORY_DELTA)
nNewMemoryDelta = MIN_MEMORY_DELTA;
// 2^N
for (int i = sizeof(int) * 8 - 1; i >= 0; i--)
if (((1 << i) & nNewMemoryDelta) != 0) {
nNewMemoryDelta &= (1 << i);
break;
}
}
m_nMemoryDelta = nNewMemoryDelta;
}
void TDllStream::SetCapacity(int nNewCapacity) {
SetPointer(Realloc(nNewCapacity), m_nSize);
m_nCapacity = nNewCapacity;
}
char *TDllStream::Realloc(int &nNewCapacity) {
char *pResult;
if (nNewCapacity > 0 && nNewCapacity != m_nSize)
nNewCapacity = (nNewCapacity + (m_nMemoryDelta - 1)) & ~(m_nMemoryDelta - 1);
pResult = m_pMemory;
if (nNewCapacity != m_nCapacity) {
if (nNewCapacity == 0) {
free(m_pMemory);
pResult = NULL;
} else {
if (m_nCapacity == 0)
pResult = (char *)malloc(nNewCapacity);
else
pResult = (char *)realloc(m_pMemory, nNewCapacity);
}
}
return pResult;
}
int TDllStream::GetSize() const {
int nPos, nResult;
nPos = const_cast<TDllStream &>(*this).Seek(0, SO_CURRENT);
nResult = const_cast<TDllStream &>(*this).Seek(0, SO_END);
const_cast<TDllStream &>(*this).Seek(nPos, SO_BEGINNING);
return nResult;
}
void TDllStream::SetSize(int nSize) {
int nOldPos = m_nPosition;
SetCapacity((int)nSize);
m_nSize = (int)nSize;
if (nOldPos > nSize)
Seek(0, SO_END);
}
int TDllStream::GetPosition() const {
return const_cast<TDllStream &>(*this).Seek(0, SO_CURRENT);
}
void TDllStream::SetPosition(int nPos) {
Seek(nPos, SO_BEGINNING);
}
int TDllStream::Read(void *pBuffer, int nCount) {
int nResult = 0;
if (m_nPosition >= 0 && nCount >= 0) {
nResult = m_nSize - m_nPosition;
if (nResult > 0) {
if (nResult > nCount)
nResult = nCount;
memmove(pBuffer, m_pMemory + (DWORD)m_nPosition, nResult);
m_nPosition += nResult;
}
}
return nResult;
}
int TDllStream::Write(const void *pBuffer, int nCount) {
int nResult = 0;
int nPos;
if (m_nPosition >= 0 && nCount >= 0) {
nPos = m_nPosition + nCount;
if (nPos > 0) {
if (nPos > m_nSize) {
if (nPos > m_nCapacity)
SetCapacity(nPos);
m_nSize = nPos;
}
memmove(m_pMemory + (DWORD)m_nPosition, pBuffer, nCount);
m_nPosition = nPos;
nResult = nCount;
}
}
return nResult;
}
TDllStream::TDllStream(BYTE *datas, int len) :
m_nCapacity(0), m_pMemory(NULL), m_nSize(0), m_nPosition(0) {
SetMemoryDelta(DEFAULT_MEMORY_DELTA);
Clear();
WriteBuffer(datas, len);
Finished = false;
Rewind();
}
TDllStream::~TDllStream() {
Clear();
}
int TDllStream::Seek(int nOffset, SEEK_ORIGIN nSeekOrigin) {
switch (nSeekOrigin) {
case SO_BEGINNING:
m_nPosition = (int)nOffset;
break;
case SO_CURRENT:
m_nPosition += (int)nOffset;
break;
case SO_END:
m_nPosition = m_nSize + (int)nOffset;
break;
}
return m_nPosition;
}
bool TDllStream::ReadBuffer(void *pBuffer, int nCount) {
if (nCount != 0 && Read(pBuffer, nCount) != nCount)
return false;
else
return true;
}
bool TDllStream::WriteBuffer(void *pBuffer, int nCount) {
if (nCount != 0 && Write(pBuffer, nCount) != nCount)
return false;
else
return true;
}
void TDllStream::Clear() {
SetCapacity(0);
m_nSize = 0;
m_nPosition = 0;
}
bool TDllStream::IsEOF() {
return Position >= Size;
}
void TDllStream::Rewind() {
Position = 0;
}
void TDllStream::Finish() {
unsigned short value = DRGRAPH_DLL_TYPE_NULL;
WriteBuffer(&value, sizeof(unsigned short));
Finished = true;
}
TDllData TDllStream::Next() {
unsigned char type;
bool readed = ReadBuffer(&type, sizeof(unsigned char));
TDllData result(type);
if (readed)
(*this) >> result;
return result;
}
void TDllStream::Reset() {
Clear();
}
int TDllStream::NextFunType() {
if (Size - Position <= 2)
return 0;
GET_DLL_DATA(int, funType, this);
if (READING_DLL_DATA.type == DRGRAPH_DLL_TYPE_NULL)
funType = DRSTREAM_FUNCTION_NONE;
return funType;
}
TDllStream::operator BYTE *() {
Position = 0;
int len = Size;
BYTE *result = new BYTE[len];
ReadBuffer(result, len);
Position = 0;
return result;
}
TCbwPipe *TCbwPipe::singleton = nullptr;
TCbwPipe *TCbwPipe::get_singleton() {
if (!TCbwPipe::singleton) {
TCbwPipe::singleton = new TCbwPipe();
}
return TCbwPipe::singleton;
}
void TCbwPipe::Free() {
if (TCbwPipe::singleton)
delete TCbwPipe::singleton;
TCbwPipe::singleton = NULL;
}
TCbwPipe::TCbwPipe() {
setlocale(LC_ALL, "");
g_hNamedPipe = INVALID_HANDLE_VALUE;
}
TCbwPipe::~TCbwPipe() {
if (g_hNamedPipe != INVALID_HANDLE_VALUE && g_hNamedPipe != NULL)
CloseHandle(g_hNamedPipe);
}
bool TCbwPipe::CreateNamePipeC(const char *iPipeName) {
char t_PipeName[200];
//1,创建一个命名管道
sprintf_s(t_PipeName, "\\\\.\\pipe\\%s", iPipeName);
if (WaitNamedPipeA(t_PipeName, NMPWAIT_WAIT_FOREVER) == 0) {
OS::get_singleton()->print("当前没有可以利用的管道:%d\n", GetLastError());
return false;
}
g_hNamedPipe = CreateFileA(t_PipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (g_hNamedPipe == INVALID_HANDLE_VALUE) {
OS::get_singleton()->print("打开命名管道失败!:%d\n", GetLastError());
g_hNamedPipe = NULL;
return false;
}
OS::get_singleton()->print("链接管道%s已成功\n", t_PipeName);
return true;
}
#include <iomanip>
#include <iostream>
#include <sstream>
// 读取数据
void TCbwPipe::ReadPipeData(BYTE *iBuffer, int &iBufferSize, int timeout) {
DWORD availableBytes;
if (g_hNamedPipe == INVALID_HANDLE_VALUE) {
OS::get_singleton()->is_pipe_allowed = false;
return;
}
if (!PeekNamedPipe(g_hNamedPipe, NULL, 0, NULL, &availableBytes, NULL)) {
OS::get_singleton()->print("[Pipe.Read] > 读取数据失败:%d\n", GetLastError());
if (g_hNamedPipe != INVALID_HANDLE_VALUE && g_hNamedPipe != NULL)
CloseHandle(g_hNamedPipe);
g_hNamedPipe = INVALID_HANDLE_VALUE;
OS::get_singleton()->is_pipe_allowed = false;
return;
}
if (availableBytes < 1) {
iBufferSize = 0;
return;
}
//读取数据
DWORD dwRead;
HANDLE t_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
OVERLAPPED ovlap;
ZeroMemory(&ovlap, sizeof(OVERLAPPED));
ovlap.hEvent = t_hEvent;
if (ReadFile(g_hNamedPipe, iBuffer, iBufferSize, &dwRead, &ovlap) == false) {
OS::get_singleton()->print("[Pipe.Read] > 读取数据失败:%d\n", GetLastError());
if (t_hEvent)
CloseHandle(t_hEvent);
t_hEvent = NULL;
iBufferSize = 0;
return;
}
iBufferSize = 0;
if (t_hEvent) {
bool failed = (WaitForSingleObject(t_hEvent, timeout) == WAIT_FAILED);
CloseHandle(t_hEvent);
t_hEvent = NULL;
if (failed) {
OS::get_singleton()->print("[Pipe.Read] > 等待对象失败:%d\n", GetLastError());
return;
}
}
if (dwRead > 0) {
iBufferSize = dwRead;
std::ostringstream oss{};
//oss << "[Pipe.Read] > 接收到数据: ";
for (DWORD i = 0; i < dwRead; ++i)
oss << std::hex << iBuffer[i] << ", ";
oss << std::endl;
std::string str = oss.str();
OS::get_singleton()->print("[Pipe.Read] > 接收到数据: %s\n", str.c_str());
TDllStream cifs(iBuffer, dwRead);
do {
int funType = cifs.NextFunType();
if (funType == DRSTREAM_FUNCTION_NONE)
break;
if (funType == DRSTREAM_FUNCTION_STATUS) {
READING_DLL_DATA = cifs.Next();
std::string status = READING_DLL_DATA;
READING_DLL_DATA = cifs.Next();
std::string value = READING_DLL_DATA;
OS::get_singleton()->print("[Pipe.Read] > funType = %d > status = %s, value = %s\n", funType, status.c_str(), value.c_str());
}
} while (true);
//ConnectToServer(FPipeServerName);
}
}
bool TCbwPipe::WriteDllStream(TDllStream &os, int timeout) {
DWORD dwWrite;
int len = os.Size + 1;
BYTE *data = os;
if (!WriteFile(g_hNamedPipe, data, len, &dwWrite, NULL)) {
OS::get_singleton()->print("[Pipe.Error] > 写入数据失败:%d\n", GetLastError());
delete data;
return false;
}
delete data;
return true;
}
bool TCbwPipe::ConnectToServer(std::string pipeServerName) {
FPipeServerName = pipeServerName;
if (g_hNamedPipe != INVALID_HANDLE_VALUE && g_hNamedPipe != NULL)
CloseHandle(g_hNamedPipe);
g_hNamedPipe = INVALID_HANDLE_VALUE;
const char *t_PipeName = pipeServerName.c_str();
return CreateNamePipeC(t_PipeName);
}
实现过程没费劲,就是编译费劲。一直提示相应功能没有实现。原来godot是用scons什么工具编译的,需要配置路径什么的。为省事,避免琢磨scons,我把CbwPipe两个文件放在已有目录下就OK了。
GDScript支持
在源码中增加了功能,肯定是希望在godot项目中使用,比如用GDScript编写脚本时可用
在CharGPT指导下,完成这个功能还算顺利。核心是与ClassDB打交道
class DllStream : public Object {
GDCLASS(DllStream, Object);
TDllStream stream;
public:
DllStream();
DllStream *rewind();
DllStream * write(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
void send_pipe();
};
DllStream::DllStream() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "write", &DllStream::write, MethodInfo("write"));
ClassDB::bind_method(D_METHOD("rewind"), &DllStream::rewind);
ClassDB::bind_method(D_METHOD("send_pipe"), &DllStream::send_pipe);
}
DllStream * DllStream::write(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
for (int i = 0; i < p_argcount; ++i) {
print_line("DllStream::write(", i + 1, "/", p_argcount, ": type = ", p_args[i]->get_type_name(p_args[i]->get_type()), ", value = ", *p_args[i]);
switch (p_args[i]->get_type()) {
case Variant::BOOL:
stream << bool(p_args[i]);
break;
case Variant::INT:
stream << int(*p_args[i]);
break;
case Variant::FLOAT:
stream << float(*p_args[i]);
break;
case Variant::STRING:
stream << String(*p_args[i]).ptr(); // todo: char32_t的处理
break;
}
}
return this;
}
DllStream* DllStream::rewind() {
stream.Rewind();
return this;
}
void DllStream::send_pipe() {
TCbwPipe::get_singleton()->WriteDllStream(stream);
}
在godot启动过程中,直接自动发一些管道信息:
std::string pipeName = String2std(p);
OS::get_singleton()->is_pipe_allowed = TCbwPipe::get_singleton()->ConnectToServer(pipeName);
TDllStream dsSet, dsGet;
dsSet << DRSTREAM_FUNCTION_SET
<< "MainForm"
<< "Caption"
<< "godot 标题 Command by DrGraph"
<< ioFinish;
dsGet << DRSTREAM_FUNCTION_GET
<< "CurrentForm"
<< "Caption" << ioFinish;
TCbwPipe::get_singleton()->WriteDllStream(dsSet);
TCbwPipe::get_singleton()->WriteDllStream(dsGet);
在DrGraph软件中接收到管道数据:
GDScript注册
为了在GDScript中使用,还需要注册类名
GDREGISTER_CLASS(DllStream);
在Script编辑器中,就可以出现代码提示了
相应功能调用
Godot工程运行后,在界面中操作以触发相应代码功能
使用触发后,在Godot软件中可看到输出
DrGraph软件中同步收到管道信息
达到效果。还有一点小问题,中文乱码,应该是编解码问题,有空再处理一下。