Link to home
Create AccountLog in
Avatar of BrokenNoze2008
BrokenNoze2008

asked on

C++ Header conversation

I'm trying to import the following function into Delphi so I can use the MitelClient Dll from within my source.


Can load the Library however how do i define a c++ function such as

int SXInit(int,...)

In delphi to use? I'm unsure as to how the "..."  should be defined, is it an array of const?

Thanks.
Avatar of Zoppo
Zoppo
Flag of Germany image

Hi BrokenNoze2008,

the '...' declares a variable argument list - so the function can be called with one or more arguments. The first argument should give the function a hint how much arguments are passed and which type they have. Then the called function can evaluate the arguments.

A well known example for such a function is 'printf' - the number and types of arguments passed after the format-string depend on the placeholders defined in that format string.

I don't know if there's a similar featur in Delphi ...

Hope that helps,

ZOPPO
Avatar of BrokenNoze2008
BrokenNoze2008

ASKER

the Delphi equivilent is "array of " so I'm assuming this is something like:

function SXInit(a : array of integer): integer; cdecl external "MitelClient80"

However I get an Access violation at addresss 0000000 when it attempts to call the function as above.
Well, maybe you misunderstood - the variable argument list representated by '...' does not have to be a list of variable of a special type - for example in 'printf' you can mix any kind of nativ types (int, float, doulbe, char, pointers) within one function call, i.e.:

printf( "Value '%s' is %d", "dummy", -1 ); // printf is declared somehow like 'int printf( const char* pszFormat, ... );'

So, the "dummy" (pointer to char) differs from -1 (int) ... therfore IMO you can't say you can use an 'array of integers'.

ZOPPO
the Delphi equivilent is "array of "
no it's not.

array of  ... is single parameter/variable of type array while "..." means that you can suply multiple parameters.
Look at ReadLn() procedure it does not take one parameter of type array but it takes multiple parameters

ziolko.
understood,

in this case Delphi would normally use the "array of const" where the datatype in undefined. which again is not working.  the format function is the example i'd normally use.

However the question is how to convert the (int,...) into the correct calling convention so I can call the function from within Delphi. if anyone has a simple 1 line answer that work be me perfect. :)

Thaaks.
in this case Delphi would normally use the "array of const"
again answer is no.

if you declare function:

function Dummy(Args: array of const);

you can call it like this:
Dummy([2, 'a']); or like this Dummy([2, 'a', True]); but it still takes just one array parameter, as a matter of fact array of const is equivalent to: array of TVarRec which is nothing more that open array of records.

how to declare in delphi function with unknown number of paramteres?
I don't think it's possible.. at least I don't know how it can be done.


ziolko.
Sounds like a good one to ask the folks at CodeGear, let me see what they have to say.
Maybe you should post the code of 'SXInit' - it could be that it can be easily re-written without the need of a variable argument list ...
No, SXinit is within a dll hence my problem. I have no access to the DLL source code. it's a C dll written by Mitel to allow call control onto the Mitel 3300 PBX
ASKER CERTIFIED SOLUTION
Avatar of Lukasz Zielinski
Lukasz Zielinski
Flag of Poland image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
yes, i'm looking at something like that now, infact the way I'm trying to manage it is to write another C dll which parses some Delphi arguments in PChar format and then calls the SXInit with these. It's not a nice way of doing it. I also have  very little C++ experience so making the project all the more longwinded

Still looking for developmentguru's answer if he's able to get one from CodeGear?
try code that I posted, for answer from CodeGear you may wait a bit:)

ziolko.
lol. ok. I'll give it a go.
I got an answer from them, but it was not what was needed... Round 2.
Oh well, in the end all i've done is created a new C++ Dll which consumes the first and exposes the dll calls with only those arguments i need. Not the ideal solution by any means but it does at least allow me to continue with the project in the meantime.

Thanks for all your help and advice. New to Expert-Exchange and looks like it'll be worth the subscription!
New to Expert-Exchange and looks like it'll be worth the subscription!

yes it's worth subscription and it's worth to read this: https://www.experts-exchange.com/help.jsp#hi331 :)

ziolko.
:) Yes, however not sure the question to be answered.

 I still don't know if I'm able to call a DLL function with a variable length parameter list from within Delphi.

that said i will try your solution today ziolko and if it works you can have my points :)
don't get me wrong I didn't post link about closing Qs because I want points to go to my account not other experts but it happens that I also do cleanup here so I feel in duty to make sure that Qs are closed by askers:)

back to problem... I'm curious if my solution will work or not in theory it should but I've never tried that so I'd appreciate if you post what happened regardless of closing option you choose

ziolko.
It worked!!!!!

  const
    SX_LOG_DIR =                        2132;                        
type
  TSXInit = function(a : Integer;pstr : pChar;aend : Pointer): integer; stdcall;

...

