RDP AcitveX COM 组件一些事件取值说明。
1.rdpRemoteWindowDisplayed(ASender: TObject; vbDisplayed: WordBool; hwnd: POleVariant; windowAttribute: TOleEnum);
这种POleVariant ,看原来接口声明是什么类型。比如这个是句柄类型的。这里就是指针的地址。取值如下:
var PHwd: PHandle;
if @hwnd <> nil then
PHwd := @hwnd;
取值: PHwd^
通道的发送跟接收
客户端发,先看过程声明
procedure TMsRdpClient9NotSafeForScripting.SendOnVirtualChannel(const chanName: WideString;
const ChanData: WideString);
begin
DefaultInterface.SendOnVirtualChannel(chanName, ChanData);
end;
这里参数是widestring 所以发送最后都是widestring,接收也一样。当然也可以发送ansistring 就是把ansistring塞到widestring里不要直接赋值,不然编译器会自动转换。记得最后得补0不然内容不对。如果对发送的数据不想太大可以用这种方式,发送的数据小则无所谓
用ansistring发送方式
var ansiStr: AnsiString; wsData: WideString; dataLength, charCount: Integer; pLastChar: PWideChar; begin //这样需要补 // 1. 获取 ANSI 字符串 ansiStr := AnsiString(mmo2.Text); dataLength := Length(ansiStr); charCount := (dataLength + 1) div 2; // 2. 创建目标 WideString SetLength(wsData, charCount); // 3. 直接复制内存 if dataLength > 0 then Move(ansiStr[1], wsData[1], dataLength); //最后一位没有要填充成0 if dataLength mod 2 <> 0 then begin // 获取 WideString 的起始指针 pLastChar := PWideChar(wsData); // 移动到最后一个字符位置 Inc(pLastChar, charCount - 1); // 确保高字节为零(小端序:低字节在前) // 因为奇数长度时,最后一个字符的低字节是数据,高字节应该是零 pLastChar^ := WideChar(Byte(pLastChar^) and $00FF); end; // 4. 发送数据 rdp.SendOnVirtualChannel('Mytest1', wsData);
按控件封装好的,直接widestring
var s: WideString; begin s := mmo2.text; rdp.SendOnVirtualChannel('Mytest1', s);
服务端接收:这里只是随便写,接收时是有缓冲区大小的。一次发送不多的话,可以无视,多的话需要循环去read
function WTSVirtualChannelRead(
{IN}hChannelHandle: THANDLE;
{IN}TimeOut: ULONG;
{_Out_writes_bytes_to_(BufferSize, *pBytesRead)}Buffer: PAnsiChar;
{IN}BufferSize: ULONG;
{_Out_}pBytesRead: PULONG
): BOOL; stdcall; external libwtsapi32;
var szBuffer: array[0..1023] of AnsiChar; ulBytesRead: ULONG; dwError: DWORD; AnsiStr:AnsiString; begin FillChar(szBuffer, sizeof(szBuffer), 0); if (not WTSVirtualChannelRead(m_hChannelHandle, 1000 * 5, //INFINITE, @szBuffer[0], sizeof(szBuffer), @ulBytesRead)) then begin ShowMessage(Format('WTSVirtualChannelRead Error!Code:%d;%s', [dwError, SysErrorMessage(dwError)])); end else begin showmessage(inttostr(ulBytesRead)); SetString(AnsiStr, PAnsiChar(@szBuffer[0]), ulBytesRead); ShowMessage('ANSI 字符串: ' + string(AnsiStr)); Memo1.Lines.Add(StrPas(szBuffer)); end;
服务端发:这里的参数是PAnsiChar ,发送注意就得用ansistring了其实也可以进行编码,把ansistring编码成utf8接收时就要解码
function WTSVirtualChannelWrite(
{IN}hChannelHandle: THANDLE;
{_In_reads_bytes_(Length)}Buffer: PAnsiChar;
{IN}Length: ULONG;
{_Out_}pBytesWritten: PULONG
): BOOL; stdcall; external libwtsapi32;
if WTSVirtualChannelWrite(m_hChannelHandle, pansichar(mmo1.Text), Length(mmo1.Text), @ulBytesWritten) then begin // ShowMessage('WTSVirtualChannelWrite OK!'); end else begin ShowMessage(Format('WTSVirtualChannelWrite Error!Code:%d;%s', [dwError, SysErrorMessage(dwError)])); end;
编码发送:
var szBuffer: array[0..1023] of AnsiChar; ulBytesWritten: ULONG; dwError: DWORD; utf8Buf: UTF8String; begin utf8Buf := UTF8Encode(mmo1.Text);// 转为UTF-8字节流 if not WTSVirtualChannelWrite(m_hChannelHandle, PAnsiChar(utf8Buf), Length(utf8Buf), @ulBytesWritten) then
客户端接收:
procedure TForm1.rdpChannelReceivedData(ASender: TObject; const chanName, data: WideString); var p: PAnsiChar; putf8:PUTF8String; begin p := Pointer(data); mmo1.Lines.Add(Format('[%s]: %s',[chanName, p])); //如果发送是以utf8发送则解码 mmo1.lines.add('utf8'); mmo1.lines.add(UTF8Decode(p)); end;
20250730增加以内存缓冲区来接收的方式,比如发送方是发送了一块内存过来。比如Buffer: array[0..10] of AnsiChar; 这里可以随便自定义协议.
客户端接收时就得
var pData: Pointer; dataLengthBytes: Integer; pBuffer: array of AnsiChar; begin // 获取数据指针(指向二进制内存块的起始位置) pData := Pointer(data); // 计算实际内存块长度(字节数) dataLengthBytes := SysStringByteLen(Pointer(data)); // 直接获取字节长度 if dataLengthBytes > 0 then begin setlength(pBuffer, dataLengthBytes); Move(pData^, pBuffer[0], dataLengthBytes); end; end;
20250731 不需要move到pData 里直接PAnsiChar(data) 就可以。读取的话。PAnsiChar(data)[0] 地址从下标0开始。获取长度还是用SysStringByteLen,
dataLengthBytes := SysStringByteLen(Pointer(data)); // 直接获取字节长度

浙公网安备 33010602011771号