From: qdin on
Hi.

I was wondering how member function level dll exporting works.
I have an interface, and before each function I put the
declspec(dllexport) tag,
and then I implement this class in CFoo, without the declspec tag.

I compile this into a dll, and everything works fine (I can call each
function properly etc).
But when I run this dll through depends.exe, or dumpbin.exe with the /
EXPORTS flag,
nothing shows up (only static functions show up).

How is it doing this linking?
Thanks in advance,
Eric


#define DLLEXPORT __declspec(dllexport)
struct IFoo
{
virtual DLLEXPORT Func1()=0;
virtual DLLEXPORT Func2()=0;
virtual DLLEXPORT Func3()=0;
}


From: Doug Harrison [MVP] on
On Thu, 24 Apr 2008 12:40:18 -0700 (PDT), qdin <eryqdin(a)gmail.com> wrote:

>Hi.
>
>I was wondering how member function level dll exporting works.
>I have an interface, and before each function I put the
>declspec(dllexport) tag,
>and then I implement this class in CFoo, without the declspec tag.
>
>I compile this into a dll, and everything works fine (I can call each
>function properly etc).
>But when I run this dll through depends.exe, or dumpbin.exe with the /
>EXPORTS flag,
>nothing shows up (only static functions show up).
>
>How is it doing this linking?
>Thanks in advance,
>Eric
>
>
>#define DLLEXPORT __declspec(dllexport)
>struct IFoo
>{
> virtual DLLEXPORT Func1()=0;
> virtual DLLEXPORT Func2()=0;
> virtual DLLEXPORT Func3()=0;
>}

They don't show up in depends because you don't define them. Give these
pure virtual functions bodies, and they will show up in depends. Of course,
you normally wouldn't define pure virtual functions in the class that
introduces them, and thus, there's no reason to dllexport them.

--
Doug Harrison
Visual C++ MVP
From: qdin on
Thanks for the quick response.

I impelement them in a class CFoo that inherits from IFoo, so the
functions are defined there.

Your answer explains why I don't see them in depends, but not why when
I call into this dll from an app, it makes it into the appropriate
function.

in my app:

IFoo * pFoo = Factory::CreateFoo();
pFoo->Func1();

Factory is a class in my dll too.
CreateFoo is a static member func that internally news a CFoo, and
returns a casted pointer to IFoo.

When I call pFoo->Func1() it does make it into CFoo::Func1(). How does
it jump into the dll?

thanks,
Eric

On Apr 24, 3:52 pm, "Doug Harrison [MVP]" <d...(a)mvps.org> wrote:
> On Thu, 24 Apr 2008 12:40:18 -0700 (PDT), qdin <eryq...(a)gmail.com> wrote:
> >Hi.
>
> >I was wondering how member function level dll exporting works.
> >I have an interface, and before each function I put the
> >declspec(dllexport) tag,
> >and then I implement this class in CFoo, without the declspec tag.
>
> >I compile this into a dll, and everything works fine (I can call each
> >function properly etc).
> >But when I run this dll through depends.exe, or dumpbin.exe with the /
> >EXPORTS flag,
> >nothing shows up (only static functions show up).
>
> >How is it doing this linking?
> >Thanks in advance,
> >Eric
>
> >#define DLLEXPORT __declspec(dllexport)
> >struct IFoo
> >{
> > virtual DLLEXPORT Func1()=0;
> > virtual DLLEXPORT Func2()=0;
> > virtual DLLEXPORT Func3()=0;
> >}
>
> They don't show up in depends because you don't define them. Give these
> pure virtual functions bodies, and they will show up in depends. Of course,
> you normally wouldn't define pure virtual functions in the class that
> introduces them, and thus, there's no reason to dllexport them.
>
> --
> Doug Harrison
> Visual C++ MVP

From: Doug Harrison [MVP] on
On Thu, 24 Apr 2008 13:10:58 -0700 (PDT), qdin <eryqdin(a)gmail.com> wrote:

>Thanks for the quick response.
>
>I impelement them in a class CFoo that inherits from IFoo, so the
>functions are defined there.
>
>Your answer explains why I don't see them in depends, but not why when
>I call into this dll from an app, it makes it into the appropriate
>function.
>
>in my app:
>
>IFoo * pFoo = Factory::CreateFoo();
>pFoo->Func1();
>
>Factory is a class in my dll too.
>CreateFoo is a static member func that internally news a CFoo, and
>returns a casted pointer to IFoo.
>
>When I call pFoo->Func1() it does make it into CFoo::Func1(). How does
>it jump into the dll?

