Converting C functions in Delphi 10 Seattle - c

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.

Related

Calling a DLL function with an allocated character buffer that the function fills in Inno Setup

I am using (Unicode) Inno Setup 6.0.5 on Windows 10 64-bit.
The exported symbol, I want to use has the signature:
typedef int(__stdcall *GetDirVST2x86) (LPWSTR lpString1);
The Inno Setup [Code] section has its declaration as:
function GetDirVST2x86(var lpString1: String): Integer;
external 'GetDirVST2x86#files:R2RINNO.DLL stdcall setuponly';
where, lpString1 will contain a pointer to the wide-string after the function returns and R2RINNO.DLL is a 32-bit DLL.
Now my problem is, if I compile and run this setup, a read access violation occurs right when I try to retrieve the value. I get the correct result when I execute this same function from a C program. Removing the var from the prototype declaration in Inno script fetches an empty (or possibly) empty or blank string, so that doesn't help either.
I don't have the source for the DLL I wish to use, and I figured out the signature from IDA. The scripting engine Inno Setup seems hopelessly inadequate as it doesn't support pointers at all.
One interesting thing I observed was if I changed the type of lpString1 to Cardinal or Integer and used IntToStr to fetch the string I got the value of the directory in which the setup was getting created.
Here's a working C code:
#include <windows.h>
#include <stdio.h>
#define _UNICODE
#define UNICODE
typedef int(WINAPI *GetDirVST2x86) (LPWSTR );
int main() {
HMODULE hModule = LoadLibrary("R2RINNO.DLL");
if (NULL != hModule) {
GetDirVST2x86 pGetDirVST2x86 = (GetDirVST2x86) GetProcAddress (hModule, "GetDirVST2x86");
if (NULL != pGetDirVST2x86) {
LPWSTR lpszVST2x86;
pGetDirVST2x86(lpszVST2x86);
wprintf(lpszVST2x86);
}
FreeLibrary(hModule);
}
}
Here's the output:
C:\Program Files (x86)\Steinberg\VstPlugins
Here's the IDA screenshot of the function I want to use:
Pascal Script equivalent of the C declaration should be:
function GetDirVST2x86(lpString1: string): Integer;
external 'GetDirVST2x86#files:R2RINNO.DLL stdcall setuponly';
(i.e. no var, as it is an input character pointer argument).
Assuming the function contract is that you (as a caller) allocate a buffer and provide it to the function to be filled in, you should call the function like this:
var
Buf: string;
begin
{ Allocate buffer for the result large enough according to the API specification }
SetLength(Buf, 1000);
GetDirVST2x86(Buf);
SetLength(Result, Pos(#0, Result) - 1);
end;
See also How to return a string from a DLL to Inno Setup?

how convert this C function pointer to a delphi function

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');

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?

Convert C Code to Delphi

I need to convert this Line from C to Delphi.
Int CALLBACK EXPORT EXAMPLEFUNCTION(VOID){
SETEVENT(hasync);
Return Success;
}
Please i need some help.
thanks ;)
Kind of guessing here, because the style's really messy, but I think that would translate something like this:
const Success = 1; //or whatever; might not be 1.
//assume a const definition for a value
//called Success exists somewhere in scope
function EXAMPLEFUNCTION(): integer; stdcall; //CALLBACK = stdcall calling convention
begin
SETEVENT(hasync); //hopefully this makes sense in context
result := Success;
end;
That's the best I can do without further context. The EXPORT declaration is a preprocessor macro, and it (probably) means that this is part of a DLL and that this is a function that's supposed to be callable by programs that load the DLL. In Delphi, that's not part of the function definition; instead, you put it in an exports clause.

using a delphi callback function in a C dll

I'm using a C dll in a Delphi XE2 program without problem. One of the DLL function takes a function as argument.
Here is the prototype of the function:
var
LMX_MySetOption: function(LmxHandle: LMX_HANDLE;
eOption: _LMX_SETTINGS;
callback: TCallBackProcedure): LMX_STATUS cdecl
{$IFDEF WIN32} stdcall {$ENDIF};
The original prototype in C of the function was:
LMX_STATUS LMX_SetOption(LMX_HANDLE LmxHandle, LMX_SETTINGS eOption,
const void *pSetting);
TCallBackProcedure is defined as follow:
type
TCallBackProcedure = procedure(bla : Pointer) stdcall;
I'm calling the function this way:
LMX_MySetOption(LmxHandle, LMX_OPT_HEARTBEAT_EXIT_FUNCTION, UserExitRoutine);
The UserExitRoutine is definede as follow:
procedure UserExitRoutine(bla : Pointer) stdcall;
begin
...
end;
It's not working (access violation)
I can't modify the C dll.
Many thanks for any idea!
If is a C procedure don't use stdcall use cdecl .
And you can simply declare this
function LMX_MySetOption(LmxHandle: LMX_HANDLE;
eOption: _LMX_SETTINGS;
callback: Pointer): LMX_STATUS;cdecl;external 'yourmodule.dll';
procedure callback(bla:Pointer);cdecl;
begin
//Some code
end;
LMX_MySetOption(LmxHandle, LMX_OPT_HEARTBEAT_EXIT_FUNCTION, #callback);
It should work...if it doesn't maybe you don't know the exact nr of parameters that the function has...

Resources