[Autogenerated] Okay, so let's open Visual Studio again in the previous demo,
we didn't do anything specific or anything special but in
fact create process this executable was also created and
depends on various DLS for example,
we call the create process W function which is implemented somewhere.
And so if I go ahead and in fact go to the Explorer,
just simple Explorer and get to my executable here.
Here it is.
I can drag it to a one of these total p Windows let's do that.
And you can see information about that executable dot p
which of course has a bunch of imports, you can see here,
we have important kernel 32 from that.
We're actually calling the create process W function.
So create process W here is implementing kernel 32 notice,
APIs are not used by default.
We also use some functions from the C.
Runtime.
Either directly or indirectly.
It might be used by C.
runtime other libraries or other dealers in the process.
So we can see those here as well.
And we're also depending on some more functions here
for the from the universal C runtime.
And so in general, the purpose of the C.
Runtime is to provide some functionality that is expected by developers,
for example, the main function as we've seen.
Uh Well at least I I said that it is actually being called by the C.
Runtime.
Let's see.
So if we go back to this application here,
don't really, I'm not really interested in exactly what's happening here.
Just I want to show you the C.
Runtime here,
so I'm going to run into this breakpoint and let's look at the cold stack,
the call stack says create process dot txt main and then there's external code.
So normally,
Visual Studio doesn't show you that code that it's not part of
your source code here in the cold stack,
but you can right click and request to see that external code,
you can see the external code is coming from something else.
The call stack shows a few calls coming from the C runtime and in fact the
C runtime source code is provided with visual studio,
so it's perfectly legitimate to just simply double click and
see what happens in every single call.
So you can see here this is calling a function called invoke main,
which is still part of the C.
Runtime.
And that function is in fact the one that invokes our own Main.
And so what is the role of the CIA?
runtime anyway, why do we need it?
One reason is to set up various global variables that are needed for
certain function implementations that are part of the C.
Standard.
Another thing is the need to call constructors for global objects.
If you create C++ objects and make them global,
their default constructors will not be executing or any
other constructor for that matter,
unless we have a C runtime or something that does that.
This is definitely not automatic.
So this is another reason to see runtime is necessary
only then our main function is called.
So let's stop that and see what happens when we create our own DLL.
So I'm going to right click the solution node here and use add new
project to add a new project to this solution.
I'm going to use the Windows desktop wizard here to
create Dll to make it a bit easier.
So let's call that Simple Live or something or just Simple.
Well, simple library will do and create.
So I'm going to select the DLL here and I'm going to export a few
symbols just to make it easier to get started.
You can also use the pre compiled header if you wanted to but it
doesn't really matter for this particular example.
Let's do a Okay here,
you can see that we have a few files created in this new project.
One of them is a file containing DLL main function that will take a look
at in greater detail later on in this module for now,
in simple library we have a declaration here for a class and for
some function and it's done by using some macro here that is
going to be using this declaration,
specify their export here that tells the C++ linker to
export that function outside of the library.
So I don't care about the class here.
Let's just do something as simple as we possibly can.
I'm going to create a very simple function called ed.
Sorry for being a bit battle here and let's just create a function
that's going to add two numbers and returns integer.
Not very exciting.
I know, but let's do that anyway,
so there are some stuff here that we just get rid of those
and just implement our own function here,
which is called ad accepting two values here and does something.
This case will simply return the sum of A and B.
If I go ahead and build that, it should build fine.
So we have a DLL.
Great.
Now we want to use it in some client application.
So let's create yet another project in this solution.
This is going to be a simple console applications.
Just select one of the old ones that we did already.
So you can call that something like a simple test.
So this simple test will try to test the simple library.
DLL and so what I can do here, at least I want to start with something.
So let me just include S T i O here and then I need to include the header
file where we have our declaration of the function.
That will make it easier.
Of course we can just copy the declaration itself.
But let's just include the simple library header right here.
And simple library is the one that contains our add
function with the declaration specify which is going to
be export for the DLL and import, which is essentially not needed.
Uh read for for the client for the one that's importing
that function wants to use that function.
So if I go ahead and decide to add some code to use that, let's see if it works.
So I'm gonna do something like this.
Like result equals and I'm going to call the add function.
You can see what the studio picks up the
intelligence here and provides the values.
So let's go with five and eight.
Let's just display the result to the console in a simple print.
F call.
And essentially we're done.
Let's try to build this.
If I build this, we'll see that the code compiles fine but we get a linker error.
That link error says, hey, there's a function called Ed.
You say that exists, but I don't see any implementation for that function.
So that's in fact the problem.
We have the header fire but the header file is nothing.
It just provides the prototype for the function.
What it actually does is hidden inside DLL.
But the link has no way of knowing that we have in dependency on
this detail because currently we actually don't.
So how do we add that dependency?
The simplest way of doing that with visual studio is to go to
the references in the simple test project.
Right click and then select,
add reference that way we can add the reference to the project,
which is essentially adds the leap file generated by the compilation.
You can see simple library dot leave is here.
It's a very small file, that's the one that contains the the name of the DLL.
Just the name without any path and the list of exported symbols,
which in this case should be just the function add.
And so if I do that by adding that as a reference,
it will actually add the lead file as a dependency and
which means that at runtime the loader will have to figure
out where that that deal is.
And now if I build that, it compiles just fine.
And if I run it,
let me make this project the startup project and just press control of five,
we'll see that it should run just fine.
We can see the result of 13.
We can even set up a breakpoint here and run with the
debugger pressing F five and if I do add,
we can drop by pressing F 11 step into we're stepping
into the functions implementation,
we can see here that in fact A and B have the value that we
expect and the call stack shows the execution of the add
function inside the library.
So obviously the library has been loaded into the process address space.
We can also see that individual studio by using another window here,
which is called the modules window.
So here it is,
let me just drag it to a more convenient location and you should see
that simple lib is here simple I browse is here,
it has to be here because it is a dependency going back to our explore here,
let's drag this executable now that exists.
This is simple test dot txt which now exists,
we can drag it to a total P here, see what we get now.
If you look at the import, you notice the simple labrador.
Dll is a dependency and here's exactly the ad functions is
exported and in fact imported as well.
So we're using that function here.
If you look at the Dll itself, which we can do of course.
So let's just grab the simple library dot dll.
We can say it has some import.
So it depends on other stuff such as the C.
Runtime, but it has a single export.
And this is our add function.
You might be wondering why do we have these crazy
looking like the decorations here?
This is known as name mangling.
That's because the function is currently exported as a C++ function.
And the C++ function.
It has um these decorations because in C Plus plus we have function overloading,
which means we can have any number of functions called ed
that might accept different parameters.
And so the compiler Lincoln have to provide some kind of way to
distinguish these various potential function that might have the
same name and different parameters.
So the name itself is not good enough as a way to make that distinction and
we'll see what that means very soon when we do explicit linking.
So obviously we have that kind of dependency.
So now if I go ahead and delete this deal,
let me just delete it and then let's open a command window and run it again.
So I'm going to do the running now from the command window and that's
because if we try to do that through Visual Studio you will notice that
the deal is missing and will recompile it.
So I don't want that to occur.
So let's go to our debug Director of course we have not a very good
name for the solution but we'll keep it here anyway.
You can see all the executable czar here.
Let me run simple test and we get that same error dialog box
we've seen in the slides it says well,
I tried to look for simple library and I just couldn't find it.
I just couldn't find it in any of the search locations.
And so we know that the Director of the executable is one of the
first in fact it is the first location to be searched in the
file system and the library is nowhere to be found and not in
any other directory either.
And so we fail.
Now the other way of of doing that of making that import and known if we don't
have a reference here is to add the leap file specifically.
So let me build that again.
Now that I've removed the reference, we no longer can link the executable,
let's go to properties and here in the properties we can select all
the platforms and all configurations because we need that for all
various configurations and platforms.
When you compile this executable perhaps in the future version we
need to go to the linker here to the input and here you can see
there's additional dependencies and here's where you can add
dependency for simple library dot lib.
Now we have to be careful in terms of of the actual path
because the linker might not be able to find it.
And so if you build that you can see it says,
well I can't open simple labor dot lib because apparently
it's not in the directory of the project,
which is of course correct.
So we have to kind of look that up somehow.
And so we, we can, we can try this in several ways.
We can um well I actually know that it is somewhere here
so maybe we need to go back and that file might be in more
than one location actually.
So we have the lead file here,
but maybe you can find that in a different location in
the simple library directory itself.
Let's go to x 60 foreign debug and uh we might find it
here and apparently it's not here,
it's only put there by default in the output directory.
So we have to be more specific here.
Doing something like X 64 debug and simple library of obviously this is
not ideal because you have to to put the correct path and for debug and
release is going to be different and it's possible to to fix that because
there are these environment variables, so to speak.
That Visual Studio supports such as the configuration type,
so it can change,
in fact debug to something like configuration uh or something like this and it
should work in essentially the same way you can see we built successfully and
if we go ahead and run and of course it would run successfully in this case we
have the results of 13 working for us.
There is yet another way to do that to make these changes
here without using the project properties.
So I typically like doing that if it's not something I can
uh provide directly in visual studio,
it's been using a pragmatist with a lip magma.
So here I can go to uh X 64 debug and simple library dot lib.
This is what we need the lib file only and that should do the trick.
Um well I guess maybe not.
Let's see of course I put that in the wrong location,
this is the deal itself,
we have to put that Uh in the client application obviously,
so here's something like this, that should work in exactly the same way,
but again it makes it a bit more fragile because now I have to
look at the bug and release maybe X-86 as well,
so I can do these things by examining the debug compilation constant.
So yes, it would work.
I can definitely go ahead and and do that and point that to the release folder,
if I'm going to do a release build here,
which I can by changing the bag to release and rebuilding that again,
but obviously it's a bit inconvenient.
So the best option really today with visual Studio is to add that as a
reference to the to the solution to the project in this case.
So this is implicit linking, this is how you link to the DLL up front,
you know,
you want that dependency and you can't run your
application without that dependency,
that's the point here without the dependency.
That will simply not work.
And uh this is what you do for most of Microsoft's binaries,
but for your own DLS you might may or may not want to use this scheme,
you might want to load the Dll perhaps later on and not initially when
the process comes up and if the DLL is not found,
maybe you don't want to _____.
So for that we can use explicit linking linking,
which is going to be the topic of our next video