Godot 4 源码分析 - 增加管道通信

news2024/12/26 11:44:32

学习研究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 &copy);
	~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 &copy) {
	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软件中同步收到管道信息

 达到效果。还有一点小问题,中文乱码,应该是编解码问题,有空再处理一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/779175.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

POSIX线程编程

死在山野的风里&#xff0c;活在自由的梦里 本专栏参考教材是四川轻化工大学陈年老师的linux实验指导手册&#xff08;含学习通的一些程序笔记&#xff09;。 POSIX线程编程 1.线程是什么2.创建线程创建一个用户级的线程&#xff0c;实现在线程中更改进程&#xff08;主线程&a…

Bean小结

Bean是Spring框架中最核心的两个概念之一&#xff08;另一个是面向切面编程AOP&#xff09;。 Bean 定义 Spring 官方文档对 bean 的解释是&#xff1a; In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC contain…

从Vue2到Vue3【三】——Composition API(第三章)

系列文章目录 内容链接从Vue2到Vue3【零】Vue3简介从Vue2到Vue3【一】Composition API&#xff08;第一章&#xff09;从Vue2到Vue3【二】Composition API&#xff08;第二章&#xff09;从Vue2到Vue3【三】Composition API&#xff08;第三章&#xff09;从Vue2到Vue3【四】C…

webrtc QOS方法二.4(flexfec 实现可优化点)

一、冗余报文和媒体报文组织结构优化点 以单帧10个媒体报文&#xff0c;冗余度20%为例。这里webrtc输出要有10个媒体包2个冗余包。webrtc输出的报文序列如下&#xff1a; 代码实现如下&#xff1a; UlpfecGenerator::AddPacketAndGenerateFec&#xff1a;攒够足够的帧 Forwar…

使用springboot进行后端开发100问

properties和yaml文件怎么互转 安装插件 properties文件和yaml文件区别 properties 文件通过“.”和“”赋值&#xff0c;值前不加空格&#xff0c;yaml通过“:”赋值&#xff0c;值前面加一个空格&#xff1b;yaml文件缩进用空格&#xff1b; properties只支持键值对&#x…

C++实现LRU(逐句讲解)

使用双向链表解决此问题&#xff0c;因为双向链表可以很容易的获取到头结点和尾结点。题目要求 get 和 put 要在O(1)的时间复杂度下运行&#xff0c;很显然要用set或map。根据题意&#xff0c;应使用map。 unordered_map<int,Node*> cache; map->first为Node中的key&a…

查看RabbitMQ日志---trace插件的使用

我的RabbitMQ是安装在docker里面的 所以我以下的方法都是根据这个路径去操作的 如果RabbitMQ安装在其他地方 请自行百度 1. 显示正在运行的RabbitMQ容器的名称或ID&#xff1a; docker ps这将启动所有正在运行的 Docker 容器&#xff0c;并包含 RabbitMQ 容器的信息。 使用…

【Docker】Docker的数据管理

目录 一、Docker 的数据管理1.1数据卷1.2 数据卷容器1.3端口映射1.4容器互联&#xff08;使用centos镜像&#xff09; 二、Docker镜像的创建2.1基于现有镜像创建2.2&#xff0e;基于本地模板创建2.3 基于Dockerfile 创建联合文件系统&#xff08;UnionFS&#xff09;镜像加载原…

【云原生】Docker网络及Cgroup资源控制

一、Docker网络 1.docker网络实现原理 Docker使用Linux桥接&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&#xff0c;Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址&#xff0c;称为Container-IP&#xff0c;同时Docker网桥是每个容器的默认网关。…

【Linux网络】 网络套接字(二)socket编程_UDP网络程序

目录 socket 编程接口socket 常见的APIsockaddr结构 UDP网络程序简单例子服务端代码编写服务端创建套接字服务端绑定运行服务器测试启动服务端 客户端代码编写客户端创建套接字启动客户端本地测试INADDR_ANY服务端接收信息发回到客户端如何进行网络测试 socket 编程接口 socke…

【机器学习】吃瓜教程 | 西瓜书 + 南瓜书 (1)

文章目录 一、绪论1、什么是机器学习&#xff1f;2、基本术语3、假设空间4、归纳偏好5、发展历程 二、模型评估与选择A、一种训练集一种算法2.1 经验误差 与 过拟合2.2 评估方法a) 留出法b) 交叉验证法c) 自助法d) 调参与最终模型 2.3 性能度量a) 错误率与精度b) 查准率、查全率…

RT-Thread快速入门-内核移植

1RT-Thread快速入门-内核移植 RT-Thread 快速入门系列前面的文章介绍了内核相关的知识&#xff0c;以及内核提供的接口函数和如何使用。 本篇文章主要介绍如何将 RT-Thread 内核移植到某个硬件平台之上。移植分为两部分&#xff1a; CPU 架构移植 BSP 移植 也就是将 RT-Th…

MySQL第二课表的增删插改

&#x1f49b; 后端进行的表的操作增删查改 现在是建了一个成绩表&#xff0c;注意哈。 decimal(2,1). 2是M表示有两个有效数字长度&#xff0c;1是D的长度&#xff0c;即小数点后有一位(10分制) &#x1f493;开始 1.增加&#xff1a; insert into 表名 values(值&#xff0…

安装VS Code 和 MiKTeX开发环境

下载&#xff1a; Getting MiKTeX 然后以管理员方式运行安装。 配置VS Code 之后配置VS Code&#xff0c;选择扩展&#xff08;两个位置都可以&#xff09;&#xff0c;然后搜索Latex&#xff1a; 然后打开设置&#xff1a; 这样就打开了setting.json文件&#xff0c; 然后…

SQL注入之Oracle环境搭建

SQL注入之Oracle环境搭建 前言 Oracle Database&#xff0c;又名Oracle RDBMS&#xff0c;或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是世界上流行的关系数据库管理系统&#xff0c;系统可移植性…

gitlab上传新项目全过程

gitlab上传新项目全过程 一、前期准备1.1 gitlab配置1.2 gitlab安装1.3 需要在gitlab上新建一个空项目 二、本地操作2.1 gitlab上传新项目全过程2.2 gitlab将远程项目拉取到本地全过程 三、常见问题及解决四、常用命令4.1 代码更新提交命令4.2 其他指令 一、前期准备 1.1 gitl…

less中引入自定义字体文件

前言 一般做后台管理系统UI没有影响要求可以不使用自定义字体。但是在大屏项目中&#xff0c;高度自定义化&#xff0c;就肯定需要UI导出字体文件&#xff0c;然后放到服务器上或者是我们项目文件中&#xff0c;我们前端引入后在页面中使用。 下面以放在项目文件中为例。 各…

【linux】五种IO模型与非阻塞IO

文章目录 一、IO的概念二、IO的五种模型2.1 概念2.2 对比五种IO 三、非阻塞IO3.1 fcntl文件描述符控制3.2 以非阻塞轮询方式读取标准输入 一、IO的概念 前面我们说过其实IO就是拷贝数据。 先说一下读取的接口&#xff1a; 当系统调用read/recv的时候会有两种情况 ①没有数据&a…

【C语言】指针进阶(3)

目录 指针和数组笔试题解析 一维数组 字符数组 二维数组 指针笔试题 在前面两篇文章&#xff0c;我们已经学完了指针进阶的所有知识点。在这篇文章中&#xff0c;我们主要学习的是一些常见的笔试题的总结。 指针和数组笔试题解析 在做题之前&#xff0c;我们先复习一下之…

第三讲:k8s核心概念和专业术语

序言&#xff1a;这里只对概念继续基础阐述&#xff0c;不做具体案例&#xff0c;这位博主写的特别详细&#xff0c;想要对k8s深入的了解可以跳转了&#xff0c;作为小白的我看的有点懵&#xff0c;毕竟没实践过 链接地址→ http://t.csdn.cn/ZYtEF 这篇文章写了将近两万字对各…