Reputation: 17118
I am trying to get a c-based DLL working in Delphi. I thought I'd try to get one of the functions to work before I set in on all the others, and I'm stymied. Here's the C call:
int FindCityCounty(char *zip, char cityname[28], char state[2], char countyname[25],
char countynum[3]);
I'm confused by the notion of char cityname[25]
. Is that:
array[0..24] of Char/AnsiChar;
?
What's the proper way to translate these constructs? All my attempts have ended in jibberish.
UPDATE:
Here's an example of the function in question being called:
#include <stdio.h>
#include <Windows.h>
#include <srv.h> /* for CALLBACK, HINSTANCE */
#include <direct.h> /* for _getdrive and _getdcwd */
#define cpy_blank(word,len) memset(word,' ',len)
#define cpy_word strncpy
typedef int (CALLBACK* FindCityCounty)(
char ZIP[5],char cityname[28],char state[2],char countyname[25],char countynum[3]);
void runCA(FindCityCounty pCA)
{
char ZIP[5], cityname[28], state[2], countyname[25], countynum[3];
int rc;
printf("CorrectAddress C API Demonstration\n\n");
printf("FindCityCounty() function call\n");
printf("==================================\n");
/* set input parameters */
cpy_word(ZIP,"10601",5);
printf("Input ZIP code: %.5s\n", ZIP);
/* call function */
rc = pCA(ZIP, cityname, state, countyname, countynum);
/*** Now output results ***/
printf("Output city: %.28s\n",cityname);
printf("Output state: %.2s\n",state);
printf("Output county name: %.25s\n",countyname);
printf("Output county number: %.3s\n",countynum);
printf("\n\n");
printf("=====================================\n");
printf("(c) Intelligent Search Technology Ltd\n");
printf("=====================================\n");
}
int main()
{
HINSTANCE hDLL;
FindCityCounty pCA;
/* Load DLL and get function location */
hDLL = LoadLibrary("CorrectA.dll");
pCA = (FindCityCounty)GetProcAddress(hDLL,"FindCityCounty");
runCA(pCA);
getch();
return 0;
}
Delphi Code:
unit CorrectAdressAPI;
interface
type
TZip = array[0..4] of AnsiChar;
TCityName = array[0..27] of AnsiChar;
TState = array[0..1] of AnsiChar;
TCountyName = array[0..24] of AnsiChar;
TCountyNum = array[0..2] of AnsiChar;
PCityName = ^TCityName;
PState = ^TState;
PCountyName = ^TCountyName;
PCountyNum = ^TCountyNum;
type
TFindCityCounty = function(aZip: PAnsiChar;
var aCity: TCityName;
var aState: TState;
var aCounty: TCountyName;
var aCountyNum: TCountyNum): Integer; stdcall;
function Load(const AFileName : string) : Boolean;
function Unload : Boolean;
function FindCityCounty(aZip: PANSIChar;
var aCity: TCityName;
var aState: TState;
var aCounty: TCountyName;
var aCountyNum: TCountyNum): Integer;
implementation
uses
Winapi.Windows, dialogs, SysUtils;
var
hDll : THandle;
PFindCityCounty: TFindCityCounty;
function Load(const AFileName : string) : Boolean;
begin
hDll := LoadLibrary(PChar(AFileName));
Result := hDll <> 0;
if Result then
begin
PFindCityCounty := GetProcAddress(hDLL, PAnsiChar('FindCityCounty'));
Assert(Assigned(PFindCityCounty));
end;
end;
function Unload : Boolean;
begin
Result := (hDll <> 0) and FreeLibrary(hDll);
end;
function FindCityCounty(aZip: PANSIChar;
var aCity: TCityName;
var aState: TState;
var aCounty: TCountyName;
var aCountyNum: TCountyNum): Integer;
begin
Result := PFindCityCounty(aZip, aCity, aState, aCounty, aCountyNum);
end;
end.
Upvotes: 0
Views: 688
Reputation: 23036
As Mason says, arrays passed as parameters in 'C' are always passed as a pointer to the declared array type. However, a char array of fixed size is not certain to be a null terminated array, so using a PChar, PWideChar or PANSIChar would be potentially wrong.
To answer your specific question regarding the dimensions of the arrays, you appear to have mixed up your city and county names in your example, but essentially you are correct. C
arrays are 0-based so the C
declaration:
char name[N]
is equivalent to the Pascal:
name: array[0..N-1] of Char;
But getting the correct number of elements in the array is not the end of the story. You also need to be careful to ensure your array element type is declared correctly.
In the case of the char
type you need to be careful that 'Char' is the correct type for the corresponding C environment when converting any C code. In Delphi 1-2007 'Char' is a single byte ANSIChar. In Delphi 2009 onwards 'Char' is a 2-byte WideChar.
In most (if not all) C
implementations, certainly for Windows, char
is an 8-bit/1-byte value, so an ANSIChar is most likely to be the appropriate Pascal type and ensures a 1-byte char on any Delphi version.
Returning to your specific example, the fact that explicitly dimensioned arrays are involved, rather than explicitly (or implicitly) null terminated strings, I think it may be advisable in this particular case to declare types for each of the required array types, with corresponding pointer types:
type
TCityName = array[0..27] of ANSIChar;
TState = array[0..1] of ANSIChar;
TCountyName = array[0..24] of ANSIChar;
TCountyNum = array[0..2] of ANSIChar;
PCityName = ^TCityName;
PState = ^TState;
PCountyName = ^TCountyName;
PCountyNum = ^TCountyNum;
You then have two choices in your Pascal version of the C
function declaration. You could explicitly use the implicit pointer types that the C
code produces 'under the hood':
function FindCityCounty(aZip: PANSIChar;
aCity: PCityName;
aState: PState;
aCounty: PCountyName;
aCountyNum: PCountyNum): Integer; cdecl;
Or you could use the array types themselves, but declare them as var parameters to co-erce the Pascal compiler to pass them by reference, thus producing implied pointers, as per the C
code:
function FindCityCounty(aZip: PANSIChar;
var aCity: TCityName;
var aState: TState;
var aCounty: TCountyName;
var aCountyNum: TCountyNum): Integer; cdecl;
The effect is essentially the same in both cases, though personally I would favour the explicit pointers since the use of var parameters overtly suggests that the parameter values may/will be modified by the function call which is almost certainly not the case.
Note that the zip parameter is already being passed explicitly as a pointer to a char in the C
code, so using the PANSIChar pointer type here is appropriate for this parameter in either case.
Upvotes: 5
Reputation: 84550
If this was a struct, you would be correct. But in C, arrays as function parameters are always pointers. According to this tutorial, this is still the case even in an array parameter with an explicit size given. So this should be translated as PChar
or PAnsiChar
, as appropriate.
Upvotes: 2