I'm trying to call a function in a dll on a WinCE system.
this are the defines
type
TPREVIEW_CALLBACK = procedure ( pData: PByte; len: long; height: Integer; width: Integer; stride: Integer) of object; cdecl;
PPREVIEW_CALLBACK = ^TPREVIEW_CALLBACK;
function camRegisterPreviewCallback(PreviewCallbackProc: PPREVIEW_CALLBACK): Integer; cdecl; external 'CameraAPI.dll';
I made all functions global, this is the callback (still empty)
procedure PreviewCallback(pData: PByte; len: long; height: Integer; width: Integer; stride: Integer);
begin
end;
The call (also in a global function) is
CamRegisterPreviewCallback(PreviewCallback);
The error during compilation I get is
Error: Wrong number of parameters specified for call to "PreviewCallback"
As far as I understand it the parameter is a pointer so I don't understand what I'm doing wrong.
Can anyone help me on this?
Thanks in advance
Herman
When you write using the FPC dialect ({$MODE OBJFPC}) a function pointer must be explicitly specified using the # symbol.
Without this the compiler thinks that you want to call the function rather than to take its address.
So rewrite the last line as
CamRegisterPreviewCallback(#PreviewCallback);
By the way, as noted by someone in a comment, verify well your TPREVIEW_CALLBACK prototype. You declare its as of object but you implement it as a global function, which is an error. of object really means that the method has to be implemented in an class. The procedural variable of an object method is not the same as a procedural variable of a free function. In the first case there is an additional context pointer (the Self), so both are totally incompatible !
If the dll is written in C it's very likely that the of object is superfluous, but unfortunatly it's hard to say without the library API documentation.
Related
I'm trying to create a type to store color hexes preferably in byte form. I followed all the instructions in postgres docs here: http://www.postgresql.org/docs/9.3/static/sql-createtype.html
and found the part where it says CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ; a bit... unsettling. What goes in the ellipses? Turns out that was justified as I cannot find any example of creating a simple data type without custom PG functions written in C.
My best attempt was this:
CREATE TYPE color;
CREATE FUNCTION color_in(cstring) RETURNS color AS $$
BEGIN
RETURN decode($1::text, 'hex')::color;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE RETURNS NULL ON NULL INPUT;
CREATE FUNCTION color_out(color) RETURNS cstring AS $$
BEGIN
RETURN encode($1::bytea, 'hex')::text;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE RETURNS NULL ON NULL INPUT;
CREATE TYPE color (
INTERNALLENGTH = 3,
LIKE = bytea,
INPUT = color_in,
OUTPUT = color_out
);
This yields the error:
NOTICE: return type color is only a shell
ERROR: PL/pgSQL functions cannot return type color
Similar error if I use Language SQL or default to SPL.
The example in-out functions are listed here: http://www.postgresql.org/docs/9.3/static/xtypes.html. The only example functions are written in C. Am I correct in assuming this is the only way to write a UDT in postgres? Is there another way? My goal is to have the colors stored as bytes but have their native text form be hexadecimal (for the purposes of dumping, restoring, and casting from raw).
From http://www.postgresql.org/docs/9.4/interactive/datatype-pseudo.html
Functions coded in procedural languages can use pseudo-types only as
allowed by their implementation languages. At present the procedural
languages all forbid use of a pseudo-type as argument type, and allow
only void and record as a result type (plus trigger when the function
is used as a trigger). Some also support polymorphic functions using
the types anyelement, anyarray, anynonarray, anyenum, and anyrange.
And from the docs for create type
http://www.postgresql.org/docs/9.4/interactive/sql-createtype.html
The input function can be declared as taking one argument of type
cstring, or as taking three arguments of types cstring, oid, integer.
The output function must return type cstring.
Given the above:
Base data type input and output functions use cstring.
Procedural languages can not use cstring.
Base data type functions can't be written in procedural language.
Defining a base data type can't be done purely in procedural languages.
You can use pre-existing input and output functions, but I don't think
that any of them will directly get you a hex string. The closest
is probably the \x hex escaped bytea, but you'd have a \x at the beginning of your text representation. If you're willing to cast to and from text, I think you could create a type using bytea_in and bytea_out and writing custom casts to and from text. You'd have to explicitly cast to avoid the \x though.
For some reason, passing a string from Python into a Postgres function and calling it using a psycopg2 cursor causes the function to be unrecognized because the argument is unknown.
The function is very simple like so:
CREATE OR REPLACE FUNCTION text_test (some_text text)
RETURNS void AS $$
BEGIN
END;
$$ LANGUAGE plpgsql;
On the python side, I have:
cursor.callproc("text_test", ("test",))
And I get the following error:
psycopg2.ProgrammingError: function text_test(unknown) does not exist
LINE 1: SELECT * FROM text_test('test')
^
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Why does this only happen with strings and what do I need to do to have a function successfully accept a string? For some reason numeric data types are unaffected by this problem.
This happens because there is no way to cast the string to the "correct" text type. Is it a char(N)? A varchar(N)? A text?
Unfortunately .callproc() doesn't provide an easy way to specify the argument types but you can always use .execute() casting the arguments explicitly and everything works:
curs.execute("SELECT * FROM text_test(%s::text)", ("test",))
You could also make a list with the parameters you need to send:
param_list = ["test"]
curs.callproc(proc_name, param_list)
Here is a good answer about it:
python + psycopg2 = unknown types?
I am trying to use a .dll which has been written in C (although it wraps around a matlab .ddl)
The function I am trying to use is defined in C as:
__declspec(dllexport) int ss_scaling_subtraction(double* time, double** signals, double* amplitudes, int nSamples, int nChannels, double* intensities);
The .dll requires, amongst others, a 2 dimensional array - When I tried to use:
Array of array of double
In the declaration, the compiler gave an error so I defined my own data type:
T2DArray = Array of array of double;
I initialise the .dll function in a unit like so:
function ss_scaling_subtraction(const time: array of double; const signals: T2DArray; const amplituides : array of double; const nSamples: integer;const nChannels: integer; var intensities: array of double) : integer ; cdecl; external 'StirScanDLL.dll';
However, when called this function, I get an access violation from the .dll
Creating a new data type
T1DArray = array of double
and changing
Array of double
To
T1DArray
In the declaration seems to make things run but the result is still not correct.
I have read on here that it can be dangerous to pass delphi data types to .dll's coded in a different language so I thought this might be causing the issue.
But how do I NOT use a delphi data type when I HAVE to use it to properly declare the function in the first place?!
Extra Info, I have already opened the matlab runtime complier lib's and opened the entry point to the StirScanDLL.dll
The basic problem here is one of binary interop mismatch. Simply put, a pointer to an array is not the same thing at a binary level as a Delphi open array parameter. Whilst they both semantically represent an array, the binary representation differs.
The C function is declared as follows:
__declspec(dllexport) int ss_scaling_subtraction(
double* time,
double** signals,
double* amplitudes,
int nSamples,
int nChannels,
double* intensities
);
Declare your function like so in Delphi:
function ss_scaling_subtraction(
time: PDouble;
signals: PPDouble;
amplitudes: PDouble;
nSamples: Integer;
nChannels: Integer;
intensities: PDouble
): Integer; cdecl; external 'StirScanDLL.dll';
If you find that PPDouble is not declared, define it thus:
type
PPDouble = ^PDouble;
That is, pointer to pointer to double.
Now what remains is to call the functions. Declare your arrays in Delphi as dynamic arrays. Like this:
var
time, amplitudes, intensities: TArray<Double>;
signals: TArray<TArray<Double>>;
If you have an older pre-generics Delphi then declare some types:
type
TDoubleArray = array of Double;
T2DDoubleArray = array of TDoubleArray;
Then declare the variables with the appropriate types.
Next you need to allocate the arrays, and populate any that have data passing from caller to callee.
SetLength(time, nSamples); // I'm guessing here as to the length
SetLength(signals, nSamples, nChannels); // again, guessing
Finally it is time to call the function. Now it turns out that the good designers of Delphi arranged for dynamic arrays to be stored as pointers to the first element. That means that they are a simple cast away from being used as parameters.
retval := ss_scaling_subtraction(
PDouble(time),
PPDouble(signals),
PDouble(amplitudes),
nSamples,
nChannels,
PDouble(intensities)
);
Note that the casting of the dynamic arrays seen here does rely on an implementation detail. So, some people might argue that it would be better to use, for instance #time[0] and so on for the one dimensional arrays. And to create an array of PDouble for the amplitudes and copy over the addresses of the first elements of the inner arrays. Personally I am comfortable with relying on this implementation detail. It certainly makes the coding a lot simpler.
One final piece of advice. Interop can be tricky. It's easy to get wrong. When you get it wrong, the code compiles, but then dies horribly at runtime. With cryptic error messages. Leading to much head scratching.
So, start with the simplest possible interface. A function that receives scalar parameters. Say, receives an integer, and returns an integer. Prove that you can do that. Then move on to floating point scalars. Then one dimensional arrays. Finally two dimensional arrays. Each step along the way, build up the complexity. When you hit a problem you'll know that it is down to the most recently added parameter.
You've not taken that approach. You've gone straight for the kill and implemented everything in your first attempt. And when it fails, you've no idea where to look. Break a problem into small pieces, and build the more complex problem out of those smaller pieces.
I would like to declare an array of pointer with an initialization
Apb : array [0..2] of pointer to bool := adr(r0), adr(r1), adr(r2);
Where r0, r1, r2 are declared in Modbus like Bitwise holding register.
I got an error: Wrong initial value.
In case:
Apb : array [0..2] of pointer to bool;
Apb[0]^ := r0;
Everything works as I want.
I think that POU variable declarations do not want function calls in them or even variables assigned to other variables.
The only way to have variables in your declaration is to use VAR_CONSTANTs. You will still have to do some legwork, but it can make larger-scale substitutions easier to manage.
There is also a way to use dynamic values using pragmas (I never really use pragmas although, so Im not certain of how powerful it is).
Coming from more standard programming languages, this one has similar rules and constructs as C, but not nearly as much flexibility, dreadful syntax, and nothing even resembling 'void' types. I ended up using python templates to help generate POU variable declaration headers because the allowed syntax is quite strict, leading to excessively verbose declarations.
I'm trying to call a simple Matlab routine, from a Delphi XE 32bit application, which I have compiled into a shared C libray called Test.dll using the Matlab 2012b compiler.
The routine increments a number and returns the new value.
As I understand from the matlab documentation I first need to call mclInitializeApplication.
I've mapped this dll call as follows:
unit mclmcrWrapper;
interface
type
TAnsiArray = TArray<AnsiString>;
PAnsiArray = ^TAnsiArray;
function mclInitializeApplication(A: PAnsiArray; B: Integer): Boolean; cdecl; external 'mclmcr.dll' name '_mclInitializeApplication';
// Also tried, with same result:
// All attempts made with and without underscore give the same results.
// function mclInitializeApplication(A: PAnsiArray; B: Integer): Boolean; cdecl; external 'mclmcr.dll' name '_mclInitializeApplication';
// function mclInitializeApplication(A: THandle; B: Integer): Boolean; cdecl; external 'mclmcr.dll' name '_mclInitializeApplication';
implementation
initialization
mclInitializeApplication(nil, 0); //Initialize the matlab runtime
end.
According to ddlDepends the function is present in the dll.
When I execute my program I get the following error message:
---------------------------
MatlabTest.exe - Entry Point Not Found
---------------------------
The procedure entry point _mclInitializeApplication could not be located in the dynamic link library mclmcr.dll.
---------------------------
OK
---------------------------
All dll's are present in the same folder. If they are not I get an error that the dll itself cannot be found.
In itself this is also strange as the Matlab compiled runtime is installed on my system, and it is added to the windows path correctly.
Can anyone tell me what I'm doing wrong?
Thanks in advance.
So far as I know, that function is actually defined in mclbase.dll.
Once you resolve the linking, I suggest that you change the parameter list for your imported function. It's risky to pass Delphi managed types to a non-Delphi module. I would declare it like this:
type
PPAnsiChar = ^PAnsiChar;
function mclInitializeApplication(A: PPAnsiChar; B: Integer): Boolean; cdecl;
external 'mclbase.dll';
It turns out I had a couple of things to fix:
Install the MCR correctly.
Pass a PPAnsiChar instead of an array
Call "_proxy" functions in mclmcrrt8_0.dll, instead of the normal functions in the other dll files.
The method declaration is now as follows:
function DLLInit(A: PPAnsiChar; B: integer): Boolean; cdecl;
external 'mclmcrrt8_0.dll' name 'mclInitializeApplication_proxy';
in the unit I added the following code (yes, I'm not passing any parameters):
initialization
if not DLLInit(#MyString, 0) then
raise Exception.Create('Could not initialize Matlab library.');
I also made sure that this unit is the first to be loaded in the project, as the mclInitializeApplication needs to be called once and before all other matlab calls.