1

我目前正在将日历约会从我们的应用程序同步到 Win Server 2008 上的 Exchange Server 2007 SP1。它应该处理删除和添加多个用户帐户的约会。该接口是使用 Delphi XE5 的 WDSL-Import 组件创建的。它生成一个类型“ExchangeServicePortType”,使用如下:

var
  ws: ExchangeServicePortType;
  exCreate: CreateItem;
  exItemResp: CreateItemResponse;
  exImper: ExchangeImpersonation;
  secContext: SerializedSecurityContext;
  exMailboxCult: MailboxCulture;
  exReqServerVersion: RequestServerVersion;
  exServerVersion: ServerVersionInfo;
....
ws := GetExchangeServicePortType(false);
...
exImper.ConnectingSID.SID := <useraccount>; 
...
ws.CreateItem(exCreate, exImper, secContext, exMailboxCult, exReqServerVersion,  
    exCreateItemResponse, exServerVersion);

问题:它只适用于“模拟”在以下情况下:

  • 'syncuser' 正在客户端上运行同步程序。
  • 服务器上的“syncuser”帐户对所有用户帐户具有特殊权限 ms-Exch-EPI-Impersonation、ms-Exch-EPI-May-Impersonate。
  • 为服务器上的所有人调用 cmdlet 'Add-MailboxPermission -Identity "user-account" -User -AccessRights FullAccess -InheritanceType All'。
  • EWS 身份验证 = Windows 身份验证

问题:在 Delphi XE 中是否有可能在没有“模拟”的情况下调用 EWS,它是如何工作的?

在托管 API 中可以调用:

ExchangeServiceBinding ws = new ExchangeServiceBinding();
ws.Credentials = new NetworkCredential("user", "password", "domain");

非常感谢任何帮助/想法/解释/建议。


感谢大卫赫弗南。我已经尝试了使用带有 R. Giesecke 的 .DllExport 扩展名的 C#-dll (Visual Studio 2010) 和 EWS 托管 api 1.2 的建议方法。代码如下所示:

EWSTerminSync.cs
...
using System.Runtime.InteropServices;
using RGiesecke.DllExport;
...

public class  EWSSync
{      
   public static ExchangeService service;

    private static bool CertificateValidationCallBack(
       object sender,
       System.Security.Cryptography.X509Certificates.X509Certificate certificate,
       System.Security.Cryptography.X509Certificates.X509Chain chain,
       System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        ...
    }   

   [DllExport]
    public static int InitEWS()
    {           
       (0)ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;               

      (1) service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
       service.Credentials = new WebCredentials("name", "pwd", "domain");
       service.Url = new Uri("https://myServer/EWS/Exchange.asmx");
       ...
    }   
    [DllExport]
    public static int DoSomething()
    {
    ...
    }
}

C#-dll 在 Delphi7 应用程序中加载,如下所示:

type
TCreateInstance = function(): integer; stdcall;

FDLLHandle: THandle;
...
procedure Execute()
var
    res: integer;
begin
FDLLHandle := LoadLibrary(pansichar('EWSTerminSync.dll'));
if FDLLHandle >= 32 then
begin
    @FCreateInstance := GetProcAddress(FDLLHandle, 'InitEWS');

    res := FCreateInstance;
    ...
end;
...
end;

如果它作为 delphi 应用程序执行,则一切正常。我可以创建/删除约会、日历和其他东西。但我必须在作为 Windows 服务运行的 delphi 应用程序中使用它。相同的代码会产生错误“EXCEPTION: EExternalException / Externe Exception E0434352”。在函数 InitEWS() 中运行第 (1) 行。无需调用任何 ews 托管的 api 函数,只需在函数 InitEWS() 中进行一些字符串操作,服务中的一切也都可以正常工作。应用程序和服务在相同的用户凭据下运行。

在 Windows 服务中使用 ews 管理的 api 是否有任何限制?为了在服务中调用 ews 托管的 api 函数,必须执行哪些设置?

4

1 回答 1

0

您可以在没有模拟的情况下使用 Ews,问题是 Delphi 即使为 nil 参数添加了一个 xml 节点(无论 soDontSendEmptyNodes 选项如何)。我找不到比创建一个简单地跳过 nil 参数的新 TOPToSoapDomConvert 类更好的方法来消除这种情况。

