在XE中使用pchar数组作为参数调用外部dll

时间:2013-02-08 02:13:51

标签: delphi dll unicode pchar

我有一个在delphi 6中运行良好的delphi项目,但是当我升级到XE时它不起作用。 我知道它与delphi XE中的新unicode类型有关,我已经尝试将参数的定义从pchar更改为pansichar,ansichar但到目前为止还没有成功。谁能看到我做错了什么? 我的项目调用第三方dll中的函数,其定义如下:

type
PPChar = array of PChar;
{$EXTERNALSYM gsapi_init_with_args}
function gsapi_init_with_args(pinstance:Pgs_main_instance;argc:integer;argv:PPChar):integer; stdcall;

Implementation
{$EXTERNALSYM gsapi_init_with_args}
function gsapi_init_with_args; stdcall; external gsdll32 name 'gsapi_init_with_args';

以下是我如何调用该函数。

procedure PSPDF(input : string; output:string);
var
code:integer;
instance:Pointer;
argv:array of PAnsiChar;

begin
new(instance);
setlength(argv,10);
code:=gsapi_new_instance(@instance,nil);
if code<>0 then
begin
raise Exception.Create('Impossible to open an instance of ghostscript. Error code: '+IntToStr(code));
end;

try

argv[0] := PAnsiChar('ps2pdf');
argv[1] := PAnsiChar('-dNOPAUSE');
argv[2] := PAnsiChar('-dBATCH');
argv[3] := PAnsiChar('-dSAFER');
argv[4] := PAnsiChar('-sDEVICE=pdfwrite');
argv[5] := PAnsiChar(PAnsiString('-sOutputFile='+output));
argv[6] := PAnsiChar('-c');
argv[7] := PAnsiChar('.setpdfwrite');
argv[8] := PAnsiChar('-f');
argv[9] := PAnsiChar(PAnsiString(input));

gsapi_new_instance(instance, nil);

code := gsapi_init_with_args(instance,length(argv),@argv[0]);
if code<0 then
raise Exception.Create('ERROR: init_args: '+IntToStr(code));
gsapi_exit(instance);
gsapi_delete_instance(instance);

finally
end;
end;

如果有人可以帮助我,我将非常感激。

马里奥。

2 个答案:

答案 0 :(得分:4)

PChar更改为PAnsiChar是正确的做法,但是array of ...在DLL函数参数中使用是不安全的,即使在Delphi 6项目中使用也是错误的。查看official Ghostscript documentation后,请在两个项目中尝试:

interface

type
  PPAnsiChar = ^PAnsiChar;
  {$NODEFINE PPAnsiChar}

function gsapi_new_instance(var pinstance: Pointer; caller_handle: Pointer): Integer; stdcall;
{$EXTERNALSYM gsapi_new_instance}

procedure gsapi_delete_instance(instance: Pointer); stdcall;
{$EXTERNALSYM gsapi_delete_instance}

function gsapi_init_with_args(instance: Pointer; argc: Integer; argv: PPAnsiChar): Integer; stdcall;
{$EXTERNALSYM gsapi_init_with_args}

function gsapi_exit(instance: Pointer): Integer; stdcall;
{$EXTERNALSYM gsapi_exit}

implementation

function gsapi_new_instance; external gsdll32 name 'gsapi_new_instance';
procedure gsapi_delete_instance; external gsdll32 name 'gsapi_delete_instance';
function gsapi_init_with_args; external gsdll32 name 'gsapi_init_with_args';
function gsapi_exit; external gsdll32 name 'gsapi_exit';

procedure PSPDF(input : AnsiString; output: AnsiString);
var
  code:integer;
  instance: Pointer;
  argv: array of PAnsiChar;
