?
Solved

how do I call a dll not written in C/C++ within VC++

Posted on 2003-02-24
78
Medium Priority
?
774 Views
Last Modified: 2012-06-21
Hi guys,

I have a dll that I have written in object pascal using delphi that I want to use within my VC++ project but don't know how!

What I would like to know is the commands and declarations that I need to include and where I need to include them to be able to use these functions. So lets say my dll contained only one function
procedure mydllfunc(data:mydataType, num:ineteger)
how do I go about using this in VC++?(notice that data is a construct I made myself for the project)

thanks all,
ice
0
Comment
Question by:iceblue_22
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 41
  • 23
  • 8
  • +1
78 Comments
 

Expert Comment

by:Dancer
ID: 8012559
use spyguru or any similiar program to open the dll and look at it's exports.
Use the name used there (it may have more then a few @s, letters and symbols apart from the function name) when declaring the function where I will tell you to use the "mangled" function name

let's say that your mangledfunction name was _mydllfunc@D@I
(It most probably isn't this exact name)

now, in the header, define the function (you'll have to know what each type is, my guess is that DATA turns into some pointer or something to the data structure, and num to integer (Generally, any type bigger then a DWORD will be passed by reference, i.e. pointer):

typedef void (WINAPI *DLT_mydllfunc)(SMyStruct* lpData, int nInteger)

after the typedef, create an instance of that type (preferably in some class:

class CMyClass
{
  .
  .
  .
  DLT_mydllfunc Vmydllfunc;
  .
  .
  .
}

now we load the library and initialize the function, probably in an init function or maybe (if you don't care for failiure check or if you do it another way) in the constructor.

int CMyClass::Init()
{
  //First we load the library, You should check for success in your own code
  HINSTANCE hDll = LoadLibrary("MyDll.dll");

  //Now you assign the procedure address to the variable, use mangled name here!
  Vmydllfunc = (mydllfunc)GetProcAddress(hDll,"_mydllfunc@D@I");
}

Now you can simply call the function using the call:

  CMyClass::Vmydllfunc (ddata, number);

Yours,
<><
Dancer
0
 

Expert Comment

by:Dancer
ID: 8012563
Sorry,
CMyClass.Vmydllfunc (ddata, number);

<><
Dancer
0
 

Author Comment

by:iceblue_22
ID: 8012810
Hi Dancer,

thanks dude...will try right now....and hopefully all will go well.

I just have one query. Do I need to make sure that the header declarations that I make are in the same class as the class struct declaration? ie the struct delcaration I will do in say file sapp.cpp....will I then need to make my corresponding type def in sapp.h?

thanks,

ice
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:iceblue_22
ID: 8012824
crap I forgot....

u talk abt a mangled version for the name of the dll....the name doesn't have any @s as I created the dll. Are these @s mandatory. wht do they represent?

ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8013197

For the @s, that's what's called "Name mangling" if you have classes (C++) inside of a dll, like say MFC, the names will be mangled.

How do they name mangle? Well, it's not a standard in the industry, each compiler vendor will do it their own way, which is why MFC DLL's (dlls which have mfc objects in them) can not be used by Delphi or C++ Builder - the name mangling is different.  it looks like some people here have ideas on how to do this, but, I don't muck with that....

On the other hand, if you have created a standard DLL - say in Delphi <grin>, then you can access the functions in the dll.



If you are using standard types, it's pretty easy. Make sure you list the functions in the exports section of the dll.

However, it looks like the procedure name you included has a Object Pascal type. If that is a record type.

ex:  TMyData = record

... what else are you using in that type? If you are using any Delphi specific types, like say TDateTime, you'll have to consider those too.

I don't think the record will map perfectly to a "C" struct, You might have to change your byte alignment in the compiler settings.

also are you linking statically or are you linking dynamically using LoadLib() ??


your dll should be roughly this format:

library MyLib;

function Min(X, Y: Integer): Integer; stdcall;

begin
  if X < Y then Min := X else Min := Y;
end;


exports
  Min;

begin
end.


don't forget stdcall in function decls and also the exports section.

hopefully this will help you out a little.

sincerely,
J


0
 

Author Comment

by:iceblue_22
ID: 8013515
Hi J,

doesn't a cdecl directive have the same effect as stdcall??
I ask because I was under the impression that as I was going to use the dll (I made using delphi LOL)in VC++ a c declaration would be more appropriate. Rite?

this is how the declarations go:
in the main dll project file I have just an exports directive and then the functions ie:
exports
      func1,
      func2,
      ....
      ;

rite now I have an exports and cdecl directive typed after each function header in the interface section of each unit and no directives in the implementation section. Is this correct?

thanks dude,
ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8013731

I would use stdCall instead.. it is supposedly more efficient... otherwise they look almost the same.... except cdecl calling convention the 'caller' of the dll cleans up and in stdcall the routine in the dll cleans up... slight difference.

but it looks like cdecl is ok.

if you have delphi, look in help under "Calling Conventions" and you can decide for yourself.

I have used Delphi dlls and called them from Visual C++ and (even) Visual Basic. I use stdcall and it has worked fine.

so, if your looking to just get it working, you might just go with stdcall  :)

another thought: you might for the fun of it (if you can afford the time), create a do nothing one liner dll, which contains the simplest function you could think of and try accessing that from C++ - just to rule out any weirdness witht the params that could be contributing to why it's not working... .just a thought.

hope that helps,
J
0
 

Expert Comment

by:Dancer
ID: 8014855
IceBlue_22, The declarations and all don't have to be in the same class as the caller (doesn't even have to be on the same thread).
Just include the header in the calling cpp file.

I have used this method on meny occasions in order to enable plugins fo my program, for integration with other projects written in different languages and a few times in order to use a Borland C++ dll in a VC++ project.
0
 

Expert Comment

by:Dancer
ID: 8014874
Oh, and the @s may not appear at all...
There are ways of making sure there's no mangling in VC and Borland C++ by declaring the function as extern "C", I don't know if there are ways in pascal/delphi but I guess there are, also, maybe they don't mangle at all.
BTW, The mangling is there to enable function overloading and classes.

<><
Dancer
0
 

Author Comment

by:iceblue_22
ID: 8015021
Dancer,

how/where do I put in the extern directive?

J,

did your files while calling the dll look anything like the above skeleton?

Also guys I would really like to get both your opinions on how successful you think my method will be. I have been trying to get a response from ppl who are adept at windows programming(I have no what so ever exp save for the current project). The majority think it is a very chancy thing to do. Both of you sound as though you have mastered the skill. So wht do you guys think?

Also J....yeah I do need to transfer a Object pascal data type....file....wht do you think needs to be done?

Thanks both of you for all ur help not only is it good its also prompt.......and with the project needing to be done ASAP....theres nothing more to say than that ur both champs!!

cheers
ice
0
 
LVL 12

Expert Comment

by:Salte
ID: 8015188
Declare the function as __stdcall.

I assume that parameter types can be immediately translated to C or that you can declare structs etc that map to the object pascal data types.

Be particularly wary for pascal strings and pascal method pointers (those that Borland C++ builder refer to as __closure).

Those aren't really simple pointers but are a struct containing two pointers, a pointer to the method or function to call and a pointer to the object to use as this object for the function.

The function can also be a static function, this should be detectable by either a NULL object pointer or a pointer to the type info for the type. If static function the this pointer should not be used and the pointer should be treated like a regular function pointer.

If non-static function the function pointer is really a pointer to member function and the pointer to object is a pointer to an object that is of a type that is compatible to the type that member function is a member function of. In other words, if object is of type A and the member function is a member function of class B then either A == B or A's baseclass is B or A's baseclass' baseclass is B etc.

Alf
0
 

Expert Comment

by:Dancer
ID: 8015223
in c++, the extern "C" is put in the decleration of the function in the dll header/exported function decleration.

I don't think I understand your second question (maybe it is because english isn't native to me, I am hebrew.

I think if the object only has data and no functions, it should be easy enough to understand it's structure (that is, if delphi doesn't have any new radically different way of storing objects. I didn't use pascal since 1989.
Also, it should be easy enough if it does have functions.
All you need to do is make a small dll and a small program, the dll is passed an object of the wanted structure as a single parameter, and then serializes (to a file or the scree, whatever is easy for you) the object, so you can inspect what went through.
If there are functions, you probably won't be able to construct the object in C++, so to call the function you'll have to copy construct another object in the pascal side.

You'd be suprised at how often this kind of expirimenting this is done.

Yours,
<><
Dancer
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8016511
IceBlue_22:

I may be getting confused here: You have a dll written in Delphi and you want to call it from a C/C++ application correct?  It appears that the posts above are assuming your reading a c++ builder dll ... i dunno.

As for extern "C" in your dll - there is no such thing like that in Delphi.

The skeleton did look just like what I provided.. in fact, I went and reviewed what I had done in one my dll projects and that is what it looked like.

as for how successful this will be, I don't see anything wrong with doing it.

what is the object pascal type?  Is it a TDateTime a TStringList or ???

also what is not working? Do you have a project compiling or is it that it doesnt' compile or does it crash when you make the function call or does it say it can't find the function??

I have done this before and you can do it too, don't worry.

hope this helps,
J
0
 

Expert Comment

by:Dancer
ID: 8017149
in c++, the extern "C" is put in the decleration of the function in the dll header/exported function decleration.

I don't think I understand your second question (maybe it is because english isn't native to me, I am hebrew.

I think if the object only has data and no functions, it should be easy enough to understand it's structure (that is, if delphi doesn't have any new radically different way of storing objects. I didn't use pascal since 1989.
Also, it should be easy enough if it does have functions.
All you need to do is make a small dll and a small program, the dll is passed an object of the wanted structure as a single parameter, and then serializes (to a file or the scree, whatever is easy for you) the object, so you can inspect what went through.
If there are functions, you probably won't be able to construct the object in C++, so to call the function you'll have to copy construct another object in the pascal side.

You'd be suprised at how often this kind of expirimenting this is done.

Yours,
<><
Dancer
0
 
LVL 12

Expert Comment

by:Salte
ID: 8017807
cdecl is not the same as stdcall. In fact they are very different.

stdcall passes arguments in the same manner that Win32 functions accept arguments. It's a safe bet that declaring your function as stdcall in C++ will enable it to be callable from a language L using the same declaration that Win32 functions are callable from language L.

cdecl on the other hand is C's own calling standard and is VERY different. For example arguments come in the opposite order compared to stdcall. On the other hand, you can use variable number of arguments to cdecl functions. variable number of arguments is NOT available with stdcall. printf() etc are all __cdecl. The vprintf() functions etc doesn't have to be __cdecl since they are called with regular arguments. I believe they usually are though - not sure about that.

stdcall is the 'lingua franca' among calling styles on Win32 platforms. Use stdcall, it is available in most languages on Win32 platforms and all languages that can call DLL functions. This is because most DLL's are defined using __stdcall and in particular kernel32.exe, user32.exe and gui32.exe have almost all their functions defined as __stdcall and those that aren't are not available from any language unless  that language can declare a function to be __cdecl. Object pascal happen to have cdecl as a keyword and can define functions as cdecl but there's no reason why you should do that.

Alf
0
 

Author Comment

by:iceblue_22
ID: 8020609
Hi Dancer,
 
I think I am going to give the extern a miss and stick with how I am doing it right now...thts not too much of a hassel rite?

Hi Alf,
thanks for clearing tht up for me....I am going to change all my cdecl into stdcall's right now.

Hi J,

The typedef that I am having problems with is this:
void DecodeJPEG(lStream: TMemoryStream; lOutSmallRA: SmallIntP0; lImgRAz: ByteP0;lOutputSz,lCptPosition,lCptSize: integer; lVerbose: BOOL);  
In the above I don't know how to represent parameter lStream as it is type TMemoryStream...would you have any clue as to how to do this? Also type SmallIntPO and BytePO are custom made types in delphi...wht would you suggest i do...I have been referring to these as pointers....is this ok? so for example if I had:
 void func1(var1:BytePO; var2:SmallInoPO);
I would convert this into a typedef as follows
 typedef void (WINAPI *DLTfunc1)(BytePO* var1, SmallIntPO* var2)
and in class MyClass I have a corresponding
  .....
  DLTfunc1 func_1;
  .....

What is happening is that though I can get both the dll and the C header files to compile the functions don't seem to work!!!...i don't knw if it because I have written the dll incorrectly or if I am calling the dll functions incorrectly......

thanks all
ice
0
 

Author Comment

by:iceblue_22
ID: 8020625
Also u guys,

My initial 20 points don't do justice to the help you've given me......so please let me know on a more likely number bearing in mind tht u'll have to share them....can u do tht?

later,
ice
0
 

Author Comment

by:iceblue_22
ID: 8020643
also J,

what about type file?? how would I declare it an array?...can I do this?

ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8020774

Hi,
a few thoughts/comments.  First, I apologize if I didn't emphasize it enough, but in my first post, I suggested you go with stdcall instead of cdecl and that although i didn't have the gory differences, I mentioned help file, and that I thought you should just go with stdcall

regarding your Delphi specific types, I would move away from them.

void DecodeJPEG(lStream: TMemoryStream; lOutSmallRA: SmallIntP0; lImgRAz: ByteP0;lOutputSz,lCptPosition,lCptSize: integer; lVerbose: BOOL);  

as for SmallIntPO, what do you have that declared as? Also your lOutputSz is integer, but it the way you named it, it looks like it should be a pchar...

the TMemoryStream, I'm not sure what to do about that, let me go eat dinner and think about it...

as for points.... I don't even bother to track points much.. was it only 20?  Yeh, you might crank that up some.

J
0
 

Author Comment

by:iceblue_22
ID: 8020859
Another query Dancer,

in the above skeleton that u have given me:
    //Now you assign the procedure address to the variable, use mangled name here!
 Vmydllfunc = (mydllfunc)GetProcAddress(hDll,"_mydllfunc@D@I");

where does the (mydllfunc)Get.... come from ie which name am I supposed to use?

ice
0
 

Author Comment

by:iceblue_22
ID: 8020931
Another query Dancer,

in the above skeleton that u have given me:
    //Now you assign the procedure address to the variable, use mangled name here!
 Vmydllfunc = (mydllfunc)GetProcAddress(hDll,"_mydllfunc@D@I");

where does the (mydllfunc)Get.... come from ie which name am I supposed to use?

ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8020967

You can link to dlls 2 ways
1. using load time dynamic linking
2. using run-time dynamic linking


for load-time dynamic linking, you need to link in a .lib file, which has the information about the dll.

for run-time dynamic linking, you use the LoadLib() function and a few others to dynamically make a call to the dll at runtime.

Here's a sample of calling a dll. I'm in a hurry right now, so I stole it from a sample...  for this purpose, let's pretend that you have a dll called MyDll.dll

it contains one function, called void puts( char* psz);

to call that function in our pretend dll, you sould could use the following code (courtesy of a microsoft sample)

look this over and I think you'll get a better idea of how you call it.

hth ,
J

 
#include <stdio.h>
#include <windows.h>
 
typedef VOID (*MYPROC)(LPTSTR);

 
VOID main(VOID)
{
    HINSTANCE hinstLib;
    MYPROC ProcAdd;
    BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
 
    // Get a handle to the DLL module.

    hinstLib = LoadLibrary("myputs");
 
    // If the handle is valid, try to get the function
    // address.
 
    if (hinstLib != NULL)
    {
        ProcAdd = (MYPROC) GetProcAddress
            (hinstLib, "myPuts");
 
        // If the function address is valid, call the
        // function.
 
        if (fRunTimeLinkSuccess = (ProcAdd != NULL))
            (ProcAdd) ("message via DLL function\n");
 
        // Free the DLL module.
 
        fFreeResult = FreeLibrary(hinstLib);
    }
 
    // If unable to call the DLL function, use an
    // alternative.
 
    if (! fRunTimeLinkSuccess)
        printf("message via alternative method\n");
}

0
 

Author Comment

by:iceblue_22
ID: 8021056
J...HELP!!!....

first off...please knw that all you help is much appreciated.......having said that help me!!!

I compiled the header file and I get 103 errors for 20 lines of code.....most of them come from the pointer declarations of the delphi custom made types. And also something about bool type usage:
   'bool' : illegal use of this type as an expression

also id having the particular dll within the same directory as the project enough for VC++ to link the dll with the project?

waiting in trepridation,
ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8022203
Ok, I'm back.

what header file did you compile? I guess a file you created to map to the types for Delphi?

Ok for the memory stream, I thought about this some and I don't think you'll be able to get away with moving that between c++ and delphi - unless maybe your using C++ Builder (heh heh)... I have the feeling your using Visual C++ right?.. so that is ruled out.

what you might consider doing is creating a set of functions in the dll, which you can call to perform operations on the MemoryStream - which is living inside the dll. Kind of like manipulating windows with the Windows API, you have a set of functions, which you call and they all operate on a Windows Handle (HWND). You might be able to do the same thing with the MemoryStream - this way you wouldn't have to worry about passing it back and forth... thus solving that problem.

as for the other types...  please provide me with the record as you have declared it in Delphi and the types you used in the record if they are not standard types.

I'm putting together a little sample, which will help, hold on.

J

0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8022238
oh yeh, you get a compiler error for 'bool' because
c++ doesn't know about that type.

You need to declare your bool as BOOL
case matters.

J
0
 

Author Comment

by:iceblue_22
ID: 8022433
J...ur a legend...

right now I have about 8 errors....I figured out the prob with bool...but wht is pissing me off right now is the followig error....
error C2320: expected ':' to follow access specifier 'type'
and
fatal error C1070: mismatched #if/#endif pair in file 'sapp.dll'

both of these I can't figure out. Also in relation to the delphi data types what I have done is written up C struct that hold the same information.

for error C2320 I have done the following say my function is Display_Image...then

typedef void (WINAPI *DLT_DisplayImage)(bool lUpdateCon, bool lForceDraw, int lSlice, double lInWinWid, double lInWinCen);
 and
class sappdll
{
//Construction
public
     
DLT_DisplayImage  Display_Image_dll;
}

is this right?

ice
0
 

Author Comment

by:iceblue_22
ID: 8022467
J...ur a legend...

right now I have about 8 errors....I figured out the prob with bool...but wht is pissing me off right now is the followig error....
error C2320: expected ':' to follow access specifier 'type'
and
fatal error C1070: mismatched #if/#endif pair in file 'sapp.dll'

both of these I can't figure out. Also in relation to the delphi data types what I have done is written up C struct that hold the same information.

for error C2320 I have done the following say my function is Display_Image...then

typedef void (WINAPI *DLT_DisplayImage)(bool lUpdateCon, bool lForceDraw, int lSlice, double lInWinWid, double lInWinCen);
 and
class sappdll
{
//Construction
public
     
DLT_DisplayImage  Display_Image_dll;
}

is this right?

ice
0
 
LVL 2

Accepted Solution

by:
BorlandMan earned 240 total points
ID: 8022655

That is declared right.

To keep things simple, I would try doing it in a C type routine before I go hog wild and stick it in a class.

here's some boilerplate code for calling a dll dynamically at run time.

I have also included the delph dll source too below it so you can see there are no smoke and mirrors.

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

typedef int (CALLBACK* MY_DOMESSAGE_PROC)(LPTSTR);

void Make_DllCall()
{
     
    HINSTANCE hinstLib;
    MY_DOMESSAGE_PROC     doMessageProcPtr = NULL;
    BOOL fFreeResult;
    BOOL fRunTimeLinkSuccess = FALSE;

     
    // Get a handle to the DLL module.
    hinstLib = LoadLibrary("MyDll.dll");
 
    // If the handle is valid, try
    // to get the function address.
    if (hinstLib != NULL)
    {
     // this points to the function address;
        // note the name of the function is case sensitive
        doMessageProcPtr = (MY_DOMESSAGE_PROC)
              GetProcAddress(hinstLib, "DoMessage");
 

        // If the function address
        // is valid, call the function.
        if (fRunTimeLinkSuccess =
              (doMessageProcPtr != NULL))
     {
        LPTSTR lpszStr = "Test Delphi";

        // actually calling the function here
           int retVal = doMessageProcPtr (lpszStr);
        if (retVal)
           MessageBox (NULL, "Clicked Yes",
                          "Status", MB_OK);
        else
           MessageBox (NULL, "Clicked Nope",
                          "Status", MB_OK);
     }
       
        // Free the DLL module.
        fFreeResult = FreeLibrary(hinstLib);
    }
 
    if (! fRunTimeLinkSuccess)
        MessageBox(NULL,
               "message via alternative method",
                "Error", MB_OK);

}


//
// Delphi DLL
//     The passing of the record I'm missing something
//     on at this moment.
//

library MyDll;

uses
  SysUtils,
  Classes,
  Dialogs,
  controls;

{$R *.res}

type
  TMyRec = record
    Name: string;
    Value: boolean;
    Amount: Integer;
  end;

function DoMessage(szMessage:pchar):integer; stdcall;
var
   sMessage: string;
begin
  sMessage := szMessage;  // automatically converted
                          // from pchar to pascal string :)

  result := 0;
  if MessageDlg(sMessage, mtInformation,
               [mbyes, mbno], 0) = mrYes then
     result := 1
end; // DoMessage

//
// this is not right yet, sorry. I'm missing something
// here which isn't returning right.
//
function getMyRec ( ARec: TMyRec):integer; stdcall;
begin
  arec.Name := 'Hello World';
  arec.Value := false;
  arec.Amount := 42;
end;

exports
  DoMessage,
  getMyRec;
begin
end.
0
 

Author Comment

by:iceblue_22
ID: 8022705
J...ur a legend...

right now I have about 8 errors....I figured out the prob with bool...but wht is pissing me off right now is the followig error....
error C2320: expected ':' to follow access specifier 'type'
and
fatal error C1070: mismatched #if/#endif pair in file 'sapp.dll'

both of these I can't figure out. Also in relation to the delphi data types what I have done is written up C struct that hold the same information.

for error C2320 I have done the following say my function is Display_Image...then

typedef void (WINAPI *DLT_DisplayImage)(bool lUpdateCon, bool lForceDraw, int lSlice, double lInWinWid, double lInWinCen);
 and
class sappdll
{
//Construction
public
     
DLT_DisplayImage  Display_Image_dll;
}

is this right?

ice
0
 

Author Comment

by:iceblue_22
ID: 8022737
J.

its official....I am in love with you!!!!...

thanks sooo much....I just got a look at your code for delphi and VC++....actually I have made life a lil bit easier as I now only need to call A function....without any delphi data types......

as you have given me a working version of the dll I am going to follow it like the gosple truth!!!

ice....

PS: will defintely get back to you on my success.....(:
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8022741

Display_Image_dll is a variable which points to the function, yes.

but now you need to do the GetProcAddress() stuff to get a pointer to the function in the dll.

looks good so far.

J
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8022917

Thanks for the kind words   :)
(unix right?)

Good job making your dll calls use standard C data types, that should simplify things considerably.

looks like your pretty much there.

just out of curiosity what was this project for? .. and how did Delphi get involved with it?

alright then,
take it easy,
sincerely,
J
0
 

Author Comment

by:iceblue_22
ID: 8022995
Hiya J...

am doing all tht u've hinted towards...hopefully its all good.....this is wht my final thing looks like
sapp_dll::sapp_dll()
{
                HINSTANCE hinstLib;
          DLT_DisplayImage Display_Image_dll = NULL;
          BOOL fFreeResult;
          BOOL fRunTimeLinkSuccess = FALSE;

          //Get handle to the DLL module.
          hinstLib = LoadLibrary("sappdll.dll");

          //If the handle is valid try to get the function address.
          if(hinstLib != NULL)
          {
               //this points to the function address
               //note the name is case sensitive
               Display_Image_dll = (DLT_DisplayImage)GetProcAddress(hinstLib,"DisplayImage");
               
               //if function address is valid, call the function
               if(fRunTimeLinkSuccess = (Display_Image_dll != NULL))
                    (Display_Image_dll)("message via DLL function\n");

               //free the DLL module.

               fFreeResult = FreeLibrary(hinstLib);
          }

          //If unable to call the DLL function use an alternative.

          if(!(fRunTimeLinkSuccess))
               printf("message via alternative method\n");
}

I did go crazy and put it in a class...so according to what u've told me so far.....from here on I will just need to call the function and the dll will take over from there...rite?

ice
0
 

Author Comment

by:iceblue_22
ID: 8023015
now the mix of delphi and VC++....

I am been trying to debug a medical image viewer as part of my IT for my degree.....the problem was that the application(in VC++) couldn't read certain file formats......

So out I went and got some code which did this...the only problem was that it was in delphi.....so far I have had no exp with windows programming at all(yups I am a unix chic)...

...thus end my story......only thing left to say is THANK YOU!!!!

check you out later,
ice
0
 

Author Comment

by:iceblue_22
ID: 8023018
by the way J could I have put in the calling of the DLL in any class??

ice
0
 

Author Comment

by:iceblue_22
ID: 8023052
once again thank you....u've helped me get this thing done on time....

take care,
sincerely,
ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8023096

Hi,
a medical image viewer very cool. I've done some software, which communicates with embedded devices, it's interesting and tricky stuff... what file format were you trying to read?... just out of curiosity (yep, I'm a Curious George)

by the way, Delphi is a very cool tool. It gives you the power of c++ and the rad of Visual Basic. You can sit at a high level of doing just component gui stuff and not have to muck with Windows APIs or you can dig down and do that too... excellent tool for database development and very object-oriented... good for developing apps in Windows even if you don't know Windows... then as you get more into it, Delphi helps you there too... if you want a c++ version of Delphi, check out c++ Builder at www.borland.com
... it supports all the same types and components as Delphi does... so if you were using C++ Builder, you could have simply linked in the code you had for delphi without having to use a dll....

as for putting the call to the dll in the class that is fine. I was just suggesting this to minimize the things that could go wrong.

oh quick observation, there is a printf() in the code I gave you, you might want to change that to
MessageBox (NULL, "the error message", "Title of dialog", MB_OK);

Unix is cool. I have always liked vi (my windows buddies think I am  sick)... and the way you can chain little programs together.. have you checked out Apples OS X ??
It is built on Unix BSD and Mach .. very slick.

anyway,
take it easy,
John Scalco
0
 

Author Comment

by:iceblue_22
ID: 8023185
dude I am nearly there....

except that after declaring the calling of the dll func in my sapp_dll class....I don't know how to call Display_image in other classes.....any ideas?

the image format I am working is called DICOM...its a industry standard for all medical images.....yep its been great leanrning abt the stuff....

and hence forth after the last month on windows i am definitely gonna try getting comfortable with it......

0
 

Author Comment

by:iceblue_22
ID: 8023228
hey dude,

ur MessageBox statement come up with the error..
error C2660: 'MessageBoxA' : function does not take 4 parameters

also i am trying to use Display_Image like so....
sapp_dll::Display_Image_dll(false, false, 0, 10, 0);
however I get 2 errors
'sapp_dll' : is not a class or namespace name //however sapp_dll is a class
'Display_Image_dll' : undeclared identifier //and I have defintely declared this like u told me to.....

waiting for a reply....
urs,
ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8025528

MessageBox(NULL, "Message", "Title", MB_OK);

.. if your doing it from inside a class you have to
say ::MessageBox(NULL, "Message", "Title", MB_OK);
as the compiler thinks you are calling a method inside of the class

as for sapp_dll, my guess, based on previous discussions is that you have declared the class, maybe something like this:

class sappdll
{
//Construction
public
   
DLT_DisplayImage  Display_Image_dll;
}

Ok, well you can't say this

sapdll::Display_Image_dll(..);

unless you make the Display_Image_dll a static method.

what I think you want to do is create an instance of the class and then call the method - did you create your object?

ex:

void Test_Drive()
{
   sapdll*  pMySapDll;

   pMySapDll = new MySapDll();
   pMySapDll->Display_Image_dll(...);

   delete pMySapDll;

}

or you can create it on the stack frame

void Test_Drive2()
{
   sapdll MySapDll;

   MySapDll.Display_Image_dll(...);

}


hope that helps,
J
0
 

Author Comment

by:iceblue_22
ID: 8041274
hi J.....

sorry for the late reply...
I have been away for the past 2 days...and wont be at work till the coming tuesday...I don't have any of the stuff on me...so am taking a break frm it for a few days...remember me only a uni student...and it starts this monday......

hopefully u won'r be too buggered abt helping me out on tuesday when I get stuck....

ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8041616
I thought you had it working now?

if you need help, post the question and I'll see what I can do.

J
0
 

Author Comment

by:iceblue_22
ID: 8045343
sure will.

later dude,
ice
0
 

Author Comment

by:iceblue_22
ID: 8060762
hey am back....

well I did everything that you suggested.....so far I have got the dll to compile without errors vut I don't know what I have done in calling it.....

the exe just crashes when I run the particular function.
This is the code I wrote in the class sappdll.cpp:

sapp_dll::sapp_dll()
{
          HINSTANCE hinstLib;
          DLT_DisplayImage Display_Image_dll = NULL;
          BOOL fFreeResult;
          BOOL fRunTimeLinkSuccess = FALSE;

          //Get handle to the DLL module.
          hinstLib = LoadLibrary("sappdll.dll");

          //If the handle is valid try to get the function address.
          if(hinstLib != NULL)
          {
               //this points to the function address
               //note the name is case sensitive
               Display_Image_dll = (DLT_DisplayImage)GetProcAddress(hinstLib,"DisplayImage");
               
               //if function address is valid, call the function
               /*if(fRunTimeLinkSuccess = (Display_Image_dll != NULL))
                    (Display_Image_dll)("message via DLL function\n");*/

               //free the DLL module.

               fFreeResult = FreeLibrary(hinstLib);
          }

          //If unable to call the DLL function use an alternative.

          if(!(fRunTimeLinkSuccess))
          ;     //MessageBox (NULL, "the error message", "Title of dialog", MB_OK);
}

and this is how I called the function in another class within the project:

DLT_DisplayImage Display_Image_dll = NULL;
Display_Image_dll(false, false, 0, 10, 0);

is this correct? My header is fine so I can't seem to find the problem...I put in the static parameters just to try the thing out first.

waiting for ur reply,
ice

0
 

Author Comment

by:iceblue_22
ID: 8060934
hey am back....

well I did everything that you suggested.....so far I have got the dll to compile without errors vut I don't know what I have done in calling it.....

the exe just crashes when I run the particular function.
This is the code I wrote in the class sappdll.cpp:

sapp_dll::sapp_dll()
{
          HINSTANCE hinstLib;
          DLT_DisplayImage Display_Image_dll = NULL;
          BOOL fFreeResult;
          BOOL fRunTimeLinkSuccess = FALSE;

          //Get handle to the DLL module.
          hinstLib = LoadLibrary("sappdll.dll");

          //If the handle is valid try to get the function address.
          if(hinstLib != NULL)
          {
               //this points to the function address
               //note the name is case sensitive
               Display_Image_dll = (DLT_DisplayImage)GetProcAddress(hinstLib,"DisplayImage");
               
               //if function address is valid, call the function
               /*if(fRunTimeLinkSuccess = (Display_Image_dll != NULL))
                    (Display_Image_dll)("message via DLL function\n");*/

               //free the DLL module.

               fFreeResult = FreeLibrary(hinstLib);
          }

          //If unable to call the DLL function use an alternative.

          if(!(fRunTimeLinkSuccess))
          ;     //MessageBox (NULL, "the error message", "Title of dialog", MB_OK);
}

and this is how I called the function in another class within the project:

DLT_DisplayImage Display_Image_dll = NULL;
Display_Image_dll(false, false, 0, 10, 0);

is this correct? My header is fine so I can't seem to find the problem...I put in the static parameters just to try the thing out first.

waiting for ur reply,
ice

0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8061557
Hi,
You aren't doing a check on the ptr to the function, so if it comes back incorrect or NULL, then you just call it anyway, at least that's what it looks like


you should probably add a check like this (which i included in the sample <wink-wink>


Display_Image_dll = (DLT_DisplayImage)GetProcAddress
                            (hinstLib,"DisplayImage");

// check GetProcAddress returned correct address
// if you access it and the address is wrong your hosed!
//
if (Display_Image_dll != NULL) {
   /* do your thing here */
}
else {
   MessageBox (NULL, "Could not find address of fn",
               "Status Dialog", MB_OK);
}


Please provide your declaration for DLT_DisplayImage
(the pointer to the function declaration)

and the prototype of the function you are calling in the Delphi dll.

I'd like to look at those see if anything is amiss.


hth
J
             

0
 

Author Comment

by:iceblue_22
ID: 8061937
hi,

DLT_DisplayImage looks like so in the header:
typedef void (WINAPI *DLT_DisplayImage)(BOOL lUpdateCon, BOOL lForceDraw, INT lSlice, double lInWinWid, double lInWinCen);
and in delphi looks like this:
  procedure DisplayImage(lUpdateCon,lForceDraw: boolean;lSlice: integer; lInWinWid,lInWinCen: double); stdcall;

is there a problem in the translation?

regards
Sri
0
 

Author Comment

by:iceblue_22
ID: 8061945
hey I just have a query...

the change you wanted me to make can be done in my sappdll.cpp file rite?

and then I proceed to call the function in another class like I said above:

DLT_DisplayImage Display_Image_dll = NULL;
Display_Image_dll(false, false, 0, 10, 0);

correct?
0
 

Author Comment

by:iceblue_22
ID: 8062041
hey I just have a query...

the change you wanted me to make can be done in my sappdll.cpp file rite?

and then I proceed to call the function in another class like I said above:

DLT_DisplayImage Display_Image_dll = NULL;
Display_Image_dll(false, false, 0, 10, 0);

correct?
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8062179
Ok,

Short answer, the changes I suggested should be in the application which is calling the dll (your c++ application)

Your problem is most likely that you are not checking for null when you call GetProcAddress() - you should make it a habit to do this. Because if the function is not found in your dll, then you will be trying to call a NULL pointer.

So, test for that. If you are getting NULL, then it means that (a) you are not loading the right dll (do you have a copy in more than one place (ex: C:\mydev and c:\WinNt\System32) - you might think your calling one dll, when in fact your calling an old dll.

If you are sure you are calling the right dll (that is, there is only one of these dlls on your computer), then check that you have your exports in the Delphi dll.


Next, another point to consider (not necessarily the cause of your bug), but... if any of the params you are passing in to your dll, you expect to return a value from the dll; Say, lUpdateCon is used to determine from the dll the update status, then you need to make a change, because  BOOL lUpdateCon passes in a copy, not a pointer of the variable, so any changes made in the dll to the variable you passed in will never be returned back to your program.
You need to pass the address of your variable in your application into the dll - pointers.

Here's an example. For this example, let me assume that you expect all params to change in the dll and want to get that in your main application when the dll is done being called.

The changes you would make would be something like this:

typedef void (WINAPI *DLT_DisplayImage)(BOOL* lUpdateCon,
               BOOL* lForceDraw,
               int* lSlice,
               double* lInWinWid,
               double* lInWinCen);

your delphi procedure would look almost the same, but you put var in front of each variable which you want to pass back and forth from the dll

ex:

procedure DisplayImage(var lUpdateCon: boolean;
                       var lForceDraw: boolean;
                       var lSlice: integer;
                       var lInWinWid: double;
                       var lInWinCen: double); stdcall;

Note: if you use var, then you must separate each variable's declaration with a semicolon.

You can't say this:  var lUpdateCon, var lForceDraw: boolean


Here's an example of calling it from a dll.


hinstLib = LoadLibrary("MyDll.dll");
 
if (hinstLib != NULL) {

  doItProcPtr = (DLT_DisplayImage) GetProcAddress
                         (hinstLib, "DisplayImage");

  if (fRunTimeLinkSuccess = (doItProcPtr != NULL))
  {
    BOOL lUpdateCon = false;
    BOOL lForceDraw = false;
    int lSlice = 0;
    double lInWinWid = 0;
    double lCen = 0;

    // passing the address of the variables here
    // so we'll know the changes.
    doItProcPtr (&lUpdateCon, &lForceDraw,
                 &lSlice, &lInWinWid, &lCen);
  }
  // Free the DLL module.
 
  fFreeResult = FreeLibrary(hinstLib);


ok?

This should fly, if you still have errors.
comment out your dll's code in teh function and put one line in there:  MessageBox (NULL, "Can you hear me now?",
                           "Test Dialog", MB_OK);

run your app, the message should appear, if it does not, you still don't have your dll setup correctly - if it does display the message, then all is well with your dll functions - it's something in your code that is causing the crash.


hope that helps,
I'm not sure what time zone your in, but I'm headin' for bed, I'll check mail in the morning.

hth,
J
0
 

Author Comment

by:iceblue_22
ID: 8062253
hey I just have a query...

the change you wanted me to make can be done in my sappdll.cpp file rite?

and then I proceed to call the function in another class like I said above:

DLT_DisplayImage Display_Image_dll = NULL;
Display_Image_dll(false, false, 0, 10, 0);

correct?
0
 

Author Comment

by:iceblue_22
ID: 8062445
hey borlandman,

how do I use doubles in my parameters? using these gives as u suggested gives me the following error:

'void (bool,bool,int,double,double)' : cannot convert parameter 5 from 'double *' to 'double'

wht do you reckon I need to use...is there something like LPTSTR?

thanks dude
Sri
0
 
LVL 12

Expert Comment

by:Salte
ID: 8063118
The best way to figure out what to name the function in argument to GetProcAddr is to inspect the DLL with some form of DLL viewing tool and see what the DLL think the name is. It isn's always the same as what C++ think it is. I assume you have already specified extern "C" so it is actually what you might think C think it is.


The point is that the C compiler (and the C++ compiler when using extern "C") also do some name mangling, it isn't as fancy as for C++ but there is some.

First, stdcall and cdecl uses different name mangling, stdcall typically looks like:

Foo@28

This is a function foo with an argument list so large that the size of it is 28 bytes.

Not sure if you can simply place "DisplayImage" as the name of the function to GetProcAddr, I would think you would have to write something like:

DisplayImage@N where N is some number and typically a multiple of 4 since an argument list is usually or always a multiple of 4 bytes.

Secondly, as far as I know, C++ does know about the bool type. I even thought that C knows about the bool type since the C99 version, I may be wrong in this though.

The typedef BOOL that windows uses isn't bool however, it is defined as:

typedef int BOOL;

so it really is the same as int. This is because it stems from the days when C didn't have bool type and there was no C++.

Alf
0
 

Author Comment

by:iceblue_22
ID: 8063140
Alf,

my error is more to do with the double....when i put in a double the compilers complains tht the conversion frm double * to double can't be made...but doesn't have this problem with int or bool....I thk bool...isn't so bad as WINAPI will realize tht the BOOL is the same as bool rite??

thanks,
ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8064271

Hi IceBlue_22,

did you check that you are only have one of these dlls on your system? Do a search and double check. You can have the same dll on your machine in different folders many times, but Windows will use the one first found in your WinNt\System32 folder and then look in you applications folder..... so one dll could hide the other.... Make sure!! Otherwise you may be on a wild goose chase and it may infact work.


regarding your question about the double, that should be fine. I guess I didn't explain this very well in my last posting (above), but if you want to pass in a parameter and have that parameter change, then you need to pass a pointer.

say you have a function called

Random_Num()

you pass in an integer and that integer will be changed by the function, for this to happen you pass an address

int myNum = 0;
Random_Num (&myNum);

// now it's maybe 42 or some random number.
after the call myNum will be populated with whatever Random_Num() wrote into that variable.


in your dll (delphi one) you need to change your function to look like this:

procedure DisplayImage(var lUpdateCon: boolean;
                      var lForceDraw: boolean;
                      var lSlice: integer;
                      var lInWinWid: double;
                      var lInWinCen: double); stdcall;

see the 'var' in front of each variable, that means that when you call this procedure from see, you must pass the address. So, you put var in front of whatever variable you want to be able to return. You don't have to put it on all of them, just the ones that you want to get the value.

var is Delphi's way of saying that this variable can be changed by the function and returned back to the caller.


Your typedef should look like this:

typedef void (WINAPI *DLT_DisplayImage)(BOOL* lUpdateCon,
              BOOL* lForceDraw,
              int* lSlice,
              double* lInWinWid,
              double* lInWinCen);

basically put a *  whereever you have a parameter you want to get back with a result which was set in the dll.

from your c++ application's function where you call
say your function where you call this is DisplayStuff(),
you should call LoadLib() - like we have in the past discussions, check the pointer is ok, then use GetProcAddress() to get a pointer to the function, check that the pointer is not NULL and then make the call below

doItProcPtr (&lUpdateCon, &lForceDraw,
             &lSlice, &lInWinWid, &lCen);

and that should work.

if you still can't get this to work, then I suggest you

1. Include in your next mail the declaration of your procedure in the DLL (delphi)

2. Your current typedef which you use to call that procedure.

ok?
J

0
 
LVL 12

Expert Comment

by:Salte
ID: 8064500
Err...

The type 'double *' is a pointer to double.

'int *' is a pointer to an int

and 'bool *' is a pointer to a bool.

All these are different from double, int and bool.

If you have a double * and you want a double you need to dereference the pointer:

double x;
double * px = & x;

px is now pointing to the x.

*px = 1.0; // set x to 1.0

func(*px); // give the value 1.0 as argument to function func.

Func is here a function that takes a double as argument.

Use & x to get from type T to type 'T *'. If x is of type T then & x is of type 'T *' and has a value that is a pointer to the variable x.

Use *px to get form type 'T *' to type T. If px is of type 'T *' then *px is of type T and is the contents of the variable which px is pointing to.

If px points to x and x has the value 3.14 then *px will evaluate to the value 3.14 and if assigned to as in:

*px = 2.7;

Then it is the variable x that is assigned to. If you instead do:

double y;
px = & y;

Then it is not x that is changed but the pointer px is now changed to point to y instead of x from then on *px = 1.2; will set y to 1.2 and x will not be touched.

double *px;

is very different from

double x;

It is two different types, the latter is a value of type double (floating point) and the former is a value that can hold the location of a double variable. Actually, it doesn't have to be a variable, it can also be an element of an array:

double arr[5];
double * px = & arr[3];

In this case px holds the address of element arr[3] so *px will reference the value in that array element. When used as pointer to array element you can also do pointer arithmetic:

px + 1   will be a pointer to arr[4] so

*(px + 1) = 3.7;

will change arr[4] to 3.7

In fact: arr[4] is exactly the same as *(arr + 4) where the array arr is used as a pointer to the first element. This is why you often see functions that take a pointer type such as buffer or table or array. The pointer received is simply the pointer to the first element of that array or table and if you then also have a count of how many elements the array or table contains you can reach all the elements from that pointer.

double arr[10];

func(arr,10);

func might have a prototype like:

void func(double * vec, int count)
{
   ....
}

The array is transferred but the function doesn't see the array, it see a pointer to the first element of the array.
*vec is the same as arr[0], *(vec + 1) is the same as arr[1] etc... you can also write vec[0] and vec[1] etc, they mean the same thing: vec[x] is the same as *(vec + x).

I don't think you can resolve your problem by sending the double as a group of 2 32 bit ints. Your problem is rather that you have a pointer to double and try to send that as the double itself. Use *pdbl as argument instead of pdbl.

Alf
0
 
LVL 12

Expert Comment

by:Salte
ID: 8064517
err disregard part of my previous post, I got the question mixed up with another question and part of my response was a response to the a question that wasn't the question here :-)

Anyway, the fact that pointer to double and double are two different types still remain. Disregard the thing about transferring two 32 bit values instead of double and other non-sense :-) That doesn't belong here.

Alf
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8064633

Right pointer to double and a double are different.
Alf, you might want to read the previous posts to get an idea what is going on.

It looks like IceBlue is not calling her dll correctly.
I say this because I have compiled similar code, code which calls a Delphi dll from a visual c++ application - that is what she is trying to do... and Delphi does handle double with no problems. So, I think it's just a little error somewhere.

hth,
J
0
 

Author Comment

by:iceblue_22
ID: 8068710
Hi J,

I am taking a day off work today and will be back on the case tomorrow. will defintely try to make the changes tht u suggested. I think my problem is on the delphi end of the question as I didn't do precisely what u have said above. I am pretty confindent on the VC++ side as I did wht told me ealier.

btw dude all ur seggestions have been very very helpful, thanks once again for them(I knw I am repeating myself.....(:)

I am from sydney australia....not quite sure abt the time zone.

cheers,
sri
0
 
LVL 12

Expert Comment

by:Salte
ID: 8070296
I did read the backlog previously, so I sort of knew what was going on, I just mixed this thread with another thread and goofed :-) There's another thread where a guy is trying to pass a VB double to a C++ function and for some reason he cannot or will not use 'double' but want to use two 32 bit integers or some such instead. So I started to respond to his thread in this thread. Plain goof in other words :-)

In any case pointer to double and double are still different types.

What is the prototype in Delphi and what is the C/C++ prototype you're using?

Those two has to match somehow...

procedure foo;

void foo();

function bar return integer;

int bar();

etc etc...
function baz(x:Double) return double;

double bar(double x);

the argument name doesn't have to match but the types must and when you call the function you must call it with values matching the argument list, so a double require a type of double and not a pointer to double.

Be very wary when Delphi uses 'var' or reference parameters:

procedure DisplayImage(var lUpdateCon: boolean;
                     var lForceDraw: boolean;
                     var lSlice: integer;
                     var lInWinWid: double;
                     var lInWinCen: double); stdcall;

In C++ and C you can write this like:

void __stdcall DisplayImage(bool * UpdateCon,
                            bool * lForceDraw,
                            int * lSlice,
                            double * lInWinWid,
                            double * lInWinCen);

For C pre C99 you must also have a:

typedef int bool;

you should probably also use 'int' of appropriate size instead of the bool if Delphi's bool has different size than C++'s bool type. Check delphi's bool and see how many bits it is, and if that fit with sizeof(bool) then it's fine, otherwise use int/short/char depending on the size of delphi bool. If delphi's bool is 1 byte then most likely you should use char instead of bool for delphi's bool.

Also, note that since the var arguments are really pointers, you must pass pointer values to them:

double x, y;
int k;
bool b, b2;

DisplayImage(&b,&b2,&k,&x,&y);

In delphi's var arguments they can either be both IN OUT or just OUT parameters, I think the 'var' keyword specify that they are both IN OUT while 'out' is what you would use for OUT arguments.

This means that all the variables b, b2, k, x and y must have reasonable values before calling the function. The function may modify those values.

If the parameters are for output only and the procedure ignore their initial values you don't have to put any special value in them.

When calling the function you MUST provide addresses, since the reference parameters translates to pointers in C and C++. Use the & as 'address of' operator as I showed above.

Alf
0
 

Author Comment

by:iceblue_22
ID: 8070504
Hi Alf,

thanks for ur suggestions.....will be in tomorrow so am defintely gonna implement the above changes that both u and J have given.

later,
ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8072161

Hi IceBlue_22,
How are you?

hope you have a good day off.

please post your declaration for the procedure on the Delphi side and we'll straighten it out.

also, if you could indicate what parameters you want changed by the dll, i'm sure that would be useful.

worse comes to worse, i have some skeleton (c++ and delphi) code I slapped together which matches your function declarations - with doubles being used and it works fine.... tha'ts why i asked if your blow up was because (a) your checking the ptr to the function (b) your calling the function and it blows up or (c) your calling it and something IN the function is blowing up.

talk to you when you come back,
have a good one.

i heard it's going to be warm in Sydney today <grin>
hmmm, time zone, yeh, I would imagine it's a bit different (heh heh) from where I am. I'm in the United States, SouthEast.

regards,
J
0
 

Author Comment

by:iceblue_22
ID: 8076467
Hi J....

actually its quite nippy here right now.....I ain't actually at work today have uni till tuesday....but yeah...

on the delphi side of things my declaration lookd like so:

procedure DisplayImage(var lUpdateCon: boolean;
                                 var lForceDraw: boolean;
                                 var lSlice: integer;
                                 var lInWinWid: double;
                                 var lInWinCen: double);                           stdcall;

very much like wht u have above......also i put in the exports clause only in the dll proj file in delphi....ie:
exports:
Display_image;

does this sound abt right to you?
MSDev right now doesn;t like me using a double for the function as I have it declared as a double *.......

wht do you thk??.....I will be back at my workplace on tuesday....

see you then...
later ice...

its winter or autum for u rite now yeah??...have a good one....LOL
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8076718

hi,
oh, I guess I have been fooled by the media. TV/Movies always show Australia (Sydney) warm... but obviously, it's seasonal..

the delphi declaration looks just right.

the exports though, I hope is a typo because the name of the function does not match that Display_image != DisplayImage

so that could be an issue.

To make certain that it is not and you are exporting your function from the delphi dll correctly, go to your Visual Studio folder and pick the sub folder in there called "Visual Studio tools", in that folder is a program called depends. Start it. Pick from the file menu, Open. A common dialog to select a file should appear. Navigate to the location where your dll is. Click on the dll and click 'open' button (or dbleclick file item). The result should be that a window appears with a treeview pane on the left. It shows you the dll and all dlls that your dll uses (surprise!).. to the right of that pane (like window pane), you should see 3 other windows the one in the middle lists your exported functions - if there are no items in that window, then you have not exported your function correctly. If it is in there, then you've done it right.


as far as the function on the visual c++ side goes, yes, you should be using double*

and call the function like so:  DoIt( &mydblVar )
making sure you are passing a pointer to the double - so that your dll can change the data you pass it from your application.


as for where I am it was 74 degrees today, but we have been having ups and downs. 2 weeks ago we had a couple of inches of ice....(which is unusual) There are some days I wear short sleeves and others I wear my sailor jacket...
Time zone, looks like it's 12:47 your time (March 6) and 9:00pm my time (March the 5th)... so i guess your a few hours ahead.

oh well, talk to you later,
sincerely,
J


0
 
LVL 12

Expert Comment

by:Salte
ID: 8078288
How does the declaration looks like on the C++ side?

I would assume that

var foo: Double

would translate to

double * foo

in the argument list. However, that also means that the caller must call it as a pointer:

double x;

DisplayImage( ...,&x,...);

If you try:

DisplayImage(.....,x,....);

you will get error on the MSDEV side.

I am also uncertain about the boolean data types, if they are compatible or not. Is sizeof(bool) in C++ side the same as the size of Boolean on the Delphi side?

Alf
0
 

Author Comment

by:iceblue_22
ID: 8078520
Hi J,

please stick around as i am sure to get back to u on how wht u'll asked me to do went......this is gonna be tuesday....is there a way I can send the query directly to you?

actually I am getting a cold right now...very bad for my singing...but yeah...

later,
ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8080517
Alf

good suggestion about using the double* - just what I suggested too.

as for bool, boolean works on the delphi side.

IceBlue_22 -
I'm in meetings today, but 'listening'.. this has been going on quite a long thread if I do say so myself.

if you want to send me an email is that what you mean by a query, search the web (google) for a Company called "Ideal Software Inc.", there should be an email link there... I don't provide it here because of spammers. ok? ... also I mentioned my name in the post where I was talking about unix and the mac.

oh singer eh?  I play guitar and a few other things, so I don't have to worry about the colds (heh heh)

As my mom always says "Drink plenty of liquids and rest"
free advice.

sincerely,
J
0
 

Author Comment

by:iceblue_22
ID: 8085138
Hi J,

yups this has been going for quite a while...and I throughly sympathize with you abt putting up with me.....but I do belive that once I put in the changes that both urself and Alf have given me.....it'll all be good....plz let it be!!!

Guitar??...how long have u been playing tht??....I have been singing for the past 14yrs....its all good.....plenty of liquids is all good but rest ain't possible by me.....

have a good wkend......later..

ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8085276
Is it already the weekend? geeze...

Glad to help out if I can and I can get the time to... and the person is appreciative... so far all conditions are being met, so no problem.. but thanks for being appreciative, I appreciate you being appreciative .... heh heh like "Help me to help you" [Jerry Maguire] ....

Guitar oh how's about 22ish years. I've been writing songs about the same time too... yep that's the "other side of me" a musical creative type... one of these days I'll put up some mp3s of some tunes I've written and performed..

have a good weekend and if you want to write me directly, look me up.

J
0
 

Author Comment

by:iceblue_22
ID: 8092564
hi J...

wow thts cool...never been confindent enough to write my own songs...send us some of the mp3's when they're done....maybe I should try now.....

but hope u have a good weekend.....btw can't find anything on ur company(will try again)....

later...probably tuesday...
ice
0
 

Author Comment

by:iceblue_22
ID: 8106974
HI J,

well it compiles...but crashes when I use then funstion to open my image.....I don't understand where the problem stems from.

this is how I am calling the function:
{
/*DLT_DisplayImage Display_Image_dll = NULL;
                    Display_Image_dll(false, false, 0, 10, 0);*/

                    HINSTANCE hinstLib;
                    DLT_DisplayImage Display_Image_dll = NULL;
                    BOOL fFreeResult;
                    BOOL fRunTimeLinkSuccess = FALSE;

                    //Get handle to the DLL module.
                    hinstLib = LoadLibrary("sappdll.dll");

                    //If the handle is valid try to get the function address.
                    if(hinstLib != NULL)
                    {
                         //this points to the function address
                         //note the name is case sensitive
                         Display_Image_dll = (DLT_DisplayImage)GetProcAddress(hinstLib,"DisplayImage");
               
                         //if function address is valid, call the function
                         if(fRunTimeLinkSuccess = (Display_Image_dll != NULL))
                         {
                              BOOL lUpdateCon = false;
                              BOOL lForceDraw = false;
                              int lSlice = 0;
                              double lInWinWid = 10;
                              double lInWinCen = 0;

                             
                              BOOL* plUpdateCon = &lUpdateCon;
                              BOOL* plForceDraw = &lForceDraw;
                              int* plSlice = &lSlice;
                              double* plInWinWid = &lInWinWid;
                              double* plInWinCen = &lInWinCen;

                              Display_Image_dll(*plUpdateCon, *plForceDraw, *plSlice, *plInWinWid, *plInWinCen);

                         }
                         //free the DLL module.

                         fFreeResult = FreeLibrary(hinstLib);
                    }
the typedef is as follows:

typedef void (WINAPI *DLT_DisplayImage)(BOOL* lUpdateCon,
             BOOL* lForceDraw,
             int* lSlice,
             double* lInWinWid,
             double* lInWinCen);
and the delphi declaration is:

procedure DisplayImage(var lUpdateCon: boolean; var lForceDraw: boolean; var lSlice: integer; var lInWinWid :double; var lInWinCen: double); stdcall;

I have done exactly as you have advised......know I am unsure about whether the problem is with the program or the files themselves.

I knw this is probably not something you can help me with as u don't have acess to all my code. However if you see something in what I have done tht could perpetrate the problem please let me know.

thanks....btw everything you have said so far has helped...
Ice
0
 

Author Comment

by:iceblue_22
ID: 8107470
HI J,

well it compiles...but crashes when I use then funstion to open my image.....I don't understand where the problem stems from.

this is how I am calling the function:
{
/*DLT_DisplayImage Display_Image_dll = NULL;
                    Display_Image_dll(false, false, 0, 10, 0);*/

                    HINSTANCE hinstLib;
                    DLT_DisplayImage Display_Image_dll = NULL;
                    BOOL fFreeResult;
                    BOOL fRunTimeLinkSuccess = FALSE;

                    //Get handle to the DLL module.
                    hinstLib = LoadLibrary("sappdll.dll");

                    //If the handle is valid try to get the function address.
                    if(hinstLib != NULL)
                    {
                         //this points to the function address
                         //note the name is case sensitive
                         Display_Image_dll = (DLT_DisplayImage)GetProcAddress(hinstLib,"DisplayImage");
               
                         //if function address is valid, call the function
                         if(fRunTimeLinkSuccess = (Display_Image_dll != NULL))
                         {
                              BOOL lUpdateCon = false;
                              BOOL lForceDraw = false;
                              int lSlice = 0;
                              double lInWinWid = 10;
                              double lInWinCen = 0;

                             
                              BOOL* plUpdateCon = &lUpdateCon;
                              BOOL* plForceDraw = &lForceDraw;
                              int* plSlice = &lSlice;
                              double* plInWinWid = &lInWinWid;
                              double* plInWinCen = &lInWinCen;

                              Display_Image_dll(*plUpdateCon, *plForceDraw, *plSlice, *plInWinWid, *plInWinCen);

                         }
                         //free the DLL module.

                         fFreeResult = FreeLibrary(hinstLib);
                    }
the typedef is as follows:

typedef void (WINAPI *DLT_DisplayImage)(BOOL* lUpdateCon,
             BOOL* lForceDraw,
             int* lSlice,
             double* lInWinWid,
             double* lInWinCen);
and the delphi declaration is:

procedure DisplayImage(var lUpdateCon: boolean; var lForceDraw: boolean; var lSlice: integer; var lInWinWid :double; var lInWinCen: double); stdcall;

I have done exactly as you have advised......know I am unsure about whether the problem is with the program or the files themselves.

I knw this is probably not something you can help me with as u don't have acess to all my code. However if you see something in what I have done tht could perpetrate the problem please let me know.

thanks....btw everything you have said so far has helped...
Ice
0
 

Author Comment

by:iceblue_22
ID: 8107781
HI J,

well it compiles...but crashes when I use then funstion to open my image.....I don't understand where the problem stems from.

this is how I am calling the function:
{
/*DLT_DisplayImage Display_Image_dll = NULL;
                    Display_Image_dll(false, false, 0, 10, 0);*/

                    HINSTANCE hinstLib;
                    DLT_DisplayImage Display_Image_dll = NULL;
                    BOOL fFreeResult;
                    BOOL fRunTimeLinkSuccess = FALSE;

                    //Get handle to the DLL module.
                    hinstLib = LoadLibrary("sappdll.dll");

                    //If the handle is valid try to get the function address.
                    if(hinstLib != NULL)
                    {
                         //this points to the function address
                         //note the name is case sensitive
                         Display_Image_dll = (DLT_DisplayImage)GetProcAddress(hinstLib,"DisplayImage");
               
                         //if function address is valid, call the function
                         if(fRunTimeLinkSuccess = (Display_Image_dll != NULL))
                         {
                              BOOL lUpdateCon = false;
                              BOOL lForceDraw = false;
                              int lSlice = 0;
                              double lInWinWid = 10;
                              double lInWinCen = 0;

                             
                              BOOL* plUpdateCon = &lUpdateCon;
                              BOOL* plForceDraw = &lForceDraw;
                              int* plSlice = &lSlice;
                              double* plInWinWid = &lInWinWid;
                              double* plInWinCen = &lInWinCen;

                              Display_Image_dll(*plUpdateCon, *plForceDraw, *plSlice, *plInWinWid, *plInWinCen);

                         }
                         //free the DLL module.

                         fFreeResult = FreeLibrary(hinstLib);
                    }
the typedef is as follows:

typedef void (WINAPI *DLT_DisplayImage)(BOOL* lUpdateCon,
             BOOL* lForceDraw,
             int* lSlice,
             double* lInWinWid,
             double* lInWinCen);
and the delphi declaration is:

procedure DisplayImage(var lUpdateCon: boolean; var lForceDraw: boolean; var lSlice: integer; var lInWinWid :double; var lInWinCen: double); stdcall;

I have done exactly as you have advised......know I am unsure about whether the problem is with the program or the files themselves.

I knw this is probably not something you can help me with as u don't have acess to all my code. However if you see something in what I have done tht could perpetrate the problem please let me know.

thanks....btw everything you have said so far has helped...
Ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8107902
this line shouldn't be this:

Display_Image_dll(*plUpdateCon, *plForceDraw, *plSlice, *plInWinWid, *plInWinCen);


Do you want to pass in to the function the number which you are pointing to or the address of the variable which you are pointing to?

I think you want to allow the function to change the value in the variable, so it's probably the address of the variable you want to pass in. It should be this:

Display_Image_dll(plUpdateCon, plForceDraw, plSlice, plInWinWid, plInWinCen);


Let's talk about this a minute:

Suppose you have a pointer to an int.

int* pi = NULL;   // init to null
int num = 42;

// to point to that number you do as you did above
pi = &num;  

pi now points to the address where the variable num is located in memory.

so, if you say this:

*pi    // says "get me the data the pointer is pointing at, in this case it's 42

pi     // says "get me the address of the variable
       // in memory (which contains 42)

So, how does your function compile and work (well ok, it blows up)...

since you are dealing with numbers

Display_Image_dll(*plUpdateCon, *plForceDraw, *plSlice, *plInWinWid, *plInWinCen);

this probably compiles and works - because C/C++ thinks "Hey ice is passing in some addresses to me (addresses can be long vars), so I'll try to process that"

but what you are passing into the dll is the numbers that the pointers are pointing to NOT the address of the variables which the pointers point to.

I hope that makes sense and in no way is it meant to sound obnoxious, It isn't meant to, I'm just trying to explain it with an example so that it is clear (maybe easy to understand?) ... I mean 'easier' to understand, I don't think anyone should say this stuff is easy...


Hope that helps.
J
0
 

Author Comment

by:iceblue_22
ID: 8108340
HI J,

nopes I take no offence in you stating things as easy to understand as possible...only hope this isn't driving you crazy.

if there is no need for the * infront of my inputs while calling the function, I can just do wht u said earlier and wht I was doing myself. The problem is when I don't have this is just comes back with an error saying you can't pass a double* as a double and a int* as an int. In an errot to tackle this I changed the code to make sure only ints/doubles were passed into the dll func.

So when I change it to this:
Display_Image_dll(plUpdateCon, plForceDraw, plSlice, plInWinWid, plInWinCen);

then I get the following error:
error C2664: 'void (bool,bool,int,double,double)' : cannot convert parameter 5 from 'double *' to 'double'
        There is no context in which this conversion is possible

wht could the problem be?

Also I knw I asked earlier but my method of registering the dll in correct rite? using the LoadLibrary and Getprocaddress..??

thanks dude,
Ice
0
 
LVL 2

Expert Comment

by:BorlandMan
ID: 8108933
ok,

by the way, instead of doing this:


BOOL* plUpdateCon = &lUpdateCon;
BOOL* plForceDraw = &lForceDraw;
int* plSlice = &lSlice;
double* plInWinWid = &lInWinWid;
double* plInWinCen = &lInWinCen;

Display_Image_dll(*plUpdateCon, *plForceDraw,
   *plSlice, *plInWinWid, *plInWinCen);

you can do this if you want:

Display_Image_dll(&lUpdateCon, &lForceDraw,
                 &lSlice, &lInWinWid, &linWinCen);

onward.

you mechanism for calling it is correct, you do a LoadLib(),  you check that the pointer returned is ok, you then do a GetProcAddress() and you check that the pointer is non null before daring to use it <g>


on the double bit, your error says:

error C2664: 'void (bool,bool,int,double,double)' : cannot convert parameter 5 from 'double *' to 'double'
       There is no context in which this conversion is possible

Notice it says "convert parameter 5 from 'double *' to double' .... but isn't param 4 also a double?? How come it doesn't complain about that conversion?

I will send you a sample via email, watch for it.

hth,
J




0
 
LVL 12

Expert Comment

by:Salte
ID: 8109402
I noticed that the typedef didn't have __stdcall while the Delphi had it.

_stdcall is not the default for C so you must specify it if you want it. Try

typedef void __stdcall (WINAPI *DLT_DisplayImage)(BOOL* lUpdateCon,
            BOOL* lForceDraw,
            int* lSlice,
            double* lInWinWid,
            double* lInWinCen);

I believe that is more comparable to the Delphi declaration.

Alf
0
 

Author Comment

by:iceblue_22
ID: 8109789
Hi alf...

is tht so?....I didnt realize......will make the change.

Hi J...

The error is repeated for both doubles and also for the int param.

I did get the stuff thanks(via email)......but I might not be able to have a look at it for a while as I earlier thought.....I just ain't cut out for full time uni and part-time work!!!!....

anyways I will try to defintely look at it before tuesday.....and of course let you knw....

take care...and hope there is a benevolent soul looking out for you as well...

ice
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
Suggested Courses

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question