小编him*_*elf的帖子

如何在DCOM中进行模拟?

我有一个使用OLE自动化编组器的DCOM客户端和服务器应用程序.它们在同一台PC上运行时工作正常,但当服务器位于不在同一域的不同PC上时,我得到E_ACCESSDENIED(0x80070005).

服务器PC配置了dcomcnfg,以便为我在客户端上指定的登录名和密码的用户提供对任何DCOM对象的所有访问权限.ServerApp及其类型库已在服务器pc上注册.

类型库也在客户端PC上注册.我直接在ClientApp中指定服务器名称,因此据我所知,客户端PC上不需要dcomcnfg配置.

具有服务器名称,登录名,域名和密码的CreateInstanceEx()工作正常.它返回IUnknown,同时在服务器PC上启动ServerApp.

但是当我尝试使用QueryInterface()获取服务器支持的接口时,我得到了E_ACCESSDENIED.

分析安全事件日志,我有两条记录:

首先,我在ClientApp中指定其凭据的用户成功进行网络登录.当我调用CreateInstanceEx()时会发生这种情况.

接下来,我在客户端PC上登录的用户登录尝试失败.由于两台PC不在域中,因此服务器PC不知道该用户.

现在,为什么这个用户会登录到服务器,特别是当我调用所有东西的QueryInterface时?

研究CreateInterfaceEx参数,似乎有某种模仿机制正在进行中.但目前还不清楚是谁冒充了谁.涉及三个用户凭据:

  1. ServerApp在服务器PC上运行的用户(在dcomcnfg中配置).

  2. 连接时ClientApp指定凭据的用户.

  3. ClientApp在客户端PC上运行其凭据的用户.

无论你如何看待它,如果涉及#3,那么它就是一个用户.如果DCOM要在服务器PC上识别/模仿#3,为什么我需要指定#2的凭证?到了什么地步?

DCOM冒充#2似乎是合乎逻辑的,因为这是我明确指定为我的凭据.但为什么第二次登录尝试呢?

有人可以解释模仿是如何工作的,还有一种方法可以忽略它并以dcomcnfg中指定的用户身份运行?

windows com remoting dcom

14
推荐指数
1
解决办法
5545
查看次数

德尔福堆栈错位+ com编组=错误的编组

这不是一个直截了当的问题,因为我刚刚解决了它,但更像是"我是否正确"这类问题,并提醒那些可能会陷入困境的人.

事实证明,Delphi没有在堆栈上对齐变量,也没有指令/选项来控制这种行为.我的XP SP3上的默认COM编组器在编组记录时似乎需要4字节对齐.更糟糕的是,当它遇到未对齐的指针时,它不会返回错误,哦不:它将指针向下舍入到最近的4字节边界并继续这样做.

因此,如果您通过引用将已经在堆栈上分配的记录传递给COM编组功能,那么您就会被搞砸,甚至不知道.

这个问题可以通过使用New/Dispose来分配记录来解决,因为内存管理器倾向于将所有内容对齐为8个字节或更好,但是上帝,这很烦人,未对齐部分和"修剪指针"部分.

这真的是原因,还是我错了?

更新:如何重现(Delphi 2007 for Win32).

uses SysUtils;

type
  TRec = packed record
    a, b, c, d, e: int64;
  end;

  TDummy = class
  protected
    procedure Proc(param1: integer);
  end;

procedure TDummy.Proc(param1: integer);
var a, b, c: byte;
  rec: TRec;
begin
  a := 5;
  b := 9;
  c := 100;

  rec.a := param1;
  rec.b := a;
  rec.c := b;
  rec.d := c;
  writeln(IntToHex(integer(@rec), 8));
  readln;
end;

var Obj: TDummy;
begin
  obj := TDummy.Create;
  try
    obj.Proc(0);
  finally
    FreeAndNil(obj); …
Run Code Online (Sandbox Code Playgroud)

delphi com

7
推荐指数
1
解决办法
445
查看次数

将Delphi const字符串参数传递到内存管理器边界是否安全?

SUBJ.我想使用字符串而不是PChar,因为这样可以节省很多时间,但如果我这样做的话

procedure SomeExternalProc(s: string); external SOMEDLL_DLL;
Run Code Online (Sandbox Code Playgroud)

然后使用非共享内存管理器在其他项目中实现它:

library SeparateDll;
procedure SomeExternalProc(s: string);
begin
  //a bla bla bla
  //code here code here
end;
Run Code Online (Sandbox Code Playgroud)

