[Autogenerated] Let's see what explicit linking looks like.
I'm going to create another application here for testing purposes,
another console application,
let's call that test or very simple test to just to
have something different to look at.
And my goal is the same to call the add function that exists in the in the DLL.
But in this, in this case I don't want to link link implicitly but explicitly.
So let's start with something simple.
Let's start with S T D I O as always.
And let's try first to include our header file.
So if I do that and try to call the function,
obviously it's probably going to be problematic probably because it
will not work because it's essentially the same code we've seen
already without having the linker part.
If I go ahead and copy that here and return zero.
That will not, that will not link will get the unresolved external error saying,
well, I I can't find the add function so I want to do things differently.
So we'll we'll start with the load library function.
So with load library we can specify location for our library
add in this case include for windows dot age,
we have to be a bit more explicit here,
we have to have that definition for load library,
you can see it expects a deal and because of the L l is in
the same director is the executable than load library with
the name should be good enough.
Let's just load this DLL and the result is going to be an H instance,
which essentially is the um the address in the future
address space of the process where that DLL is being
loaded if that is returned as null,
it means that we couldn't find the DLL so or it failed to initialize.
So let's just display the error and display whatever get last error
has to say and that just returned out of this code because there's
really nothing else we can do in this case,
we don't really care about anything else except loading this DLL.
So does that mean I can now call the function ahead it here,
just like we see here.
Unfortunately, that doesn't really help anything.
So even though I can try to build this again,
it fails in exactly the same way because we have the low lab recall here.
But this is something the linker doesn't see the Lincoln
doesn't know what I'm doing at runtime.
That's just not good enough.
Instead,
I have to get the add function from the DLL itself by calling the get
proxy address API here's where I specify the instance.
Two DLL notice that the type itself is shown as a church module but H
modern H instances are all the same thing really.
And the name of the function as an ask e string.
So let's use adhere and get broke address returns a very generic pointer and
we have to to make it the correct type as you can see here.
The function get broke,
others return something which is very generic it's called far products.
Just some generic pointer.
We have to be more specific than that.
So we'll be able to call the add function in the correct way.
One way of doing that is by using a function pointer.
So if you look at the original function, it looks something like this.
And to turn that into a function pointer,
we just need to adhere a pointer like so this makes it
a function pointer now called Ed.
Let's use a small letters and because we have to use that sort of like twice.
So maybe not,
maybe we can get away with that and say that ad equals and we have to
now perform this kind of casting uh to the same type.
So it's it's kind of annoying and very inconvenient on the eyes at least.
So what we need to do here is to use a type that let me just add type def here.
So now we have a type to represent this kind of function pointer
that accepts two integers and returns run integer.
And so now we're able to use P Ed here,
let's call that ad and we can perform a casting to P ad and use get
broke address here to get the function from the DLL.
And now we're finally ready to do the work.
So if we get back a valid point,
which is not now we can call the add function here.
Notice, I'm not using the reel or the function add coming from this header.
Find fact that header file is not really needed.
He doesn't serve any purpose here.
I just want to call this function from this DLL.
So let's see if that works.
I'm not really sure that it's going to work.
In fact, I'm pretty sure it's going to fail,
but let's see why let me make this the startup project and press F5 to run it.
We'll take a few seconds to load some symbols perhaps.
And then we'll get to the breakpoint.
So here it is, let's start with load library.
Look at the modules.
Uh window here.
We shouldn't be seeing simple library here anywhere.
It's not here anywhere that dependency is not stored anywhere.
If you look at the pE file itself,
there is no reference to simple library dot Dll anywhere.
And that's why it's not loaded by default.
Now we want to load that explicitly.
So I'm going to press F 10 here to step over and you'll notice that it works.
And simple library is now loaded into the process address space.
Well, actually I'm doing release debugging here.
Let me switch that,
stop and do that again and switch to the to debug build because
it will give us more context while debugging.
It's easier to debugging.
Debug build versus release build.
I'm gonna do the same thing and it should work in exactly the same way
because the DLL is in the same directory as the executable and we know
that Lord library is searching there by default.
So simple libraries right here we got back some value which is not now.
In fact,
that's the the address of the DLL into in the address space of the process.
And by the way we can see the same things with process
exploring don't have debugger handy.
So if I look for a simple test to here,
notice the lower part here shows handles at this
point let me switch that to DLS.
Once we do that,
we can see that simple labrador Dll has been loaded into the process
address space and although I didn't prove that,
let's just do that again just to prove it and that it
didn't really exist there previously.
So let me press a five again to run the executable.
Once again, here's a simple test, Let's find it again.
You notice that at this point there is no simple library here anywhere.
But once we press F 10 we should see simple library
loading up and becoming green here.
It is.
In fact, we can go ahead and add another column here,
such as the base address into which the deal has been loaded
and that should be the same number as the one that we see in
the debugger that's the address here, seven F F eight and so on.
This should be exactly the same number and and it is so
this is the way to distinguish the little bit among all
other dealers in the process.
So this step worked as expected.
If we if it didn't we could just write some error
and get out of this application.
But we're not without crashing in a more uh I would say tragic way
that is initiated by the loader if it doesn't find implicitly linked
to the executable So now we're in the second stage which is looking up
the function add from the DLL.
So if we try the other pressing F 10, let's see what we get.
So you notice that Ed is returned as zero.
It means we failed.
And if you go to the watch window to see what's going on,
it says error product, not found indicating that the the procedure,
the function hasn't been found in in the DLL and you might be wondering
why that is but perhaps you can guess why that is.
If you go back to our Dll, let's go back to R.
D.
L.
Let me just drag it again here to total P.
Looking at the exports this export is this thing.
So the string I have to provide is this weird string
right here and not the simple name of.
And that's because we have that name mangling that I mentioned earlier.
So although it is possible to make that kind of copy
and then paste that in the code.
Obviously this is not ideal.
We might want to do something a bit better.
So for simple functions that are really C style,
we can explore them as c functions, buying,
doing a little tweak in the definition of the function here,
instead of just using whatever we have here,
export, we can add an external see here,
which tells the linker to export this thing as a C
function rather than a C++ function.
Let's see if that changes anything.
So, first, let's go to total P.
Let me reload the Dll into the tool and now go to exports again.
You notice now that the name of the export is very simply had
without any name mangling associated with it.
And that's because I'm guaranteeing here,
because I'm saying I would like to export that as a C function,
that there will be only one such function.
If I try to add another function called add to the DLL,
the compiler will fail, compilation said,
well there's,
it just can't work because you said that you're
supposed to export that as a C function.
So if you do that now, we should have a better chance of this working for us.
So if I go ahead and load the DLL that of course,
should succeed as it did before.
But now, if I do get address, you can see that actually succeeds,
we get back some pointer here And if we try to call that,
we can go into the add function and we call that and it does
what we expect uh it's expected to do returning the result of
13 and everything seems to be okay.
And so this is definitely possible to do but obviously it's a bit cumbersome.
We can make it a bit easier to some extent,
but this is explicit linking in in essence you also have to mind the
calling convention for X 64 there's just one so you don't really have to
worry about that but for X 86 there are several and you have to match the
calling convention otherwise you get stuck corruption if the function is
not called in the expected way,
one way of just simplifying this little bit we can add that include we didn't
use it but it is possible to use it as simply by doing some some work here by
using declarations specified here and saying well whatever the function ad
looks like this is the one that I want.
We can use auto here.
We can remove the type def let me just comment this out.
And so they can spec sorry, Decade type of course,
that's the c++ 11 keyword that provides us the type of
whatever we give it to it in this case.
The type of the function with the pointer and we can grab that using
the auto keyword so we don't have to repeat ourselves and it should
compile and work in exactly the same way.
So this frees us from the you need to define a function pointer,
which is never a fun thing to do.
Well.
Some people consider that fun.
That's fine.
But you might find the decade type option easier.
But of course it means you have a C++ compilation here
and you have to use C++ 11 compiler,
which of course is available with Visual Studio So running that
we should get exactly the same thing because really it is just a
compiler trick and nothing else.
So you can call the add function and and that's it.