A class that has virtual functions also has a data structure called a
"vtbl", or "virtual function table", and each object of the class has a
hidden pointer member, the "vptr", which points to the class's vtbl. The
vtbl is an array of function pointers, and when you say:

p->f(); // f is virtual

The compiler implements it something like this:

(*p->vtbl[index_of_f])()

From the caller's perspective, this does not require the function's name to
be known to the linker. Of course, to fill the vtbl with function
addresses, the function's name has to be known to the module that creates
the vtbl. Putting this together, as long as the creational aspects happen
in the DLL, the DLL users can call virtual functions without you
dllexporting them. However, if you disable the dynamic call mechanism by
calling the function statically, e.g. by saying base::f() or
p->ClassName::f(), the linker will need to be able to find the function by
name, and your DLL will need to dllexport them in order for its clients to
call them in this way.

NB: If you're uncertain of the purpose of the vtbl, it looks like this will
help:

http://www.parashift.com/c++-faq-lite/virtual-functions.html

If you can find a copy, the ARM (C++ Annotated Reference Manual by
Stroustrup) has a good description of a possible implementation of this and
many other things.

--
Doug Harrison
Visual C++ MVP
From: qdin on
On Apr 24, 4:45 pm, "Doug Harrison [MVP]" <d...(a)mvps.org> wrote:
> On Thu, 24 Apr 2008 13:10:58 -0700 (PDT), qdin <eryq...(a)gmail.com> wrote:
> >Thanks for the quick response.
>
> >I impelement them in a class CFoo that inherits from IFoo, so the
> >functions are defined there.
>
> >Your answer explains why I don't see them in depends, but not why when
> >I call into this dll from an app, it makes it into the appropriate
> >function.
>
> >in my app:
>
> >IFoo * pFoo = Factory::CreateFoo();
> >pFoo->Func1();
>
> >Factory is a class in my dll too.
> >CreateFoo is a static member func that internally news a CFoo, and
> >returns a casted pointer to IFoo.
>
> >When I call pFoo->Func1() it does make it into CFoo::Func1(). How does
> >it jump into the dll?
>
> A class that has virtual functions also has a data structure called a
> "vtbl", or "virtual function table", and each object of the class has a
> hidden pointer member, the "vptr", which points to the class's vtbl. The
> vtbl is an array of function pointers, and when you say:
>
> p->f(); // f is virtual
>
> The compiler implements it something like this:
>
> (*p->vtbl[index_of_f])()
>
> From the caller's perspective, this does not require the function's name to
> be known to the linker. Of course, to fill the vtbl with function
> addresses, the function's name has to be known to the module that creates
> the vtbl. Putting this together, as long as the creational aspects happen
> in the DLL, the DLL users can call virtual functions without you
> dllexporting them. However, if you disable the dynamic call mechanism by
> calling the function statically, e.g. by saying base::f() or
> p->ClassName::f(), the linker will need to be able to find the function by
> name, and your DLL will need to dllexport them in order for its clients to
> call them in this way.
>
> NB: If you're uncertain of the purpose of the vtbl, it looks like this will
> help:
>
> http://www.parashift.com/c++-faq-lite/virtual-functions.html
>
> If you can find a copy, the ARM (C++ Annotated Reference Manual by
> Stroustrup) has a good description of a possible implementation of this and
> many other things.
>
> --
> Doug Harrison
> Visual C++ MVP

Thanks for your explanation. It's all very clear now.

I do have one more question, now about static function dll exporting.
Basically - if I use __declspec(dllexport), does it export by name or
by ordinal?

I have a class with only static functions in it (the Factory class I
mentioned above).
I export each of these functions with __declspec(dllexport).
So I compiled this into a dll, and a link .lib,
then compiled the link .lib into my client app.

After this, I added (and exported) another static function in front of
all other functions in the class, and compiled again.

I did NOT relink the .lib into my client application.

When I swap the new dll in, everything still works, and the proper
functions are being called.
I checked both dlls in depends.exe, and have seen that the ordinals on
some functions do change between the two dlls,
yet these functions work regardless of the dll that I use.

I guess this would imply that it exports by name in this case (?)...
but then that raises the question of why you would want to export by
ordinal in the first place?

Thanks again.

Eric