我(正式)不保证Delphi不会因任何原因决定更改字符串,修改其引用计数器,复制或唯一它,或其他任何东西.例如

var InternalString: string;

procedure SomeExternalProc(s: string);
begin
  InternalString := s;
end;
Run Code Online (Sandbox Code Playgroud)

Delphi递增refcounter并复制指针,就是这样.我想让Delphi复制数据.将参数声明为"const"会使其安全吗?如果没有,有办法吗?将参数声明为PChar似乎不是解决方案,因为您需要每次都将其强制转换:

procedure SomeExternalProc(s: Pchar); forward;
procedure LocalProc;
var local_s: string;
begin
  SomeExternalProc(local_s); //<<--- incompatible types: 'string' and 'PAnsiChar'
end;
Run Code Online (Sandbox Code Playgroud)

delphi string parameters const

7
推荐指数
2
解决办法
929
查看次数

使用Indy的HTTP连续打包流

我有一个JSON-RPC服务,其中一个请求返回一个连续的JSON对象流.

即:

{id:'1'}
{id:'2'}
//30 minutes of no data
{id:'3'}
//...
Run Code Online (Sandbox Code Playgroud)

当然,没有内容长度,因为流是无穷无尽的.

我正在使用自定义TStream后代来接收和解析数据.但内部TIdHttp缓冲数据并且RecvBufferSize在收到字节之前不会将其传递给我.

这导致:

{id:'1'} //received
{id:'2'} //buffered by Indy but not received
//30 minutes of no data
{id:'3'} //this is where Indy commits {id:'2'} to me
Run Code Online (Sandbox Code Playgroud)

显然这不会做,因为30分钟前重要的信息应该在30分钟前送达.

我希望Indy能做套接字的工作:如果有可用数据则立即读取RecvBufferSize并立即返回.

我从2005年发现了这个讨论,其中一些可怜的灵魂试图向Indy开发者解释这个问题,但他们并不了解他.(阅读它;这是一个悲伤的景象)

无论如何,他通过编写自定义IOHandler后代来解决这个问题,但那是在2005年,也许今天有一些现成的解决方案?

delphi indy indy10 idhttp

6
推荐指数
1
解决办法
2298
查看次数

重建窗口时锚点被破坏的解决方法?

这种情况发生在直到XE3的所有Delphi中:

  1. 创建一个表单并在其上放置一个面板.将面板固定到[akLeft, akTop, akRight, akBottom],但在它和边框之间留出空间.
  2. 添加一个调用按钮 RecreateWnd()
  3. 运行应用程序.调整窗体大小以隐藏面板,因为它由于锚定而小于0像素.按下重新创建按钮.
  4. 重新调整表单大小并注意面板的锚定已损坏.

只要我记得自己使用Delphi,就会因此无法使用锚点.调整表单大小,然后停靠它:重新创建窗口,您的布局被破坏.

我想知道是否有某种解决方法?

更新

评论中提供了两种解决方法,一种是经证实且稳定但形式眨眼,另一种是实验性但可能更彻底和清洁.

我暂时不会投票给任何一个,因为其中一个是我的,我甚至不确定它是否稳定.相反,我会等待一些公众意见.

delphi

5
推荐指数
1
解决办法
986
查看次数

Delphi字符串比较函数有什么区别?

有很多方法可以比较现代Delphi中的字符串(比如2010-XE3):

  • '<='运算符,解析为UStrCmp/LStrCmp
  • CompareStr
  • AnsiCompareStr

原则上,有人可以给出(或指向)这些方法的描述吗?

到目前为止,我已经认为AnsiCompareStr在Windows上调用CompareString,这是一种"文本"比较(即考虑到unicode组合字符等).简单的CompareStr没有这样做,似乎做了二进制比较.

但是CompareStr和UStrCmp有什么区别?在UStrCmp和LStrCmp之间?它们都产生相同的结果吗?这些结果是否会在Delphi版本之间发生变化?

我问,因为我需要进行比较,这将始终产生相同的结果,因此使用一个版本的Delphi构建的应用程序中的索引与使用另一个版本构建的代码保持一致.

delphi string-comparison

5
推荐指数
1
解决办法
1204
查看次数

如何以编程方式重新格式化XML?

我有一个关于输入的XML文档,格式很糟糕(如果有人关心的话,它是Delphi项目文件) - 不一致的缩进,空行,节点字符串集中在一起:

<BorlandProject><Delphi.Personality><Parameters><Parameters Name="HostApplication">C:\Some\Path\Filename.exe</Parameters> <!--etc--> <Excluded_Packages>


