how convert this C function pointer to a delphi function - c

There is a third-party C DLL, with Delphi 2007 development program (novice level), in the DLL header file, the function structure is more complex, there is a big god can give some ideas? C header file definition:
typedef int (*SetValueFunc)(const char* path, const char* value);
typedef const char* (*GetValueFunc)(const char* path);
typedef const ConfigNode* (*GetPropertysFunc)();
typedef struct tagIProperty
{
SetValueFunc SetValue;
GetValueFunc GetValue;
GetPropertysFunc GetPropertys;
}IProperty;
Call in C:
property->SetValue("0/baud_rate", "1000000")
I would be grateful if someone gave some advice.

Try something like this:
type
ConfigNode = record
...
end;
PConfigNode = ^ConfigNode;
SetValueFunc = function(const path, value: PAnsiChar): Integer; cdecl;
GetValueFunc = function(const path: PAnsiChar): PAnsiChar; cdecl;
GetPropertysFunc = function: PConfigNode; cdecl;
tagIProperty = record
SetValue: SetValueFunc;
GetValue: GetValueFunc;
GetPropertys: GetPropertysFunc;
end;
IProperty = tagIProperty;
var
property: ^IProperty;
...
property := ...;
...
property.SetValue('0/baud_rate', '1000000');

Related

Trouble Including Externally Declared Enumeration - C Code

Update: The issue is resolved. Here is code that compiles properly.
---instruction.h---
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
typedef enum OPCODE {ADD = 0x20,ADDI = 0x8,SUB = 0x22,MULT = 0x18,BEQ = 0x4,LW = 0x23,SW = 0x2B} opcode;
/*opcode is OPCODEs alias*/
typedef struct INSTRUCTION {
opcode op;
int rs;
int rt;
int rd;
int Imm;
} inst;
/*inst is INSTRUCTIONs alias*/
#endif // INSTRUCTION_H
---parser.c---
#include <stdio.h>
#include "instruction.h"
void parser(char *instruction)
{
/*Parse character string into instruction components*/
inst set1 = {LW,0,1,2,0};
printf("parsing");
};
int main()
{
char *instruction;
instruction = NULL;
parser(instruction);
};
/*pass in pointer for instruction being passed in*/
/*pointing to address of instruction being passed in*/
/*Parser return type is struct inst*/
I cannot seem to get my enumeration type "opcode" to be recognized in my main c file. I included the header file. I am fairly new to C, so haven't made much ground on the issue for some time now and wanted to see if anyone knew why I was getting the error messages below. My guess is the linking the header file is not working properly. Any help is much appreciated.
---instruction.h----
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
typedef enum {add = 32,addi = 8,sub = 34,mult = 24,beq = 4,lw = 35,sw = 43}opcode;
extern opcode oper;
typedef struct {
opcode op;
int rs;
int rt;
int rd;
int Imm;
}inst;
#endif // INSTRUCTION_H
---Parser.c---
#include <stdio.h>
#include "instruction.h"
void parser(char *inst)
{
/*Parse character string into instruction components*/
struct inst{lw,0,1,2,0};
};
int main()
{
char *instruction;
instruction = NULL;
parser(instruction);
};
struct inst{lw,0,1,2,0};
This looks like it's supposed to be a variable declaration, but I don't see a name for the variable. Try:
struct inst name_of_the_variable = {lw,0,1,2,0};
As a side note, enum values are global constants, so it's probably not a good idea to give them names like lw that can be confused for variables. Standard practice would be to use all-caps for the names and give them a prefix… say, OPCODE_ADD, OPCODE_LW, etc.
This is not a valid variable definition:
struct inst{lw,0,1,2,0};
There's no struct inst defined, only inst, there's no variable name, and you need = to use an initializer. To create a variable of this type an initialize it, you need:
inst myinst = {lw,0,1,2,0};
Also, your function has a parameter named inst which masks the type inst. You need to give it a different name:
void parser(char *instruction)

Converting C dll header to delphi: char*