begin
  code := gsapi_new_instance(instance, nil);
  if code < 0 then
    raise Exception.Create('Impossible to open an instance of ghostscript. Error code: '+IntToStr(code));
  try
    SetLength(argv, 10);
    argv[0] := PAnsiChar('ps2pdf');
    argv[1] := PAnsiChar('-dNOPAUSE');
    argv[2] := PAnsiChar('-dBATCH');
    argv[3] := PAnsiChar('-dSAFER');
    argv[4] := PAnsiChar('-sDEVICE=pdfwrite');
    argv[5] := PAnsiChar('-sOutputFile='+output);
    argv[6] := PAnsiChar('-c');
    argv[7] := PAnsiChar('.setpdfwrite');
    argv[8] := PAnsiChar('-f');
    argv[9] := PAnsiChar(input);

    code := gsapi_init_with_args(instance, Length(argv), @argv[0]);
    if code < 0 then
      raise Exception.Create('ERROR: init_args: '+IntToStr(code));
    try
      ...
    finally
      gsapi_exit(instance);
    end;
  finally
    gsapi_delete_instance(instance);
  end;
end;

更新:这是gsapi.pas unit的更正版本,应该在两个Delphi版本中都有效:

// Copyright (c) 2001-2002 Alessandro Briosi 
// 
// Permission is hereby granted, free of charge, to any person  
// obtaining a copy of this software and associated documentation  
// files (the "Software"), to deal in the Software without  
// restriction, including without limitation the rights to use, copy,  
// modify, merge, publish, distribute, sublicense, and/or sell copies  
// of the Software, and to permit persons to whom the Software is  
// furnished to do so, subject to the following conditions: 
//  
// The above copyright notice and this permission notice shall be  
// included in all copies or substantial portions of the Software. 
//  
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND  
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS  
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN  
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
// SOFTWARE. 
//  
// 
// This software was written by Alessandro Briosi with the  
// assistance of Russell Lang, as an example of how the  
// Ghostscript DLL may be used Delphi. 
// 

unit gsapi; 

interface 

uses
  Windows; 

// {$HPPEMIT '#include <iminst.h>'} 