</Excluded_Packages>
Run Code Online (Sandbox Code Playgroud)

我想将它重新格式化为好的东西.使用Win32/COM以编程方式执行此操作的最简单方法是什么?如果是MSXML,我该怎么办呢?

我希望能够指定缩进单位(制表符/几个空格).

我尝试使用Delphi的MSXML包装器TXmlDocument,它确实删除了带有制表符的空行和缩进节点,但它不会像这样拆分行:

<BorlandProject><Delphi.Personality><Parameters><Parameters Name="HostApplication">C:\Some\Path\Filename.exe</Parameters> <!--etc--> <Excluded_Packages>
Run Code Online (Sandbox Code Playgroud)

xml delphi msxml

4
推荐指数
1
解决办法
8619
查看次数

使用Delphi进行透明远程处理最简单的解决方案是什么?

我有一个两层Delphi for Win32应用程序,在一个神对象中实现了很多业务逻辑,我想将其外包到一个单独的服务中.多个客户端应通过TCP/IP telnet样式协议访问此单独的服务.

我如何才能使过渡变得最简单?

确切地说,我想保持这种简单性:我想只定义一次所有功能.例如,如果我想在我的应用程序中添加PIN码登录功能,我只需要定义

 function Login(Username: string; PinCode: integer): boolean;
Run Code Online (Sandbox Code Playgroud)

在服务器上的某个对象中运行,然后我可以从客户端使用它而无需任何额外的工作.

在最坏的情况下,我必须实现三个功能而不是一个.首先,函数体本身在服务器上,第二,unmarshaller从网络接收文本行,解包并检查有效性:

 procedure HandleCommand(Cmd: string; Params: array of string);
 begin
   ...
   if SameText(Cmd, 'Login') then begin
     CheckParamCount(Params, 2);
     ServerObject.Login(
       Params[0],
       StrToInt(Params[1])
     );
   end;
 end;
Run Code Online (Sandbox Code Playgroud)

第三,marshaller在被客户端调用时打包params并将它们发送到服务器:

function TServerConnection.Login(Username: string; PinCode: integer): boolean;
begin
  Result := StrToBool(ServerCall('Login '+Escape(Username)+' '+IntToStr(PinCode)));
end;
Run Code Online (Sandbox Code Playgroud)

显然,我不想要这个.

到目前为止,我已经设法摆脱了unmarshaller.使用Delphi RTTI,我写了一个通用的unmarshaller,它按名称查找已发布的方法,检查params并调用它.

所以现在我可以将已发布的方法添加到服务器对象中,我可以从telnet调用它:

 function Login(Username: string; PinCode: integer): boolean;

 > login john_locke
 Missing parameter 2 (PinCode: integer)!
Run Code Online (Sandbox Code Playgroud)

但是我怎么做关于编写编组的人呢?我无法动态获取服务器功能列表并向客户端对象添加功能.我可以保留一些动态伪函数集合,但这会让我的客户端调用丑陋:

ServerConnection.Call('Login', [Username, Password]);
Run Code Online (Sandbox Code Playgroud)

此外,这会破坏类型安全性,因为每个参数都作为变体传递.如果可能的话,我想保持编译时类型安全.

也许客户端代码自动生成?我可以在我的服务器中写"GetFunctionList()"和"GetFunctionPrototype(Name:string)":

> GetFunctionList
Login
Logout
IsLoggedIn

> …
Run Code Online (Sandbox Code Playgroud)

delphi remoting rpc design-patterns rtti

3
推荐指数
2
解决办法
854
查看次数

OnMouseMove事件是否应无休止地到达?

我正在尝试在Delphi(XE3)中处理OnMouseMove,即使不移动鼠标,我也会无休止地收到OnMouseMove事件流。

例如 :启动新的VCL表单应用程序。使用以下代码将OnMouseMove处理函数添加到表单中:

var s: string;
begin
  s := IntToStr(GetTickCount()) + ': MouseMove';
  OutputDebugString(PChar(s));
end;
Run Code Online (Sandbox Code Playgroud)

将鼠标放在窗体上,在IDE的“消息”日志中观察无尽的OnMouseMoves。

我希望MouseMove消息仅在我实际移动光标时才会到达(也许在其他一些特殊情况下)。实际上,尽管OnMouseMove总是这样工作的。

难道我做错了什么?从Delphi的角度来看(即通过设计),这是否正确?WinAPI正确吗?怎么办呢?

delphi

0
推荐指数
1
解决办法
359
查看次数