I'm using an NIDAQmx DLL in a Delphi XE4 app. The DLL only has an ANSI C header file.
I'm trying to convert this function:
int32 __CFUNC DAQmxGetPhysicalChanName(TaskHandle taskHandle,
const char channel[], char *data, uInt32 bufferSize);
This is my translation:
function DAQmxGetPhysicalChanName(taskHandle: TTaskHandle;
chanName: PAnsiChar; chanPhysName: PAnsiChar;
bufferSize: DWORD): Integer; stdcall; external NI_DLL_NAME delayed;
When I call it like this:
var
s1,s2: String[200];
sp: PAnsiChar;
begin
// sp:=#s2[1]; When I uncomment this, fucntion works as
// expected, otherwice return string s2 is empty!
res:=DAQmxGetPhysicalChanName(taskHandle,#s1[1],#s2[1],200);
The function works only when I insert sp:=#s2[1] before the call. I never actually use the sp pointer, but just the fact that it get assigned helps. Without that, the s2 string is empty. I cant understand why. What am I doing wrong?

Converting C functions in Delphi 10 Seattle

I'm trying to convert API SendAnywhere header file from C to Delphi 10 code for Windows.
Using presented table of Embarcadero I successfully convert some of the functions:
typedef void* PaprikaTask;
typedef void* PaprikaAuthToken;
__declspec(dllexport) void paprika_set_apikey(const char* key);
__declspec(dllexport) PaprikaAuthToken paprika_auth_create();
__declspec(dllexport) PaprikaAuthToken paprika_auth_create_with_deviceid(const char* id, const char* password);
__declspec(dllexport) void paprika_auth_close(PaprikaAuthToken auth);
__declspec(dllexport) bool paprika_is_running(PaprikaTask task);
__declspec(dllexport) PaprikaTask paprika_create_download(const wchar_t* key, const wchar_t* destDirPath);
__declspec(dllexport) void paprika_start(PaprikaTask task);
This is my conversion:
PaprikaAuthToken = Pointer;
PaprikaTask = Pointer;
procedure paprika_set_apikey(const key: PChar); cdecl; external 'sendanywhere.dll';
function paprika_auth_create: PaprikaAuthToken; cdecl; external 'sendanywhere.dll';
function paprika_auth_create_with_deviceid(const id: PAnsiChar; const password: PAnsiChar): PaprikaAuthToken; cdecl; external 'sendanywhere.dll';
procedure paprika_auth_close(auth: PaprikaAuthToken); cdecl; external 'sendanywhere.dll';
function paprika_is_running(task: PaprikaTask): Boolean; cdecl; external 'sendanywhere.dll';
function paprika_create_download(const key: PWideChar; const destDirPath: PWideChar): PaprikaTask; cdecl; external 'sendanywhere.dll';
procedure paprika_start(task: PaprikaTask); cdecl; external 'sendanywhere.dll';
Example from SendAnywhere uses these functions as follows:
PaprikaTask pTask;
PaprikaAuthToken gToken;
paprika_set_apikey("YOUR_API_KEY");
gToken = paprika_auth_create();
pTask = paprika_create_download(L"KEY", L"/tmp");
paprika_set_auth(pTask, gToken);
paprika_start(pTask);
This is how I interpreted the proper code:
var
FAuthToken: PaprikaAuthToken;
FOption: PaprikaOption;
paprika_set_apikey(PChar('my_correct_api_key'));
FAuthToken = paprika_auth_create();
// backslash for windows
FTask := paprika_create_download(PWideChar('correct_key'), PWideChar('\tmp')); //directory exists
paprika_set_auth(FTask, FAuthToken);
paprika_start(FTask);
I checked the work of the task by function paprika_is_running. It returns FALSE before calling paprika_start_function. It begins to return TRUE after calling paprika_start_function but after 1-2 seconds (regardless of the size of the transferring file) it returns FALSE.
This means that the function is working, but it seems that the problem is in the arguments.
Please tell me where I am going wrong?
Maybe there is an incorrect conversion from string to TWideChar.
Or the path of the directory is passed incorrectly, for example and used an incorrect slash. I've tried different paths:
('C:/', 'C:\', 'C:', 'file://C:', 'file://C:/', '/', '\', '')
What is incorrect? Help please. I need your assistance.
procedure paprika_set_apikey(const key: PChar); cdecl; external 'sendanywhere.dll';
This is wrong. PChar is an alias to PWideChar. The type should be PAnsiChar.
As an aside you don't need the PAnsiChar or PWideChar casts when passing literals. Remove them to simplify the code.
Further, your use of const in parameters has a different meaning from that in the C++ code, and is in any case meaningless in an external declaration. I personally would remove those modifiers and pass the pointers as plain value params.

Pass double array by reference from C to Delphi DLL

For our Delphi (XE5) application we are developing an API. In order to communicate data from the Delphi DLL functions with the main program (C based; either (console) C or C++ code applications or Matlab and Simulink) arrays that are allocated by the caller need to be filled with doubles by the DLL.
I understand that open array (Delphi specific) are not very convenient for this purpose as they contain additional data that you then have to mimic in C. Instead I was planning to use pointer arithmetic (see dll function: inc(APDouble)) by directly pointing to the correct address. My question is if this is how you software developers would do this.
A demo is included below (full sources).
The DLL (made in DXE5):
library PDA;
uses
System.StrUtils,
System.SysUtils,
Vcl.Dialogs;
{$R *.res}
function ShowArrayContents( APDouble: PDouble;
size: Integer): integer; cdecl; export;
var
i: Integer;
begin
Result := 0;
for i := 0 to size-1 do
begin
// Show value!
MessageDlg(Format('%p -> %p -> %f', [#APDouble, APDouble, APDouble^]), mtWarning, [mbOK], 0);
Inc(APDouble);
end;
end;
exports
ShowArrayContents;
begin
end.
The C-code caller (made in C++ builder XE4):
#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include <windows.h>
typedef int (*_ShowArrayContents) (double *, int);
char *dllname = "PDA.dll";
static HINSTANCE hInstanceControl;
_ShowArrayContents ShowArrayContents = NULL;
int _tmain(int argc, _TCHAR* argv[])
{
double DVals[3] = {1.23, 4.56, 7.89};
int i;
hInstanceControl = LoadLibrary(dllname);
if( hInstanceControl != NULL){
ShowArrayContents =(_ShowArrayContents)GetProcAddress(hInstanceControl, "ShowArrayContents");
} else {
return 0;
}
// test program:
(*ShowArrayContents)(&DVals[0], 3);
FreeLibrary(hInstanceControl);
system("pause");
return 0;
}
Your code works fine, but as you observe it is awkward. For interop like this I would bite the bullet and use the $POINTERMATH directive. This allows you to treat a pointer as if it were an array, just as you do in C or C++. For example:
{$POINTERMATH ON}
function GetSum(arr: PDouble; len: Integer): Double; cdecl;
var
i: Integer;
begin
Result := 0.0;
for i := 0 to len-1 do
Result := Result + arr[i];
end;
Another option would be to copy to a native Delphi array and use that for onward processing. Obviously that involves a copy, but sometimes that's actually what you want. In that case you could do it like this:
var
x: TArray<Double>;
....
SetLength(x, len);
Move(arr^, Pointer(x)^, len*SizeOf(arr^));
Or if you don't like the use of Move, a good old loop:
{$POINTERMATH ON}
var
i: Integer;
x: TArray<Double>;
....
SetLength(x, len);
for i := 0 to len-1 do
x[i] := arr[i];

C dll header on Delphi

I want to loadd a function from "x.dll",and I have this definition of the function(.h file):
uint32 BioAPI_ModuleAttach(
const BioAPI_UUID *ModuleGuid,
const BioAPI_VERSION *Version,
const BioAPI_MEMORY_FUNCS *MemoryFuncs,
uint32 DeviceID,
uint32 Reserved1,
uint32 Reserved2,
uint32 Reserved3,
BioAPI_FUNC_NAME_ADDR *FunctionTable,
uint32 NumFunctionTable,
const void *Reserved4,
BioAPI_HANDLE_PTR NewModuleHandle);
typedef uint32 BioAPI_HANDLE, *BioAPI_HANDLE_PTR;
But, I only to pass the last parameter and the others I want to pass 0 (null)... How can I implement? There is any way to do automatic with de .lib?
I tried, but I implemented in wrong way.. :\
function BioAPI_ModuleAttach(
ModuleGuid: array of Byte;
Version: HWND;
MemoryFuncs: HWND;
DeviceID: UInt32;
Reserved1: UInt32;
Reserved2: UInt32;
Reserved3: UInt32;
FunctionTable: HWND;
NumFunctionTable: UInt32;
Reserved4: Pointer;
NewModuleHandle: PINT) : UInt32; cdecl; external 'PvFw.dll';
Thanks, for attention.
Looking at the sources, I would convert that like this:
const
BioAPI_MAX_STR_LEN = 255;
type
BioAPI_RETURN = UInt32;
BioAPI_VERSION_PTR = ^BioAPI_VERSION;
BioAPI_VERSION = record
Major: UInt32;
Minor: UInt32;
end;
BioAPI_MALLOC = function(
Size: UInt32;
AllocRef: Pointer;
FileName: PAnsiChar;
Line: UInt32;
): Pointer stdcall;
// etc...
BioAPI_MEMORY_FUNCS_PTR = ^BioAPI_MEMORY_FUNCS;
BioAPI_MEMORY_FUNCS = record
Malloc_func: BioAPI_MALLOC;
Free_func: BioAPI_FREE;
Realloc_func: BioAPI_REALLOC;
Calloc_func: BioAPI_CALLOC;
AllocRef: Pointer;
end;
BioAPI_FUNC_NAME_ADDR_PTR = ^BioAPI_FUNC_NAME_ADDR;
BioAPI_FUNC_NAME_ADDR = record
Name: array[0..BioAPI_MAX_STR_LEN - 1] of AnsiChar;
Address: BioAPI_PROC_ADDR;
end;
// etc... I'll leave the rest for you. ;-)
function BioAPI_ModuleAttach(
ModuleGuid: PGUID;
Version: BioAPI_VERSION_PTR;
MemoryFuncs: BioAPI_MEMORY_FUNCS_PTR;
DeviceID,
Reserved1,
Reserved2,
Reserved3: UInt32;
FunctionTable: BioAPI_FUNC_NAME_ADDR_PTR;
NumFunctionTable: UInt32;
Reserved4: Pointer;
var NewModuleHandle: HMODULE): BioAPI_RETURN; stdcall;
Note that in Win32, BioAPI is #defined as __stdcall, so cdecl is definitely wrong. There is nothing that indicates that records must be packed. I would leave them at their natural alignment.
I think this could work:
function BioAPI_ModuleAttach(
ModuleGuid: PByte; // pass a pointer to the first array element
Version: PByte; // PByte probably is wrong here, look up the type!
MemoryFuncs: PByte; // Also probably wrong, what is BioAPI_MEMORY_FUNCS?
DeviceID: UInt32;
Reserved1: UInt32;
Reserved2: UInt32;
Reserved3: UInt32;
FunctionTable: PBYTE; // pass a pointer to a BioAPI_FUNC_NAME_ADDR
NumFunctionTable: UInt32; // that's probably the length of the above
Reserved4: Pointer;
NewModuleHandle: PUINT32) : UInt32; cdecl; external 'PvFw.dll';
Calling it like this should work, if all the parameters can be zero or NULL:
var
DeviceId: UInt32; // LongWord
Handle: UInt32; // LongWord;
begin
DeviceId := <something>
Handle := 0;
Res := BioAPI_ModuleAttach(nil, nil, nil, DeviceId, 0, 0, 0, nil, 0, nil, #Handle);
Of course this assumes a lot, since you did not provide any information about many of the pointer parameters. I have declared them as PByte, but that's probably wrong.
const
BioAPI_MAX_STR_LEN = 255;
BioAPI_OK = 0;
BioAPI_INVALID_HANDLE = 0;
type
BioAPI_UUID = packed array[0..15] of Byte; // or TGUID
BioAPI_UUID_PTR = ^BioAPI_UUID;
BioAPI_DEVICE_ID = UInt32;
BioAPI_VERSION = record
Major: UInt32;
Minor: UInt32;
end;
BioAPI_VERSION_PTR = ^BioAPI_VERSION;
BioAPI_MALLOC = function(Size: UInt32; Allocref: Pointer): Pointer; cdecl;
BioAPI_FREE = procedure(Memblock: Pointer; Allocref: Pointer); cdecl;
BioAPI_REALLOC = function(Memblock: Pointer; Size: UInt32; Allocref: Pointer): Pointer; cdecl;
BioAPI_CALLOC = function(Num: UInt32; Size: UInt32; Allocref: Pointer): Pointer; cdecl;
BioAPI_MEMORY_FUNCS = record
Malloc_func: BioAPI_MALLOC;
Free_func: BioAPI_FREE;
Realloc_func: BioAPI_REALLOC;
Calloc_func: BioAPI_CALLOC;
AllocRef: Pointer;
end;
BioAPI_MEMORY_FUNCS_PTR = ^BioAPI_MEMORY_FUNCS;
BioAPI_PROC_ADDR = function: UInt32; stdcall;
BioAPI_FUNC_NAME_ = record
Name: packed array[0..BioAPI_MAX_STR_LEN-1] of AnsiChar;
Address: BioAPI_PROC_ADDR;
end;
BioAPI_FUNC_NAME_ADDR = array[0..0] of BioAPI_FUNC_NAME_;
BioAPI_FUNC_NAME_ADDR_PTR = ^BioAPI_FUNC_NAME_ADDR;
BioAPI_HANDLE = UInt32;
BioAPI_HANDLE_PTR = ^BioAPI_HANDLE;
function BioAPI_ModuleAttach(
ModuleGuid: BioAPI_UUID_PTR;
Version: BioAPI_VERSION_PTR;
MemoryFuncs: BioAPI_MEMORY_FUNCS_PTR;
DeviceID: BioAPI_DEVICE_ID;
Reserved1: UInt32;
Reserved2: UInt32;
Reserved3: UInt32;
FunctionTable: BioAPI_FUNC_NAME_ADDR_PTR;
NumFunctionTable: UInt32;
Reserved4: Pointer;
var NewModuleHandle: BioAPI_HANDLE): UInt32; cdecl; external 'PvFw.dll';
procedure Test;
var
NewModuleHandle: BioAPI_HANDLE;
begin
if BioAPI_ModuleAttach(nil, nil, nil, 0, 0, 0, 0, nil, 0, nil, NewModuleHandle) = BioAPI_OK then
begin
if NewModuleHandle <> BioAPI_INVALID_HANDLE then
begin
// Success
end;
end;
end;
In case cdecl is not the correct convention replace with stdcall

Resources