procedure LoadDll;
var
  iRes: Integer;
  pSXInit : Pointer;
  Hbar  : Pointer;
begin
   Hbar := LoadLibrary('MitaiClient80.dll');
   if Hbar >= 32 then { success }
   begin
     
   // Had to use pChar(1) as the DLL apparently doesn't appear to have named procs so address it via    Ord
    pSXInit := GetProcAddress(HBar, pChar(1));

    // Nil ( C++ NULL) denotes to the dll the end of the param list. hence included here.
    iRes := TSXInit(pSXInit)(SX_LOG_DIR,'C:\\',nil);
   end;
end.

iRes = 0 which is what I'd hope for so all good.

Thanks for everyones help on this one. It's not the ultimate solution but it'll do me nicely.

Thanks ziolko, i'll close this one down for you :)
Thanks loads for your help
I will add this in even though the points were already assigned.  Read it from bottom to top since it is a copy of email responses on the question.

----------------------------------------------------------------------------------------------------

Brian,

Yes, it should work with your dll.

-Nate
----------------------------------------------------------------------------------------------------
This will work when the DLL was created in C/C++ and declared as I showed?

----------------------------------------------------------------------------------------------------

Brain,
         Yes, that clears things up. What you will need to do is to create a variant sized array of variant variables. This will allow for different amount of different types of variables to be received by the function. For more information on see your help file: ms-help://borland.bds5/devcommon/varianttypes_xml.html

-Nate

----------------------------------------------------------------------------------------------------

Nate,

  I want to pass an unknown parameter set (excluding the first parameter which is an integer) to a function and get an integer back.  I would then have a nearly infinite set of overloaded functions declarations to do?  Consider that it should be possible to pass any parameter type and limit it to, say, 30 parameters passed.  If the possible types were only string int and float you would have 3^29th (68,630,377,364,883) function declarations!  What I need to know is how Delphi can let me declare a function call like WriteLn that can take multiple parameters of a non-predetermined nature.  Does that clarify things?

----------------------------------------------------------------------------------------------------

Brian,
        I want to ensure that I am reading your question correctly. You want to be able to receive different types/amounts of parameters from a function in a dll. This can be done by marking the function with the overload directive. I forgot to mention in my previous e-mail that you will also need to include the stdcall directive to ensure you parameters are passed correctly. You mentioned that the .dlls were created in C++/C depending on which language these were created with they will have to be handled differently in Delphi. This is due to the fact that C++ will mangle the function names. This can be found out by using tdump on your dll from the bin directory commandline: " tdump -em somedll.dll" (without the quotes) this will tell you the public names of the functions. Once you know the public name you can declare it in Delphi with :
function SXInit (Num1, Num2: Integer): Integer; stdcall; overload; external 'somedll.dll' name '@SXInit$qqsii';

Note this would be for your third function. You can then create multiple functions with the same name of SXInit with the overload function directive. Let me know if this answers your question.

-Nate Sharp

----------------------------------------------------------------------------------------------------

Sorry, but this does not answer the question.  I need to know how to use Delphi to access a function in the dll when the function has a first parameter as an integer and an open set of parameters to follow.  This would allow you to call in any of these ways with the same function:

SXInit(1, 'Start', 0, 0, 1);
SXInit(1, 0, 0, 1);
SXInit(1, 1);
SXInit(1, 'Start', 'End', 0, 1, 12.3, 'A');

What I need to know is how to declare the function so Delphi can call it.  The function was created in C/C++ and has the ability to pass an open ended parameter list.  Delphi does this with several of it's functions, at the moment WriteLn comes to mind.  The C++ declaration of this function looks like this:

int SXInit(int,...)

Let me know if you need more.

----------------------------------------------------------------------------------------------------

Mr. Thomas,
       Thank you for contacting CodeGear technical support. This assumes you have a file called SomeDll.dll in your project path and you have a form with a button on it. You can call a dll in Delphi using the following code:
var
  Form1: TForm1;
   function SXInit(parameter1 : integer): Integer; external 'SomeDLL.dll';

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject); var someinteger : integer; someparameter : integer; begin
   someparameter := 5;
   Someinteger := SXInit(someparameter); //Calls to the external Function in Somedll.dll with the local someparameter variable and returns it into Someinteger end;

end.

For more information you can type this into your help address bar: ms-help://borland.bds5/devcommon/librariesandpackagesov_xml.html

Let me know if this answers your question.

-Nate Sharp
Thanks Devguru. That would emply the function can be declared as

function SXInit(array of const) : integer; cdecl external "MitelClient80.dll" name "SXInit@<etc>"

Though i'm not sure whether that will work as some of the parameters need to be passed by reference. The overloaded approach seems to be the best for what I'm trying to achieve. Although it involves more code from the outset it simplifies the implementation and function prototyping for my team to implement into without tralling through the masses of Mitel documentation :-S

Thanks all again! I will no doubt be back very soon! :)