const
  gsdll32 = 'gsdll32.dll'; 

  STDIN_BUF_SIZE = 128; 
  {$EXTERNALSYM STDIN_BUF_SIZE}
  STDOUT_BUF_SIZE = 128; 
  {$EXTERNALSYM STDOUT_BUF_SIZE}
  STDERR_BUF_SIZE = 128; 
  {$EXTERNALSYM STDERR_BUF_SIZE}

  DISPLAY_VERSION_MAJOR = 1; 
  {$EXTERNALSYM DISPLAY_VERSION_MAJOR}
  DISPLAY_VERSION_MINOR = 0; 
  {$EXTERNALSYM DISPLAY_VERSION_MINOR}

  //* Define the color space alternatives */ 
  DISPLAY_COLORS_NATIVE = $01; 
  {$EXTERNALSYM DISPLAY_COLORS_NATIVE}
  DISPLAY_COLORS_GRAY   = $02; 
  {$EXTERNALSYM DISPLAY_COLORS_GRAY}
  DISPLAY_COLORS_RGB    = $04; 
  {$EXTERNALSYM DISPLAY_COLORS_RGB}
  DISPLAY_COLORS_CMYK   = $08; 
  {$EXTERNALSYM DISPLAY_COLORS_CMYK}

  DISPLAY_COLORS_MASK  = $000f; 
  {$EXTERNALSYM DISPLAY_COLORS_MASK}

  //* Define whether alpha information, or an extra unused bytes is included */ 
  //* DISPLAY_ALPHA_FIRST and DISPLAY_ALPHA_LAST are not implemented */ 
  DISPLAY_ALPHA_NONE   = $00; 
  {$EXTERNALSYM DISPLAY_ALPHA_NONE}
  DISPLAY_ALPHA_FIRST  = $10; 
  {$EXTERNALSYM DISPLAY_ALPHA_FIRST}
  DISPLAY_ALPHA_LAST   = $20; 
  {$EXTERNALSYM DISPLAY_ALPHA_LAST}
  DISPLAY_UNUSED_FIRST = $40;    //* e.g. Mac xRGB */ 
  {$EXTERNALSYM DISPLAY_UNUSED_FIRST}
  DISPLAY_UNUSED_LAST  = $80;   //* e.g. Windows BGRx */ 
  {$EXTERNALSYM DISPLAY_UNUSED_LAST}

  DISPLAY_ALPHA_MASK  = $0070; 
  {$EXTERNALSYM DISPLAY_ALPHA_MASK}

  // * Define the depth per component for DISPLAY_COLORS_GRAY, 
  // * DISPLAY_COLORS_RGB and DISPLAY_COLORS_CMYK, 
  // * or the depth per pixel for DISPLAY_COLORS_NATIVE 
  // * DISPLAY_DEPTH_2 and DISPLAY_DEPTH_12 have not been tested. 
  // * 
  DISPLAY_DEPTH_1   = $0100; 
  {$EXTERNALSYM DISPLAY_DEPTH_1}
  DISPLAY_DEPTH_2   = $0200; 
  {$EXTERNALSYM DISPLAY_DEPTH_2}
  DISPLAY_DEPTH_4   = $0400; 
  {$EXTERNALSYM DISPLAY_DEPTH_4}
  DISPLAY_DEPTH_8   = $0800; 
  {$EXTERNALSYM DISPLAY_DEPTH_8}
  DISPLAY_DEPTH_12  = $1000; 
  {$EXTERNALSYM DISPLAY_DEPTH_12}
  DISPLAY_DEPTH_16  = $2000; 
  {$EXTERNALSYM DISPLAY_DEPTH_16}
  //* unused (1<<14) */ 
  //* unused (1<<15) */ 

  DISPLAY_DEPTH_MASK  = $ff00; 
  {$EXTERNALSYM DISPLAY_DEPTH_MASK}

  // * Define whether Red/Cyan should come first, 
  // * or whether Blue/Black should come first 
  // */ 
  DISPLAY_BIGENDIAN    = $00000;    //* Red/Cyan first */ 
  {$EXTERNALSYM DISPLAY_BIGENDIAN}
  DISPLAY_LITTLEENDIAN = $10000;    //* Blue/Black first */ 
  {$EXTERNALSYM DISPLAY_LITTLEENDIAN}

  DISPLAY_ENDIAN_MASK  = $00010000; 
  {$EXTERNALSYM DISPLAY_ENDIAN_MASK}

  //* Define whether the raster starts at the top or bottom of the bitmap */ 
  DISPLAY_TOPFIRST    = $00000; //* Unix, Mac */ 
  {$EXTERNALSYM DISPLAY_TOPFIRST}
  DISPLAY_BOTTOMFIRST = $20000; //* Windows */ 
  {$EXTERNALSYM DISPLAY_BOTTOMFIRST}

  DISPLAY_FIRSTROW_MASK = $00020000; 
  {$EXTERNALSYM DISPLAY_FIRSTROW_MASK}

  //* Define whether packing RGB in 16-bits should use 555 
  // * or 565 (extra bit for green) 
  // */ 
  DISPLAY_NATIVE_555 = $00000; 
  {$EXTERNALSYM DISPLAY_NATIVE_555}
  DISPLAY_NATIVE_565 = $40000; 
  {$EXTERNALSYM DISPLAY_NATIVE_565}
  DISPLAY_555_MASK  = $00040000; 
  {$EXTERNALSYM DISPLAY_555_MASK}

