tags:

views:

186

answers:

3

I have an external function like this:

extern "C" __declspec(dllexport) int __cdecl Identify(BSTR* bstrTemplates, __int64 lCount, __int64* lIndex, __int64* lRetCode) 

The bstrTemplates should be a string array.

How should my function look like in D7, and how to pass a string array to the external function. Can't get my head around right now.

+1  A: 

BSTR* is a pointer to a BSTR (in Delphi BSTR is a WideString).

EDIT: To make the answer complete (and make Rob Kennedy happy :-) ):

Most literal translation:

function Identify(bstrTemplates: PWideString; lCount: int64; lIndex: PInt64; lRetCode: PInt64): Integer; cdecl external 'mydll.dll';

or more the Delphi way:

function Identify(bstrTemplates: PWideString; lCount: int64; var lIndex: Int64; var lRetCode: Int64): Integer; cdecl external 'mydll.dll';

or even (but this depends if the bstrTemplates can be nil):

function Identify(var bstrTemplates: WideString; lCount: int64; var lIndex: Int64; var lRetCode: Int64): Integer; cdecl external 'mydll.dll';

Use the first element in the array when you pass bstrTemplates (eg @MyArray[0])

Remko
Your answer is a bit confusing. BSTR is a WideString in Delphi. A pointer to a BSTR is not the same as a WideString. I think that's what you intended to say, but it doesn't read like that, at least not to me. "Which" here points to "the thing that is being talked about", which is "a pointer to a BSTR". A pointer to a BSTR is basically the same as a pointer to the first BSTR in a sequence. I'm guessing that the array is null-terminated.
Lasse V. Karlsen
@Lasse: Yes I intended to say that BSTR is a WideString in Delphi (I changed the text a little to make this clear, thanks)
Remko
-1. What you've said is true. But so what?
Rob Kennedy
The rest of the parameters did not seem to be part of the question.
Remko
Thank you, Remko.
Rob Kennedy
+3  A: 

A BSTR is a WideString in Delphi, and a pointer to a BSTR is also a pointer to a WideString in Delphi, but in terms of C-code, it is most likely an array reference. A typical way to handle such arrays, and I'm going to assume this is how it's done here, is to use a null-terminated array.

So, we need to declare an array of WideString's in Delphi, and leave the last element as null, or nil in Delphi:

var
  templates : array of WideString;
begin
  SetLength(templates, 3); // 2 template names + 1 nil
  templates[0] := 'template1';
  templates[1] := 'template2';
  templates[2] := nil;

  Identify(@templates[0], ....); // pass it as a pointer to the first element

I'm not guaranteeing this will work. I'm guessing here, and haven't tried it (which would involve creating a C project and testing) so this might fail horribly. Worth a shot though.

Lasse V. Karlsen
Yes for a dynamic array always pass a pointer to the first element and since you can also do this for static arrays it's a safe practice for passing arrays to c(++) dll's (+1)
Remko
Ok. Makes sense at the first sight. But there a two quirks. Assigning nil to the templates[2] doesn't work. The compiler tells me that WideString and Pointer are incompatible types. So setting length to 3 and leaving templates[2] as it is gives me an access violation if i pass the array to the function.
pantarhei
You cannot assign nil to a WideString (but you can assign empty string '') but I think the lCount parameter might indicate the number of elements in the array? So in this sample you do SetLength(.., 2) as well.
Remko
If you get an access violation, then there's something else you're doing wrong. This code alone won't crash.
Rob Kennedy
It's possible that if the user crashes they have coded their external import for Indentify() incorrectly.
Warren P
Yes. Looks like it was my problem. One of the other parameters was declared as Cardinal by me in Delphi. But the API changed from long to Int64. Saw it a bit late. The call to the DLL is working now. But it looks like the passed strings aren't recognized. They should be matched by an external device. But if there's a match for sure the function tells me there's no match. Looks like there's still some kind of issue reading the strings from the database and pass them to the dll.
pantarhei
A: 

Finally solved the problem. It was the dynamic array. Looks like it can't be used as C-style array. Looks like the length prefix confused the c dll. For the records here the prototype and usage:

Type

type
  TArrayOfWideString= array[0..999] of WideString;

Declaration

function Identify(var ATemplates: TArrayOfWideString; ATemplatesCount: int64; var ATemplateIndex: int64; var ARetCode: int64): Integer; cdecl; external 'Identify.dll';

Usage

var
  templateIndex, retCode: int64;
  templates: TArrayOfWideString;
  retval: integer;

//TODO: range checking for TArrayOfWideString needed

templates[0] := 'template1';
templates[1] := 'template2';

retVal := Identify(templates, 2, scanIndex, retCode);
pantarhei