传递给函数时,Delphi PChar字符串为空

时间:2015-06-17 12:35:55

标签: json delphi dll

我正在使用Delpi XE6,如果重要的话。

我正在编写一个DLL,它将从Google的Directions API获得响应,解析生成的JSON并确定行程的总距离。

OnException按预期工作。它需要一个网址,并尝试从Google获得回复。如果是,则返回Google返回的JSON字符串。

GetJSONString_OrDie应该接受一个JSON字符串,并解析它以获得旅程中每条腿的总距离,并将这些距离固定在一个双打数组中。

ExtractDistancesFromTrip_OrDie接收一个双精度数组,并对数组求和,并返回总数。

奇怪的是,如果我将这些函数从DLL中取出并将它们放在项目中并像这样调用它,它就会按预期工作。只有当它们陷入DLL时才会出现问题。如上所述,SumTripDistances作为intened工作并返回一个JSON字符串 - 但是当单步执行DLL GetJSONString_OrDie时,传递的PChar字符串为ExtractDistancesForTrip。那是为什么?

''

以下是调用函数的方法:

unit Unit1;



interface
uses
  IdHTTP,
  IdSSLOpenSSL,
  System.SysUtils,
  System.JSON;

type
  arrayOfDouble = array of double;

function GetJSONString_OrDie(url : Pchar) : Pchar;
function ExtractDistancesForTrip_OrDie(JSONstring: Pchar) : arrayOfDouble;
function SumTripDistances(tripDistancesArray: arrayOfDouble) : double;

implementation



{ Attempts to get JSON back from Google's Directions API }
function GetJSONString_OrDie(url : Pchar) : PChar;
var
  lHTTP: TIdHTTP;
  SSL: TIdSSLIOHandlerSocketOpenSSL;
begin
  {Sets up SSL}
  SSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  {Creates an HTTP request}
  lHTTP := TIdHTTP.Create(nil);
  {Sets the HTTP request to use SSL}
  lHTTP.IOHandler := SSL;
  try
    {Attempts to get JSON back from Google's Directions API}
    Result := PWideChar(lHTTP.Get(url));
  finally
    {Frees up the HTTP object}
    lHTTP.Free;
    {Frees up the SSL object}
    SSL.Free;
  end;
end;

{ Extracts the distances from the JSON string }
function ExtractDistancesForTrip_OrDie(JSONstring: Pchar) : arrayOfDouble;
var
  jsonObject: TJSONObject;
  jsonArray: TJSONArray;
  numberOfLegs: integer;
  I: integer;
begin
  //raise Exception.Create('ExtractDistancesForTrip_OrDie:array of double has not yet been '+
  //                        'implemented.');

  jsonObject:= nil;
  jsonArray:= nil;
  try
    { Extract the number of legs in the trip }
    jsonObject:= TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(JSONstring), 0) as TJSONObject;
    jsonObject:= (jsonObject.Pairs[0].JsonValue as TJSONArray).Items[0] as TJSONObject;
    jsonArray:= jsonObject.Pairs[2].JSONValue as TJSONArray;
    numberOfLegs:= jsonArray.Count;

    {Resize the Resuls arrayOfDouble}
    SetLength(Result, numberOfLegs);

    {Loop through the json and set the result of the distance of the leg}
    {Distance is in km}
    for I := 0 to numberOfLegs-1 do
    begin
      Result[I]:= StrToFloat((((jsonArray.Items[I] as TJSONObject).Pairs[0].JsonValue as TJSONObject).Pairs[1]).JsonValue.Value);
    end;


  finally
    jsonObject.Free;
    jsonArray.Free;
  end;

end;


function SumTripDistances(tripDistancesArray: arrayOfDouble) : double;
var
  I: integer;
begin
  //raise Exception.Create('GetDistanceBetweenPoints_OrDie:double has not yet been ' +
 //                        'implemented.');

 Result:= 0;
 {Loop through the tripDistancesArray, and add up all the values.}
 for I := Low(tripDistancesArray) to High(tripDistancesArray) do
    Result := Result + tripDistancesArray[I];


end;

end.

调用第一个函数program Project3; {$APPTYPE CONSOLE} {$R *.res} uses ShareMem, IdHTTP, IdSSLOpenSSL, System.SysUtils, System.JSON, System.Classes; type arrayOfDouble = array of double; testRecord = record testString : string; testInt : integer; end; function GetJSONString_OrDie(url : Pchar) : PWideChar; stdcall; external 'NMBSGoogleMaps.dll'; function ExtractDistancesForTrip_OrDie(JSONstring: pchar) : arrayOfDouble; stdcall; external 'NMBSGoogleMaps.dll'; function SumTripDistances(tripDistancesArray: arrayOfDouble) : double; stdcall; external 'NMBSGoogleMaps.dll'; var jsonReturnString: string; jsonReturnString2: Pchar; doubles: arrayOfDouble; totalJourney: double; uri:Pchar; a : testRecord; begin try uri:= 'https://maps.googleapis.com/maps/api/directions/json?origin=Boston,MA&destination=Concord,MA&waypoints=Charlestown,MA|Lexington,MA&key=GETYOUROWNKEY'; { TODO -oUser -cConsole Main : Insert code here } jsonReturnString:= GetJSONString_OrDie(uri); //On step-through, uri is fine. jsonReturnString2:= stralloc(length(jsonreturnstring)+1); strpcopy(jsonreturnstring2, jsonreturnstring); jsonreturnstring2 := 'RANDOMJUNK'; doubles:= ExtractDistancesForTrip_OrDie(jsonReturnString2); //On step-through, jsonReturnString2 is seen as '', rather than 'RANDOMJUNK' totalJourney:= SumTripDistances(doubles); WriteLn('The total journey was: '); WriteLn(totalJourney); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; readln; end. 时,传入uri并在查看或打印时正确。 但是,在创建随机字符串并将其传递到GetJSONString_OrDie后,该函数只会看到ExtractDistancesForTrip_OrDie。如果我要将''更改为接受整数,或记录或任何内容 - 它会看到垃圾或随机数据。如果我通过引用或值传递并不重要。

1 个答案:

答案 0 :(得分:5)

您的通话约定不匹配。您的函数使用register调用约定,但您将它们导入为stdcall。这就是你传递的参数没有到达的原因。

在实现该功能时以及导入时都使用stdcall

GetJSONString_OrDie中,您将返回指向局部变量缓冲区的指针。函数返回后,该局部变量将被销毁,指针无效。您需要找到一种不同的方法来传递此函数的字符串数据。

返回字符串通常没问题。但是因为这个函数是从一个无法工作的DLL导出的。您需要调用者分配的缓冲区或共享堆上分配的缓冲区。

最后,动态数组不是有效的互操作类型。您不应该跨模块边界传递这些。