type 
  TGSAPIrevision = record 
    product: PAnsiChar; 
    copyright: PAnsiChar; 
    revision: Longint; 
    revisiondat: Longint; 
  end; 

  TStdioFunction = function(caller_handle: Pointer; buf: PAnsiChar; len: Integer): Integer; stdcall; 
  TPollFunction = function(caller_handle: Pointer): Integer; stdcall; 

  TDisplayEvent = function(handle: Pointer; device: Pointer): Integer; cdecl; 
  TDisplayPreResizeEvent = function(handle: Pointer; device: Pointer; 
         width: Integer; height: Integer; raster: Integer; format: UINT): Integer; cdecl; 
  TDisplayResizeEvent = function(handle: Pointer; device: Pointer; 
         width: Integer; height: Integer; raster: Integer; format: UINT; pimage: PAnsiChar): Integer; cdecl; 
  TDisplayPageEvent = function(handle: Pointer; device: Pointer; copies: Integer; flush: Integer): Integer; cdecl; 
  TDisplayUpdateEvent = function(handle: Pointer; device: Pointer; x: Integer; y: Integer; w: Integer; h: Integer): Integer; cdecl; 
  TDisplayMemAlloc = procedure(handle: Pointer; device: Pointer; size: ulong); cdecl; 
  TDisplayMemFree = function(handle: Pointer; device: Pointer; mem: Pointer): Integer; cdecl; 

  TDisplayCallback = record 
    size: Integer; 
    version_major: Integer; 
    version_minor: Integer; 
    // New device has been opened */ 
    // This is the first event from this device. */ 
    display_open: TDisplayEvent; 
    // Device is about to be closed. */ 
    // Device will not be closed until this function returns. */ 
    display_preclose: TDisplayEvent; 
    // Device has been closed. */ 
    // This is the last event from this device. */ 
    display_close: TDisplayEvent; 
    // Device is about to be resized. */ 
    // Resize will only occur if this function returns 0. */ 
    // raster is byte count of a row. */ 
    display_presize: TDisplayPreResizeEvent; 
    // Device has been resized. */ 
    // New pointer to raster returned in pimage */ 
    display_size: TDisplayResizeEvent; 

    // flushpage */ 
    display_sync: TDisplayEvent; 

    // showpage */ 
    // If you want to pause on showpage, then don't return immediately */ 
    display_page: TDisplayPageEvent; 

    // Notify the caller whenever a portion of the raster is updated. */ 
    // This can be used for cooperative multitasking or for 
    // progressive update of the display. 
    // This function pointer may be set to NULL if not required. 
    // 
    display_update: TDisplayUpdateEvent; 

    // Allocate memory for bitmap */ 
    // This is provided in case you need to create memory in a special 
    // way, e.g. shared.  If this is NULL, the Ghostscript memory device 
    // allocates the bitmap. This will only called to allocate the 
    // image buffer. The first row will be placed at the address 
    // returned by display_memalloc. 
    // 

    display_memalloc: TDisplayMemAlloc; 

    // Free memory for bitmap */ 
    // If this is NULL, the Ghostscript memory device will free the bitmap */ 
    display_memfree: TDisplayMemFree; 

  end; 

  PPAnsiChar = ^PAnsiChar; 
  {$NODEFINE PPAnsiChar}

