 Hey everybody, this is Brian and welcome to the 100th Qtutorial with C++ and GUI programming. It's been a long road, but we've made it. 100. Today, we are going to cover QPluginLoader. What is QPluginLoader? Actually, what is a plug-in? Well, if you go out into the documentation and read QPluginLoader, you'll find that QPluginLoader loads plug-ins. Well, doesn't really help us a whole lot. So what is a plug-in? A plug-in is kind of down the same alley that we've been tracing, which is a DLL, or an SOFU in Linux and Unix, a system object. So let's say you have an application like Qt Creator, and you want to make a plug-in and you want to extend the functionality of this application. Let's say this help menu. Each one of these is a plug-in, and when you click it, it does something specific. For example, if we click about Qt Creator, it shows this window. But if we click about plug-ins, it shows this window. So they do the same thing. There's probably a show window function in there somewhere, but they show two totally different windows, a.k.a. they do different functionality. Now, I've come under some criticism in the past that I spent a lot of time talking and typing and trying to fix mistakes rather than teaching. So we're going to just dive into some code I've got pre-written here. And if you guys like this format, we'll continue down this road. Now, we've got a plug-in and an application that uses that plug-in. The first thing you know, I should say the first thing you should notice is that we have this plug-in interface .h. This is a virtual class. First off, what's an interface? An interface is a contract. For example, let's think of a key as a contract. You put your key into the door and it turns a lock. That's a contract, meaning you have to have that key to open that lock, or a very big sledgehammer, but we won't get into that. So an interface is just a contract. And it's virtual, meaning we don't actually implement any of this. You know how it says virtual and then const equals zero, because we're not implementing it here. We're just designing the interface. This is what all plug-ins will have in common. They will have a function that returns a q-string called name and a function that returns nothing called do something. You should also notice this q-declare interface. Right here is where we're declaring this plug-in interface class as an interface, and it's got a string, and that might look familiar for some of you that work with COM. I just use my domain name backwards with the application and then the class name with the version, but you can put pretty much anything you want in there. Now the actual plug-in is a lot simpler than you might think. Notice how it includes q-plug-in. That's a very big one. It uses acute interfaces macro and uses the plug-in interface. There we go, the plug-in interface dot h. And it also inherits q-object and plug-in interface. So this is both a q-object and a plug-in interface, but you should note that plug-in interface is not a q-object. I've had no luck getting an interface as an object. They're designed to be virtual and you can't have this dual inheritance thing. So if you want to make a plug-in that has signals and slots inside of it, you're going to have a lot of work because I haven't gotten it to work yet. Anyways, back to my plug-in class. It's q-object. It uses q-interfaces to say, hey, use this interface. And then it implements the interface. We've got our name and do something functions. And when we go in there, we can see how very simply it just returns strings. So we could have a bunch of plug-ins. Let's say they all have different names and they all do something different like return on mathematical function value or something like your age divided by 12 or something like that. One thing you should note right here is this q-export plug-in 2 with the name my plug-in and my plug-in. That's the target and the class. It's very important that these match perfectly. Not these two specifically, but these match up within the project. This first one, the target, needs to match in your project file. Target equals. That's where it's going to be right there. And the other one is the class name, my plug-in. So if those two don't match, you're going to get some weird errors. It'll compile and then when you go to load your plug-in, it'll just pop back a bunch of funky errors. I couldn't find it, etc, etc. And the only other special thing is in the project file, you notice the template is a lib or library. That's a DLL and Windows or an SO and Linux. And the config, we have it as plug-in release. One thing you should know about the q plug-in loader is it does some things like version checking. It'll make sure that the plug-in is the same version as your application and it'll make sure that it's got direct access and a few other things. I mean, you should really read the documentation, get a full description of this, but we're going to cover the basics of it. So let's just give our plug-in a good compile. Alright, now that we've got that in there, let's look at the output directory of that, our application. We've got a special folder in here called plugins. And then we've got the DLL we just compiled in there. So that's where it's going to be looking for it. Let's just jump down into our application here. Whoops, close all these. Now you notice how the application also has plug-in interface. The exact same file. The reason being is the application and the plug-in have to adhere to the same interface because the application has to know what's going on inside this plug-in. It has to know that there is a function called name, any function called do something. Now in our application, very simply, I have a class called app class and a function called load all plugins. So when we go into app class, you can see it's very simple. Just two functions, load all plugins and load plug-in with a file name. And it has, of course, Q plug-in loader and plug-in interface. Now load all plugins, just looks for the plug-in directory I just pointed out and goes through and gets every file and then tries to load the plug-in. Now in the load plug-in function, this is where the magic happens. What we do is we create a Q plug-in loader, give it the file name and then we say get an instance. What that does is it loads it in memory and it tries to create an instance of that plug-in. Then we say if possible plug-in, in other words, if this pointer here is greater than zero, then we do what's called a Q object cast. Sounds very complex, but really all it does is a cast, it turns it from just a normal Q object into what we tell it to, in this case the plug-in interface. Remember that interface is the contract. So now that it is an interface, rather than an object, we can do things like plug-in name, plug-in do something. Now if we go back out to our plug-in here, and when you see we say plug-in do something, if we look this up, it's going to just print out do something really cool here. So if we run our application, you'll see the current path is, and then it'll say loading and it finds the plug-in, the .dll file, because I'm on Windows, and loaded my plug-in version one, there's the name, and then it calls do something, which prints out do something really cool here. Now that in a nutshell is how plugins work. Once again, just to review some of the pitfalls you need to remember. You need to have an interface. This interface has to be virtual. In other words, the virtual class, you have to implement that interface. And you have to use the Q declares. Be sure to include Qt plug-in. You implement your interface here. And then you have to do a Q export plug-in to that way Q compiles us as a plug-in. And it does all the special magic in the background. So you don't have to worry about exporting macros and exporting functions and things like that. Everything's just done for you. Now, I know you're probably thinking, that's it. This is the 100th video. I thought we're going to do something cool. Well, there's a reason why it's taken me so long to get here. This is plug-in service, an application that I've been working on for a while now. Should probably back up. Why do we program? Well, unless you're getting paid to program, you program to solve a problem. I run void realms. And I have a side project called laptoplocator.net. And no, I'm not trying to say anything. I'm just going on my little spiel here. What laptop locator does is it's a Windows service that sits in your computer. You don't even have to be logged in. And it contacts this website in the background is this ping here I am here's my IP address. And then it looks up the IP address does a geo reverse geo coding. So it says this IP address is here. And I can tell you basically, you know what city and state you're in. And getting the IP address, you can obviously tell the provider, etc. etc. helps people find lost laptops. Now, the problem I have with this is if you go to the services, it's Windows only. Yes, this Mac sorry, some coming soon Linux sorry, coming soon. It's Windows only because I wrote that in C sharp but not. So that was my first hurdle. I wanted to make this cross platform. So I researched Python or research Java Ruby a few other languages and they just they were good at what they did but they weren't quite what I was looking for. And that's when I found cute. And like many of you I resisted learning C++ and I probably toss that beginning C++ book across the lawn about a dozen times until it finally sank into my brain. And then I went out and I grabbed some other books like I have the advanced cute programming really good book. I'm looking forward to finishing it. C++ GUI program with cute for that is a very good beginner book. I just got the introduction to design patterns of C++ with cute seems to be an excellent book but I have not read it yet. So don't take my word for it. And foundations of cute development. This was an awesome book. I love this book. Now, no, I'm not getting paid or any sort of royalties for mentioning this. I'm just giving credit where credit's due. Some of the source code for these tutorials actually found right in this foundation of cute development. They have a chapter on plugins that I would recommend you buy the book and read it. But anyways, back to the point I was making here. laptop locator I wanted it to be cross platform. And I wanted it to have an extensible architecture meaning I wanted it to have plugins. Because I get all sorts of weird requests. Well, I want to access my file remotely. I want to turn the webcam on and take a picture of who stole my laptop. I want to format the hard drive and encrypt my files download my tax returns, you know, just all these things. Well, to keep up with these requests, there's an easy way and a hard way of doing it. The easy way is you just well, keep modifying your program and updating it. The hard way is you keep modifying your program, keep modifying your programming, updating it. But there's a much better way obviously. It's using plugins. That way you have an application. And then you just distribute the plugins and update the plugins as needed. So what I've done here is I've created this plugin service and really a service. There's no real magic behind it. It's just a normal command line program. You can just use the windows SC command to convert it into a Windows service and install it. Something we're not going to really cover, but you can look that up on Google. What this plugin service does, let's actually jump down. I got a test plugin here. You notice the same thing. It's a plugin interface. Just much bigger, has a lot more functions in it. It has a name, description, status, can trigger install so you can install a plugin remotely, uninstall it remotely, start it, stop it, list commands. For example, you can have a plugin, I don't know, like rename files or delete a directory or whatever you want it to do. You can exact those commands, execute them. So you can give it a command and a list of arguments. Same thing though, it's got the declare plugin interface, etc, etc. And then the implementation is very similar to what you saw. It's just got a lot more in it. Like the install code goes here, start code, stop code, etc, etc. exact kind of interesting if you type in command one, it'll say you enter command one. Yay. Command two is you enter command two. How sad. Just to demonstrate that it can do different things. Now the plugin service itself. This is a bit of a monster. It took me a while to really build this thing. You can see it's got a TCP server that starts on port 1234. And this is a fine example of what I mean by this is not really production ready yet. In a production program, you would give the user the ability to change the port. So this is more of a proof of concept application. Anyways, starts the server. The server has what's called a plugin manager and a command manager. Now, the plugin manager, where is he this guy? This, the sole purpose for this class is to load plugins and then control them, start them, stop them, execute, install, uninstall, etc. And then you've got this command manager. The sole purpose of this class is very simple. It takes the commands entered by the user, converts them and do what it can understand these enum objects. So if they type in help, it converts it to the help enum, and then just does a big switch and executes everything. That's actually something we should touch on real quick here. Yeah, we use the Q meta object and Q meta enum to convert it into the actual value. And then it does a switch here in case you're ever looking to figure out how to do that. And then it has what's called a request and response object. The request is obviously the request the user sent and the response is the response back from the command manager. Whew, that's a mouthful. Now the client is created every time a client connects a server like let's look at the server here. And you see how it's creating a plugin manager command manager telling the plugin manager to load and then start. So it's loading all the plugins and then starting them starts the server. And then when a client connects, it connects the command manager signal and slots. command manager has a signal called response ready, meaning we've sent it a request it's done its magic and it pops back a response and then we send that out to the client. And then the the client has a request ready, meaning the client entered a command and we want to send that to the command manager, which then parses that request and formulates a response. So seems very complex and convoluted. But this is a design pattern you should get very good at. You want to make your classes very good at doing specific things. Don't ever make a class that does everything you want it. Keep it simple stupid. Make your classes very good at doing one specific thing. You know, one's a bit overkill two or three things. But you know what I mean? Don't throw in the kitchen sink. So this is going to be my replacement for laptop locator. And the basic shell of this is it will load plugins. As you can see, we've got the loaded CLI plugin that's going to be a command line interface, and then loaded the test plugin. It was originally named black ops. And then I changed the name to plugin service because I'm probably going to use it for a couple different projects. But you can see how it says listening. So let's just dial into this thing and see what we can do here. This is kind of the combination of a couple different tutorials. Let's just do telnet 127 001. And you see we're connected. So type help. And there is a list of commands from the server. So you see we can list, we can install uninstall start stop exact. So let's just I don't know what's just list. And those are the plugins that are currently loaded. So if we unload, and let's say CLI plugin one dot DLL error plugin not found seems I have a boo boo in there. But this is another example of what I mean by not production ready, but you can do some things here. Start all, they're all started. Stop all, they're all stopped. So if you're looking to really make a plugin program, this might be a good base or a good reference for you to go in and look and see how things work and see just how I did it. Not saying it's perfect. I'm sure as you see it has its fair share of bugs here. But it might be a good starting point for you. But this shows you the the power of plugins, if you will. See how we got CLI plugin one and test plugin one and they both say start code here. These things could do two totally different things like CLI plugin one could start a web server and test plugin one could I don't know like email, hey, this is the location of my laptop, that sort of thing. But because they follow the interface, the program can just call start and then the plugin itself worries about the details. Who's been a long, long winter, but I wanted to get this done before the New Year. So without further ado, happy New Year. I hope everybody's safe in 2012. And if you want, you can jump off to my website void realms.com go to tutorials. Click on cute. And then look for the 100th tutorial, you can just search for it or you can just scroll down in through here and find it and get the full source code for both of these applications. I wanted to thank you guys for watching and I apologize. It's taken me so long to get through my emails and stuff. It's I've had so much feedback. It's just horrendous just to try to get through it all. So if you sent me a message, I haven't got back to you. No, I'm not ignoring you. I just simply haven't gotten to your message yet. Anyways, happy New Year, everybody. And thank you for watching.