Godot 4 source code analysis - increase pipeline communication

Learning and researching Godot 4 is very cool. Although it is very complicated, it is very powerful compared to my own level, especially the vulkan can be directly packaged and available, so that I don't have to think about it from scratch.

Digest, optimize and perfect bit by bit, and finally become your own.

During this period of time, on the basis of Godot, pipeline communication was added to realize the communication between Godot and the existing programs of the machine for subsequent seamless integration.

In fact, Godot supports various network communications, such as UDP and TCP. Why do we have to implement pipeline communication? In essence, we still want to see the effect of the transformation. The ultimate goal is to realize the pipeline communication between Godot software and its own DrGraph software

DrGraph side processing

In order to realize the pipe communication, the corresponding modularization is implemented according to the Windows named pipe communication principle.

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

Source program implementation:


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

When calling, simply declare to access its properties and methods.

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 side processing

Add CbwPipe.cpp and CbwPipe.h directly to the source code, and write and implement accordingly based on usage habits

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

The implementation process is not strenuous, but the compilation is strenuous. It keeps saying that the corresponding function is not implemented. It turns out that godot is compiled with scons tools, and it needs to configure the path or something. To save trouble and avoid thinking about scons, I put the two files of CbwPipe in the existing directory and it is OK.

GDScript support

Added functions in the source code, it is definitely hoped to be used in the godot project, for example, it is available when writing scripts with GDScript

Under the guidance of CharGPT, this function was completed smoothly. The core is dealing with 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);
}

During the godot startup process, some pipeline information is automatically sent directly:

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

Pipeline data received in DrGraph software:

 GDScript registration

In order to be used in GDScript, the class name also needs to be registered

GDREGISTER_CLASS(DllStream);

In the Script editor, code hints can appear

Corresponding function call

 After the Godot project is running, operate in the interface to trigger the corresponding code function

 After using the trigger, the output can be seen in the Godot software

 Synchronously receive pipeline information in DrGraph software

 Achieve the desired effect. There is still a small problem, the Chinese is garbled, it should be a codec problem, I will deal with it when I have time.

Guess you like

Origin blog.csdn.net/drgraph/article/details/131823327