function gsapi_revision(var pr: TGSAPIrevision; len: Integer): Integer; stdcall; 
{$EXTERNALSYM gsapi_revision} 
function gsapi_new_instance(var pinstance: Pointer; caller_handle: Pointer): Integer; stdcall; 
{$EXTERNALSYM gsapi_new_instance} 
procedure gsapi_delete_instance(pinstance: Pointer); stdcall; 
{$EXTERNALSYM gsapi_delete_instance} 
function gsapi_set_stdio(pinstance: Pointer; 
                         stdin_fn: TStdioFunction; stdout_fn: TStdioFunction; 
                         stderr_fn: TStdioFunction): Integer; stdcall; 
{$EXTERNALSYM gsapi_set_stdio} 
function gsapi_set_poll(pinstance: Pointer; poll_fn: TPollFunction): Integer; stdcall; 
{$EXTERNALSYM gsapi_set_poll} 
function gsapi_set_display_callback(pinstance: Pointer; const callback: TDisplayCallback): Integer; stdcall; 
{$EXTERNALSYM gsapi_set_display_callback} 
function gsapi_init_with_args(pinstance: Pointer; argc: Integer; argv: PPAnsiChar): Integer; stdcall; 
{$EXTERNALSYM gsapi_init_with_args} 
function gsapi_run_string_begin(pinstance: Pointer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall; 
{$EXTERNALSYM gsapi_run_string_begin} 
function gsapi_run_string_continue(pinstance: Pointer; str: PAnsiChar; len: Integer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall; 
{$EXTERNALSYM gsapi_run_string_continue} 
function gsapi_run_string_end(pinstance: Pointer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall; 
{$EXTERNALSYM gsapi_run_string_end} 
function gsapi_run_string_with_length(pinstance: Pointer; str: PAnsiChar; len: Integer; user_errors: Integer; var pexit_code: Integer): Integer; stdcall; 
{$EXTERNALSYM gsapi_run_string_with_length} 
function gsapi_run_string(pinstance: Pointer; str: PAnsiChar; user_errors: Integer; var pexit_code: Integer): Integer; stdcall; 
{$EXTERNALSYM gsapi_run_string} 
function gsapi_run_file(pinstance: Pointer; file_name: PAnsiChar; user_errors: Integer; var pexit_code: Integer): Integer; stdcall; 
{$EXTERNALSYM gsapi_run_file} 
function gsapi_exit(pinstance: Pointer): Integer; stdcall; 
{$EXTERNALSYM gsapi_exit} 

implementation 

function gsapi_revision; external gsdll32 name 'gsapi_revision'; 
function gsapi_new_instance; external gsdll32 name 'gsapi_new_instance'; 
procedure gsapi_delete_instance; external gsdll32 name 'gsapi_delete_instance'; 
function gsapi_set_stdio; external gsdll32 name 'gsapi_set_stdio'; 
function gsapi_set_poll; external gsdll32 name 'gsapi_set_poll'; 
function gsapi_set_display_callback; external gsdll32 name 'gsapi_set_display_callback'; 
function gsapi_init_with_args; external gsdll32 name 'gsapi_init_with_args'; 
function gsapi_run_string_begin; external gsdll32 name 'gsapi_run_string_begin'; 
function gsapi_run_string_continue; external gsdll32 name 'gsapi_run_string_continue'; 
function gsapi_run_string_end; external gsdll32 name 'gsapi_run_string_end'; 
function gsapi_run_string_with_length; external gsdll32 name 'gsapi_run_string_with_length'; 
function gsapi_run_string; external gsdll32 name 'gsapi_run_string'; 
function gsapi_run_file; external gsdll32 name 'gsapi_run_file'; 
function gsapi_exit; external gsdll32 name 'gsapi_exit'; 

end. 

答案 1 :(得分:0)

旧的Delphi 6 PChar是Unicode Delphi(2009+)上的PAnsiChar,所以如果你将所有PChar引用改为PAnsiChar,一切都应该有效。

(包括你的Pgs_main_instance声明,如果有任何PChar在那里)

type
  PPAnsiChar = array of PAnsiChar;
  {$EXTERNALSYM gsapi_init_with_args}
  function gsapi_init_with_args(pinstance: Pgs_main_instance;
             argc: Integer; argv:PPAnsiChar): Integer; stdcall;

implementation

  function gsapi_init_with_args(pinstance: Pgs_main_instance;
             argc: Integer; argv:PPAnsiChar): Integer; 
  external gsdll32 name 'gsapi_init_with_args';

致电代码:

var
  argv:PPAnsiChar;
  instance: Pointer;

begin
  new(instance);  //how many bytes, this really doesn't make sense with a untyped pointer!
  setlength(argv, 4);
  argv[0] := PAnsiChar('ps2pdf');
  argv[1] := PAnsiChar('-dNOPAUSE');
  argv[2] := PAnsiChar('-dBATCH');
  argv[3] := PAnsiChar('-dSAFER');
  gsapi_init_with_args(instance, Length(argv), argv);
end;

要了解Unicode中的 new ,我建议您阅读MarcoCantù撰写的Delphi and Unicode白皮书。