 Hey everybody, this is Brian and welcome to the 116th cute tutorial with C++ and GUI programming. We're gonna be disgusting services. If you don't know what a service is, well, there's lots of programs running in the background on your computer and you can see from Wikipedia a window service, and there's also something called a daemon. Some people call them daemons, but I think the correct pronunciation is daemon. Anyways, they do essentially the same thing. They run in the background, but they do it totally different. That's kind of the crux with cross-platform programming is that, you know, every operating system has similar components, but they are implemented drastically different under the hood. And that's kind of one of the the issues that cute really handles very well is how to tackle the monolithic task of cross-platform programming. So, so all you really need to know is a service or a daemon runs in the background. It's a computer program like any other program. It's just called special on the operating system, meaning the operating system will start it in a different manner than it will a normal program. So of course, if it's going to start it in a different manner, we have to program it in a different manner. Well, cute at one point, actually was working on a mobility project, which I'm not sure what happened with that. But part of that was they had a service class, or I should say set of classes that turn your program into a service so it can run in the background. But as you can see here from the solutions archive, this repository contains components from the discontinued cute solutions product. Hmm, discontinued. It's nice of them to actually leave the code back up. So maybe if my internet connection wants to go a little faster, there we go. You can see there's a whole bunch of stuff like there's a browser plugged in, a lock file, a property browser, et cetera, et cetera. We're really interested in this cute service. And you can go ahead and just click the download button, download it locally, or you can just download it from my website on www.voidrealms.com. I'll have the complete source code for this and all my other tutorials. All right, so let's jump right in here. I have actually downloaded it. Given it a good build and we're just going to kind of walk through this a little bit here just to give you an idea. And then we're going to build our own service. So if you look at this, it's kind of complex. The first thing you'll notice in the project file is use lib, build lib. You can actually build this as a library that your application will use, or you can build it into the application itself. It's actually, and then of course there's the build lib. This project right here, if it's going to build the library, and they've got a common file which some of this may look like ancient Egyptian algebra, do you? Don't worry. Some of this looks like ancient Egyptian algebra to me, too. All right. Examples, this is what we're really interested in here. There's a controller, an interactive service, and a server. Now, controller, what is a controller? Controller allows you to control services. For this tutorial, really all you need to know is you really just pass command line arguments to the application. For example, a dash s will start, dash t will terminate, p will pause, r will resume. You can send a custom command with a dash c. Dash v will do a version. And there's a lot of directions in here that, you know, if you really want to spend the time, you can really get to know very well. Interactive, an interactive service is a different concept. It's a program that runs in the background, but you can still bring it up into the foreground and interact with it. That's what an interactive service is. Some operating systems don't even support this, so just kind of buy or beware on that. And if it feels like I'm kind of whipping through these without explaining them, you're right. I'm not. We're going to actually spend a little bit more time into the server. You can see from the project, it's actually a pretty simple little project. It's just including the acute service project include, which is the source. Which is this guy right here. And that's the meat of this service right here, is you'll have the project include or project implementation. And you're just setting the include path, the depend path. You're saying if it's not Windows, include network. Why? Because I believe Unix actually uses sockets to talk to their services under the hood. And then they've got a couple snazzy commands here, like we're saying, you know, if we're building the library, then do this. Otherwise, you know, include these headers. If it's Windows, include this Windows header. If it's Unix, include these. If it's Windows, include these. So they're really trying to encompass the whole, the whole spectrum of operating systems. Now, I should note that this has been discontinued, meaning there will be no further development on this, unless other people in the community decide to develop upon this. So if you're going to use this, be aware that things may change in the future that break this, you know, some Microsoft may come out with a different operating system that totally changes everything, and this doesn't work anymore. And then it's kind of on you to fix it. Doesn't mean we can't use it in the current time, though. So just looking at this, we've got some headers and we got some source files. There's a cute service, which if you read this, there's your license. And it's not very well documented. This was kind of a work in progress. But there is a lot of documentation out there if you want to go hunting for it. There's the cute service private class, meaning they call this privately. The Unix server socket, that's what the Unix systems will use to talk to the services. And then the Unix socket class. Let's close a bunch of those. And the source code, you know, as I mentioned before, it's kind of kind of deep if you want to get in there and really start looking through it. But if you open up cuteservice.cpp, you'll see they actually have the documentation in here. And you kind of read through this and figure out a little bit of what this is doing and how it's doing it. And they actually do a fairly well job. There are some features in here, like an install. I wouldn't even bother with that, to be brutally honest with you. I don't think it was fully implemented with it. You can see on a Windows account, you can pass the the account, the password, and it'll install it. Well, you can do the same thing on the command line in much less time, much less headache uninstall. Oh, and I should mention install does absolutely nothing on Linux systems. It even says right here, due to the different implementations on how services or damons are installed, Unix like systems. This method doesn't really do a darn thing. We'll actually cover that a little bit later, but I just wanted you to be aware of this. Now, if this class looks unruly and difficult to work with, well, it can be. It can be very difficult to work with. We're going to try and make that simple and easy because I like simple and I like easy. So the main functions of a service is you want to be able to start, stop, pause, resume and process custom commands. That's really all service does is it just starts and stops. Runs in the background. So we're going to collapse that whole tree and we're going to look at my service, which is a program that I'm working on right now. And as you can see, it's not much different. I mean, it's just a very simple. We've included the cute service framework. Is that a framework or just much classes? That's a good question. I don't know. But because we've included it, we've got all the source here. Same source we just looked at. And our program is for a very small, very simple. No, I'm actually going to, I lied to you. I'm going to open this back up. I want to show you something, their main file. You notice how in the server under the examples, their main file is just a big string of stuff. It's like they just wrote it as fast as possible, not knocking anybody. But I think best practices you put each class in its own file. Let's go all the way down to the main here. Here's our main function. And you say, if it's defined windows, you're doing something else. You can actually just kind of ignore that. This is the heart of it right here. HTTP service, service. And then they're passing the arguments from the main into this. And then they're starting the loop. Now you notice how this is different. It's this service that's exacting. We're in our program, a standard command line program. It's the QCore application that's exacting. The reason for that is, if we scroll up here, you can see the HTTP service class actually inherits QCore application. That's why we're going to actually implement that. And I'm going to show you a little better detail of what I mean here. So let me grab my notes because it's going to be kind of a complex little topic here. All right, so I'm just going to add new. We're going to create a class. We're going to call this myService. And I don't really want to inherit QObject. I know normally we do, but I'm not going to in this case. So here's our beautiful illustrious myService class. And we're just going to add some stuff in here. And we want to include, actually let me put it right at the top here, QCore application. Now QCore application is the event loop for command line applications. It's pretty important that you know that we're doing a QCore application here. All right, now we want to actually inherit this. So we're going to say public, QCore service. Probably help if I actually include a QCore service. And this is template based. So we're going to, I don't know if you can hear my cat in the background. I've gotten smarter about this. I've locked her out of the office, so she's out there whining. And we're going to change this constructor here to match our main. Sorry about that, I got distracted. Now we're going to change that. Good. So there's our constructor. I'm going to kind of document this as we go. And we don't normally do this, but we're going to make a deconstructor. Reason for that, if we want to really take control of our application here, we're going to make objects in memory and things like that. We'll need a place to actually get rid of those, but whoops. And I forgot it doesn't like to do that. So we're just going to copy this. Oh, how embarrassing. I actually misspelled that the constructor. It's been a very long week. My the job that I have has been experiencing network outages every day. And of course, being the network guy, they're all looking at me. Unfortunately, I don't actually have access to the equipment. It's somebody at corporate that has to do it. So that gets kind of unnerving. So what I'm typing in now is just the foundation of every type of service. You got start, pause, resume. Now we got that. Just going to document these real quick. And we're going to say start service, pause the service, resume the service. What's the difference between starting the service and resuming the service? Somebody's going to ask me, well, start is when you initially start. So you'd create all your objects in memory, things of that nature. Resume is where you've paused. So you still have your objects out in memory. Like if you have a pointer to a file or something and resume is just where you would pick back up. So like, let's say you had a timer and that timer was firing off and it was, you know, writing to a file every 30 seconds or something will pause. You'd stop the timer, resume, you'd start the timer back up. All right. So let's actually implement these guys making our little service skillet in here that you guys can reuse in any project moving forward. And I should stress this is cross platform. However, I do not know if this will actually work on like an iPhone or an Android phone. I do not know. I think they might handle those a little bit differently, but you could try it. Let me know. All right. So notice how these are all public and private. Just going to say add in any pointers. All right. So let's get rid of that annoying little thing. Let's give this a good build. Make sure it'll actually build up real fast. Ooh, no matching can function call. That's a nerving. What did we do wrong here? Oh, yes. We have forgotten to do a few things here. Namely, we have forgotten to. Cue service, Cue core application because we're inheriting this, right? We're going to pass the arguments. R, V. And you notice how there is a constant name. What is that? Well, that's actually the name of our service. So we're going to say my service. That's how the operating system will know what the service actually is. And we're just going to give this another good build and we'll make sure there's no errors. Good. So we got a clean build here. Good compile. Just because it compiled doesn't mean it actually does anything. So now we're going to make it actually do something. We're going to set the service information. So we're going to say set service description. And this is the actual description of your service. This may or may not show up in the service controllers in different operating systems, depending on what operating system you're on. Set service flags. We're going to say cute service base can be suspended. You notice how there's can be and cannot. That is the pause and resume functionality. We're going to say that yes, this can be suspended. And it's a good idea to actually let's do it. Just because I keep saying it's a good idea to do it. And then we never actually do do it. So it's a good idea to do error handling. Silly me. I must hit the wrong button there. I really do know what I'm doing sometimes. You wouldn't know it by watching some of these videos. But we're just going to just keep critical this out and say save that copy. And what I'm really building here is more or less just a skeleton that you can reuse in your programs. Copy this. No, I'm just going to kind of whip through these real quick here. Man, did I dismiss my spell? Deconstructor again. How embarrassing. Get rid of this, grab this, grab this. And we're just going to fill in the blanks here. Pause, resume, and stop. Give another good build just to make sure we didn't goof anything up. All right. So in the constructor, you see how we're inheriting. We're setting the name of the service. And then we're giving it a description and saying whether or not it can be resumed. In the deconstructor, you're going to release any memory. Like if you make any pointers to objects, that's where you just release them. You can also do it in stop and start and all that stuff. Start takes a little bit of extra work here. So what we're going to do is we're going to say qcore application, pointer to app, we're going to get the application. If you fail to do that, if you fail to do this step right here, your service will not start on Windows. It may or may not start on Linux, but Windows, it just will not start. Nothing will happen. It'll look like it's running, but just nothing happens. And that's because you're not actually entering the event loop correctly. I'm going to say qdebug, service started, service paused, resumed, and of course stopped. Now, in case you're wondering, this application isn't going to actually do a whole lot here. Let's go over it a little bit more here. We need to actually change that up a bit. Look at our little guy here. We're going to copy this out of their code. And we're going to say we're going to include my service. We're going to actually just get rid of these. So notice how we're actually replacing the default event loop with an instance of my service, the service we just created here. And our service, which of course inherits from qcore application, is actually handling the event loop, as we say service.exec. So let's give it another build here, save all. And we have a warning unused variable. Not really worried about that, but just to get rid of that, we can actually use it here. We can say qdebug, app. And we're going to get the actual path to the application. You know, what folder the application's actually started in. In different operating systems, that'll be handled differently. So like in Linux, it'll be the actual current path, the actual path of where the exe, or I'm sorry, the binary is located in Windows. It'll actually start it in C Windows System 32, or C Windows System, depending on which version of Windows. So if you have an application that's relying on the application path, it's good to grab it here. All right, so we're going to give this a good build. All right, so it runs. Let's actually run this and see what happens. See it says service started. And then there's our path right here. That's where it actually is right there. Notice how it says return to close the window, meaning this thing actually stopped. Why did it stop? Because we're not running it as a service. This is kind of the catch. Different operating systems handle this differently. There's a little explanation that you need to be aware of here. Let me jump back here. On Linux, Unix, and I think even Mac, uses something called Upstart. There are scripts that run when your computer starts. And we're just going to ls-l, etsy, etsy init. ls is just list. We're going to list in a list format on this directory. etsy init is typically where your Upstart scripts are. And as you can see, I've got some running here on this virtual machine. I've got Bluetooth, check file system, check root, cron jobs, cups, a little bit of everything here running. Now, I'm not going to really do a full tutorial on how to install services, but I'm going to point you in the right direction. I love the name of that. Whoopsie. Anyways, it'd be good to get familiar with Upstart and how it works, but I will give you a little bit of information here. Upstart scripts are, well, just that, scripts. They are just quite literally, and I'll just drag one out into the video here so you can see what it looks like. This is an Upstart script I'm working on for a program here. Quite literally, all it is, is you have the pound sign, which is a comment. You give me a description, the author. Start on. This is important. When is this script being called by Upstart? Well, I'm waiting for the file systems and the net device, or eth0, or I'm sorry, iface.lo to actually come up. You can actually start programs before the file systems even mounted. So you need to be kind of careful about that. You will start throwing some errors. Start on run level. Two, three, four, five. Run levels are different. Run levels of the system. For example, I think run level zero. You're going to shoot me for not knowing this. I think zero is actually shut down or reboot. I'm going to say it's shut down. Run zero, shut down. All right, so notice how those are commented out. Start on started network services. What's that mean started? Well, started means another upstart job named network services has run. Or I should actually call that an event. Upstart has various events. So when the network services calls the started event, Upstart's going to scan through the list of config files, see our config, and then actually start this. Stop on run level zero, one and six. So we're going to stop on system shutdown, single user mode and reboot. Console log. What that means is Upstart will actually take all your QDebug statements and pump them out to a text file. Pretty handy feature. I'll let you actually go out and Google Upstart and figure out how that happens. It's a little different on each operating system. Exec, what do we want to actually do? Now, you notice how quite literally I'm just calling a script. That's all I'm doing here. In that script, I would just simply set, you know, my local variables like my lib paths, things like that and start the application. Respawn. What that means is you're going to allow this to restart the application if it crashes. And you're going to limit this to five times in, I think, 60 seconds. So if this thing crashes four times in under a minute, it'll restart it again. If it crashes six times, it will not. You can define that. Whew, that was a handful. Upstart is actually a lot easier than the old school method. I looked into doing the old school method and it's being phased out. And I would highly recommend using Upstart. This is not an Upstart tutorial by any means. This is just a service tutorial. So you should go out and look at Upstart. Hold on, Wikipedia or whatever you use. There's a lot of information out there. Now, if you're in Windows, it's a different story altogether. Sadly, I can't keep this video and boot into Windows at the same time. But let me find my notes here. All right. Windows uses something called the SC command or service controller. You would go to an elevated command line. Let me type that out here. Elevated command line. And what that means is you're going to go to start, run, type, CMD. And then in the list of programs it gives you, you're going to right click CMD. And then run as administrator. If you don't do that, you're going to get error five access denied. Once you're in a command window, which looks very similar to this, only beyond Windows. And it'll say like C, Windows system 32. If you're watching this tutorial, I'm going to take a wild leap of faith that you know what a command line on Windows looks like. Anyways, you will run the SC command and you will say SC create. So service controller create the name of your service. So it would actually be my service. And I actually misspelled that. Wow, embarrassing. And I'm going to include this in the zip file that I'm going to throw up on my website just so you don't have to go hunt it down. Bin path is actually the path to the application. So I'm just going to swap this out as C download my service.exe. That's where it would actually be. And start equals auto. Meaning you're going to tell it to start automatically. Windows has much simpler start methods. You have manual, auto, never start, and auto delayed. We're just going to set it to auto. Now, if you ever want to delete your service, you can just say SC delete and then the name of your service. And it deletes it from the service list. The reason why you can't just take a normal EXE and make it a service is because of, well, I hate to say it, Windows. Windows has special bindings or special APIs. And if you go out to Wikipedia and read up on this, you'll see the SC command and all those things. But it has Windows PowerShell bindings. And we don't list them here, but there's a whole bunch of Windows APIs for services. And you can actually, if you're so inclined, you can go into the source of the cute service and see all the little, if it's Windows do this, if it's Windows do that, blah, blah, blah, blah. And it gets just mind boggling some of the APIs Windows has. And it just, it's very frustrating for developers. I mean, just look at some of this stuff. Anyways, but on Linux in Unix, you literally are just running a normal program. And then it is forked. And what forked means is that you are actually making a copy of that in memory. So you'll have a main program and a secondary program. And Upstart takes care of that for you. So you can literally make a normal command line program and then use it in Upstart as a service. As long as you do that config file. That was a mouthful. This is kind of an advanced tutorial. And I assume I'm going to get a lot of mail from people that just download this compiler and go, oh yeah, it won't run. Some little gotchas you need to be aware of is, well, when you go to run this, you need to have the dependencies in place. For example, if you build this and you go to run it in Windows, it's going to pop up and say, you know, cutecore.dll not found. So you're going to have to use dependency walker, depends.dxe, go out and find all the dependencies, wrap them up, put them in the same directory. One handy little tidbit I will give you is if you are tip. If you're running the service and you're not seeing anything, that's because it's running as a service. You can give it dash e for the command line arguments. And what it will do is it'll do it in executable mode, meaning it won't run as a service or to run as a normal executable. And you'll see suddenly all your Qtabug messages. That's it for all the tutorial. Thank you for watching. I hope you found this educational and entertaining. I'm going to zip all this up, throw it up on my website. So I just say I'm going to throw it up. I did. I'm sorry. I'm going to put all this up on my website. And you can use the My Service project with the My Service classes that we wrote in this tutorial to just wrap around your classes. So you would say, you know, during start, you would say, you know, myclass.dosomething. Just put that little note in there. All right. Thank you for watching.