我有一个使用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参数,似乎有某种模仿机制正在进行中.但目前还不清楚是谁冒充了谁.涉及三个用户凭据:
ServerApp在服务器PC上运行的用户(在dcomcnfg中配置).
连接时ClientApp指定凭据的用户.
ClientApp在客户端PC上运行其凭据的用户.
无论你如何看待它,如果涉及#3,那么它就是一个用户.如果DCOM要在服务器PC上识别/模仿#3,为什么我需要指定#2的凭证?到了什么地步?
DCOM冒充#2似乎是合乎逻辑的,因为这是我明确指定为我的凭据.但为什么第二次登录尝试呢?
有人可以解释模仿是如何工作的,还有一种方法可以忽略它并以dcomcnfg中指定的用户身份运行?
这不是一个直截了当的问题,因为我刚刚解决了它,但更像是"我是否正确"这类问题,并提醒那些可能会陷入困境的人.
事实证明,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) 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) 我有一个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年,也许今天有一些现成的解决方案?
这种情况发生在直到XE3的所有Delphi中:
[akLeft, akTop, akRight, akBottom],但在它和边框之间留出空间.RecreateWnd()只要我记得自己使用Delphi,就会因此无法使用锚点.调整表单大小,然后停靠它:重新创建窗口,您的布局被破坏.
我想知道是否有某种解决方法?
评论中提供了两种解决方法,一种是经证实且稳定但形式眨眼,另一种是实验性但可能更彻底和清洁.
我暂时不会投票给任何一个,因为其中一个是我的,我甚至不确定它是否稳定.相反,我会等待一些公众意见.
有很多方法可以比较现代Delphi中的字符串(比如2010-XE3):
原则上,有人可以给出(或指向)这些方法的描述吗?
到目前为止,我已经认为AnsiCompareStr在Windows上调用CompareString,这是一种"文本"比较(即考虑到unicode组合字符等).简单的CompareStr没有这样做,似乎做了二进制比较.
但是CompareStr和UStrCmp有什么区别?在UStrCmp和LStrCmp之间?它们都产生相同的结果吗?这些结果是否会在Delphi版本之间发生变化?
我问,因为我需要进行比较,这将始终产生相同的结果,因此使用一个版本的Delphi构建的应用程序中的索引与使用另一个版本构建的代码保持一致.
我有一个关于输入的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) 我有一个两层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(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正确吗?怎么办呢?