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)); // 直接获取字节长度
   指针地址: PAnsiChar(data)[0] 



posted @ 2025-07-06 09:14  Tag  阅读(9)  评论(0)    收藏  举报