MSTSCLib_TLB \ OleCtrls 修正

 

delphi7 导入RDP AcitveX 生成的MSTSCLib_TLB.pas 

delphi真的好惨啊,资料都是其他语言的。用到都得自己转换,自身导入生成的还有问题。或者用法根本就不一样。

第一处:

生成的是这样的:
IMsRdpClientNonScriptable = interface(IMsTscNonScriptable)
['{2F079C4C-87B2-4AFD-97AB-20CDB43038AE}']
function NotifyRedirectDeviceChange(wParam: UINT_PTR; lParam: LONG_PTR): HResult; stdcall;
function SendKeys(numKeys: Integer; var pbArrayKeyUp: WordBool; var plKeyData: Integer): HResult; stdcall;
end;

通过导入生成的方法,是一次只能输入一个。不能多个一起输入。

根据微软的文档:
https://learn.microsoft.com/vi-vn/windows/win32/termserv/imsrdpclientnonscriptable-sendkeys

这两个参数是数组才对,查阅资料后要改成下面这样

IMsRdpClientNonScriptable = interface(IMsTscNonScriptable)
['{2F079C4C-87B2-4AFD-97AB-20CDB43038AE}']
function NotifyRedirectDeviceChange(wParam: UINT_PTR; lParam: LONG_PTR): HResult; stdcall;
function SendKeys(numKeys: Integer; pbArrayKeyUp: Pointer; plKeyData: Pointer): HResult; stdcall;


调用时也要注意:
var
 keydatas: array[0..19] of integer; //一次最多发20个
 keyupstate: array[0..19] of SmallInt; //c++中 VARIANT_BOOL 是COM 使用的布尔类型, 其实质上是 short 类型 不能使用boolen。c++的short对应的delphi的是SmallInt
begin
  keydatas[0] := MapVirtualKey(65,0);
  keydatas[1] := MapVirtualKey(65,0);
  keydatas[2] := MapVirtualKey(66,0);
  keydatas[3] := MapVirtualKey(66,0);
  keydatas[4] := MapVirtualKey(67,0);
  keydatas[5] := MapVirtualKey(67,0);

  keyupstate[0] := 0;
  keyupstate[1] := 1;
  keyupstate[2] := 0;
  keyupstate[3] := 1;
  keyupstate[4] := 0;
  keyupstate[5] := 1;
  //注意状态要正确,不然会输入的结果。这里输入的是abc
  nonScriptable.SendKeys(6, @keyupda[0],@keydatas[0]);
 end
  

 第二处:

  TMsRdpClient9NotSafeForScriptingOnRemoteWindowDisplayed = procedure(ASender: TObject; vbDisplayed: WordBool; 
                                                                                      var   hwnd: {??_RemotableHandle}OleVariant;
                                                                                        windowAttribute: RemoteWindowDisplayedAttribute) of object;

这里只改9的,其他的版本也是一样的修改
改成不要var 用polevariant
  TMsRdpClient9NotSafeForScriptingOnRemoteWindowDisplayed = procedure(ASender: TObject; vbDisplayed: WordBool; 
                                                                                         hwnd: {??_RemotableHandle}POleVariant;
                                                                                        windowAttribute: RemoteWindowDisplayedAttribute) of object;

因为控件是生成了,这里改完可以重新打开控件包,重新编译一下。
或者直接通过动态赋值事件的方式去绑定事件也可以
rdp.OnRemoteWindowDisplayed := rdpRemoteWindowDisplayed;


procedure TForm1.rdpRemoteWindowDisplayed(ASender: TObject;
  vbDisplayed: WordBool;  hwnd: POleVariant; windowAttribute: TOleEnum);
var
  ph: PHandle;
begin
 if vbDisplayed then
 begin
  if hwnd <> nil then
  begin
   ph := @hwnd; //这里就是remoteapp 的句柄了
   mmo1.Lines.Add(inttostr(ph^));
  end;
end;

 接一下来是OleCtrls.pas 修正(不知对不对,先记录。目前测试效果是对的,还不懂汇编,是问AI修复的)

procedure TOleControl.InvokeEvent(DispID: TDispID; var Params: TDispParams);
var
  EventMethod: TMethod;
  Arg: TVariantArg;
  i: Integer;
  intval:integer;
begin
  if ControlData.Version < 300 then
    D2InvokeEvent(DispID, Params)
  else
  begin
    GetEventMethod(DispID, EventMethod);
    if Integer(EventMethod.Code) < $10000 then Exit;
    try
      asm
                PUSH    EBX
                PUSH    ESI
                MOV     ESI, Params
                MOV     EBX, [ESI].TDispParams.cArgs
                TEST    EBX, EBX
                JZ      @@7
                MOV     ESI, [ESI].TDispParams.rgvarg
                MOV     EAX, EBX
                SHL     EAX, 4                         // count * sizeof(TVarArg)
                XOR     EDX, EDX
                ADD     ESI, EAX                       // EDI = Params.rgvarg^[ArgCount]
        @@1:    SUB     ESI, 16                        // Sizeof(TVarArg)
                MOV     EAX, dword ptr [ESI]
                CMP     AX, varInteger             // 添加对varInteger的判断   //20231029 fix 
                JE      @@5                        // 与varSingle处理方式相同   //20231029 fix 
                CMP     AX, varSingle                  // 4 bytes to push
                JA      @@3
                JE      @@5                            
        @@2:    TEST    DL,DL
                JNE     @@2a
                MOV     ECX, ESI
                INC     DL
                TEST    EAX, varArray
                JNZ     @@6
                MOV     ECX, dword ptr [ESI+8]
                JMP     @@6

        @@2a:   TEST    EAX, varArray
                JZ      @@5
                PUSH    ESI
                JMP     @@6
        @@3:    CMP     AX, varDate                    // 8 bytes to push
                JA      @@2
        @@4:    PUSH    dword ptr [ESI+12]
        @@5:    PUSH    dword ptr [ESI+8]
        @@6:    DEC     EBX
                JNE     @@1
        @@7:    MOV     EDX, Self
                MOV     EAX, EventMethod.Data
                CALL    EventMethod.Code
                POP     ESI
                POP     EBX
      end;
    except
      Application.HandleException(Self);
    end;
  end;
end;
如果参数有类型是varInteger,原本的汇编没有对integer 判断。
对varInteger的情况,会出现问题:
1. varInteger是4字节整数类型
2. 但是代码里只有判断varSingle的情况会压入4字节
3. 所以对varInteger,会错误地当作8字节浮点数处理这确实是一个值得注意的问题。要修复这个问题,需要在代码的@@1标签处添加对varInteger的判断:
asm
@@1:     SUB     ESI, 16                        
                MOV     EAX, dword ptr [ESI]
                CMP     AX, varInteger             // 添加对varInteger的判断
                JE      @@5                        // 与varSingle处理方式相同
                CMP     AX, varSingle
                JA      @@3
                JE      @@5
添加一个判断varInteger的语句,如果是varInteger,也直接跳转到@@5标签进行4字节参数的PUSH操作。

 

posted @ 2023-04-08 15:36  Tag  阅读(216)  评论(0)    收藏  举报