unit SoapHelpers;

interface

uses
  System.Classes, Soap.IntfInfo, Soap.InvokeRegistry, Soap.OPToSOAPDomConv;

type

  TOPToSoapDomConvert2 = class(TOPToSoapDomConvert)
  public
    function InvContextToMsg(const IntfMD: TIntfMetaData;
                              MethNum: Integer;
                              Con: TInvContext;
                              Headers: THeaderList): TStream; override;
  end;

implementation

uses
  System.SysUtils, System.TypInfo;

type
  TInvContextTmp = class(TInvContext)
  public
    procedure CopyPointers(Cont: TInvContext);
    procedure RemovePointer(Index: Integer);
  end;

const
  IS_OUT  = $0200;

{ TOPToSoapDomConvert2 }

// Skip null parameters they are always being sent regardless of sendemptynodes settings
function TOPToSoapDomConvert2.InvContextToMsg(const IntfMD: TIntfMetaData;
  MethNum: Integer; Con: TInvContext; Headers: THeaderList): TStream;
var
  MethMD: TIntfMethEntry;
  Params, ParamsSave: TIntfParamEntryArray;
  Con2: TInvContextTmp;
  P: Pointer;
  I, K, XmlOptions, ParamCountSave, ParamCount: Integer;
  ExtParamName, ParamNamespace: string;
begin
  MethMD := IntfMD.MDA[MethNum];

  ParamsSave := MethMD.Params;
  ParamCountSave := MethMD.ParamCount;
  ParamCount := MethMD.ParamCount;

  SetLength(Params, Length(MethMD.Params));
  for I := Low(Params) to High(Params) do
    Params[I] := MethMD.Params[I];

  Con2 := TInvContextTmp.Create;
  Con2.CopyPointers(Con);

  for I := High(Params) downto Low(Params) do
  begin
    InvRegistry.GetParamInfo(IntfMD.Info, MethMD.Name, Params[I].Name,
                             ExtParamName, ParamNamespace, XMLOptions);

    if not ((pfOut in Params[I].Flags) or ((XMLOptions and IS_OUT) = IS_OUT)) then
    begin
      P := Con.GetParamPointer(I);
      if (Params[I].Info <> nil) and (Params[I].Info.Kind = tkClass) and (Pointer(P^) = nil) then
      begin
        for K := I + 1 to High(Params) do
          Params[K-1] := Params[K];
        SetLength(Params, Length(Params)-1);

        Dec(ParamCount);
        Con2.RemovePointer(I);
      end;
    end;
  end;

  if Length(MethMD.Params) <> Length(Params) then
  begin
    MethMD.ParamCount := ParamCount;
    MethMD.Params := Params;
    IntfMD.MDA[MethNum] := MethMD;
  end;

  try
    Result := inherited InvContextToMsg(IntfMD, MethNum, Con2, Headers);
  finally
    if Length(MethMD.Params) <> Length(ParamsSave) then
    begin
      MethMD.ParamCount := ParamCountSave;
      MethMD.Params := ParamsSave;
      IntfMD.MDA[MethNum] := MethMD;
    end;
    Con2.Free;
  end;
end;

{ TInvContextTmp }

procedure TInvContextTmp.CopyPointers(Cont: TInvContext);
var
  k: Integer;
begin
  SetLength(DataP, Length(TInvContextTmp(Cont).DataP));
  for k := Low(TInvContextTmp(Cont).DataP) to High(TInvContextTmp(Cont).DataP) do
    DataP[k] := TInvContextTmp(Cont).DataP[k];
end;

procedure TInvContextTmp.RemovePointer(Index: Integer);
var
  k: Integer;
begin
  for k := Index+1 to High(DataP) do
    DataP[k-1] := DataP[k];
end;

end.

什么时候,你可以像这样使用它:

...
    lRIO := THTTPRio.Create(nil);

    lRIO.Converter := TOPToSoapDomConvert2.Create(lRIO);
    lRIO.Converter.WSDLView := nil;
...
于 2013-12-19T07:37:26.407 回答