 Hey everybody, this is Brian. Welcome to the 121st Qtutorial with C++ and Queue Programming. We have hit 4 million views on my little channel here. That's quite a bit. 25,000 subscribers. Good stuff. I like hearing from you guys. Alright, let's just dive right in. You ever wonder how some applications can run multiple instances, like Notepad. You can open a million of those things. But if you go up in a video game, only one instance of that will open. Or if you have a program and you double-click a file, it will open it in the existing window. That's what we're going to cover today. It's called single-instancing. So we're just going to make a new project and we'll call it forever alone. Just because. First thing we need to do, I don't know why you guys like watching me type. Is that even a word? Type-ist? Type-er? Type-ist? Type-e? Anyways, I've kind of gone round back and forth if I should just come with the code pre-built. Or if you guys just want to watch me type it. But I think we've talked about that before and an outstanding number of you want to watch me type it. Why? I have no idea. Alright, so we've created our application. We've created a class called single-instance. Now we need to start flushing this thing out here. The old queue-debug. You can tell it's been a while since I've done a queue tutorial. I can't type and talk at the same time. Whoopsie. Really, Brian? Come on. You can do this. A queue local server, a queue local socket. Wait a minute. Sockets? Yes. We are going to use what's called a queue local socket. Somebody out there will correct me if I'm wrong because the internet is full of experts. But when you do, I want to call it... What are they called? Namepipes, basically. On Linux, Unix, etc., etc. They are actually TCP sockets. I believe they're TCP sockets. Anyways, they might be just namepipes. But point being, with every operating system it's handled a little bit differently. That's the beauty of Qt, is you just have one object you mess around with. So let's start cranking this bad boy out here. Look at my notes. Alright, good. First thing we need to do, because this is a client server model, we're going to listen. Now you notice how I'm giving it a name and not an IP address. The reason for that is we're naming a channel. It's called a name channel. So we're just going to simply give it a name and that's what we're going to listen on. And then we're going to say bull has previous. I really can spell. I really can. Now, what we want to do here is in this has previous. This is when we're checking to see if there's a previous instance. We're just going to say, give it the name. And we also want to be able to pass a Q string list of arguments. This would be the command line argument so that if you open the... Wow, that was a horrible misspelling. Look at that. Bonus. Anyways, if you open another application and it has a file name or something like that, you want to pass that to the parent program. Alright, so let's just save that. We want to... I'm just going to make a basic signal here just to let anybody know if we have any listeners. And we got some slots that we need to play around with here. Alright, so we're going to say void new connection. I've been trying to force myself to get into the habit of documenting things as I go. Of course, if you've worked with sockets before, void ready read. Determine that, you know, there is actually data in the socket. Now, we need some variables here. Rivet, private. Q local socket, that's a pointer to M socket. Darn you keyboard. And we're going to get that from the incoming connection. Now, you would be wise to stop and ask, well, if you're just using sockets, why don't you just use normal TCP sockets? Well, because this isn't really TCP. Allow me to explain. On some systems like Unix and Linux, I think I've already said, it will actually be TCP. But on Windows or other operating systems, I think even Mac, it may not be. Well, because Mac is, you know, BSD Unix, but it may or may not be. It's operating system dependent. So some, it may be an RPC call. Some may be a memory file. Some might be a pipe. Some is just a normal socket. Qt uses IO device under the hood, so they just treat it like a socket. All right, the server. All right, good. So we've got our header, and we can start fleshing this out. So let's just start refactoring our code here. Now that we've got it pretty much in there, I'm gonna give it a good build just to make sure we don't have any little bugs in there. All right, good. We got some warnings. We'll take care of those. All right, so first things first, we want to actually connect our M server. Oops, the new connection because this is actually a server. This slot, new connection. I've been playing a game called Dota 2. I don't know if you guys have ever heard of Defense of the Ancients 2. It's actually got me horribly addicted to it. I just can't seem to stop playing the darn thing. All right, so let's just do just in case. And that's in the deconstructor right there. So listen, this is where the magic's gonna start to happen here. What we need to do is say M server, remove server. Now, what are we doing here? Remove server. If you've ever worked with sockets before, you know that if you open a port, the server crashes, and then you start the application again, that port's still in use. If that socket's still lingering around in memory and doing stuff. So this is no different. We want to make sure that we turn it off, but actually just through the magic of copy and paste, put it up there also. And actually, let's just get rid of close, because I think M server actually calls close under the hood. And we're just gonna add a little queue to bug so we can see what's going on here. Four. I've been getting a lot of email from you guys. I've been really trying to drudge through it, the holidays and work and everything. It's been just crazy. I have not had a chance to keep up. Some of your questions. Let's see if I can answer them while I'm just typing some of this out. Some of your questions have been, am I gonna get into mobile development? The answer to that is yes. It may be a while though. I've never done mobile development. So it may be fraught with errors such as this. All right, fine. We'll just call close then. Be that way. Probably in a real world application, you're gonna want to put the name as an actual member variable, but I'm in a bit of a hurry. My girlfriend's out Christmas shopping, and she's probably gonna come back and give me a lot of work to do. So I want to get this tutorial out there. All right, so it has previous. This is where the bulk of the work actually happens here. So what we're gonna do here is we're gonna say queue local socket, and we're gonna call it socket. Yeah, very descriptive name. Socket. Connect to server. And we're gonna connect to the name pipe, or the name channel I should call it. And actually just in case something changes in a future version, we should actually say queue local socket. Read right. This is the method. We want to be able to read and write to that socket. And we're going to say, let's give a little queue debug here so we know what's going on. So we're checking for previous instance, and we're going to actually say if socket, oops, wait for connected. Now you notice how we are doing a blocking socket here. Blocking means that execution will stop when it hits wait for connected, and it will not pass go until it's expired. You could put in any value you want. Local sockets are extremely fast. You're talking milliseconds. I think the default is like 30 seconds. But you can just do whatever you want, right? So we're gonna return faults. And then if we did actually connect, we're going to return true. What we're doing here is we're saying is if we can connect to that name channel, we are true because it actually exists. Otherwise it's false, meaning it never existed to begin with. And we're just going to, for good measure, just in case you guys run into any problems out there, like if you have a lingering socket or something. Now we want to actually say sending args to previous instance. So we're going to actually send the program arguments to the previous instance here. And we're going to do that through, well, a buffer. We're going to say quebyteray. Buffer. And let's see here. For each. That is probably the most awesome misfeature of que is the for each. I hate typing for loops. They just are so unnecessary these days. Que string item in our. All right. So we're going to say buffer. And we're just going to say item. Plus. And we're just going to do a return here. Or I'm sorry, a new line. Once we've done all that, we're just going to say socket. Right. And we're just going to write the buffer out. So quick explanation of what we're doing here. Save my work. Give it a good build. Make sure. All right. All right. When has previous instances called, we're passing the name of the channel and a arguments list in a string list. And we're just saying connect to the name channel. And if it connects, because wait for connected, this will execute. Otherwise it's just going to return false. We're printing out the error, even if there isn't one. And if it does connect, then we're going to take the arguments from the program and basically package them up into a nice buffer and ship them off to the socket. And then return true, indicating that hey, there was a previous instance. Okay. We're almost done here. We're going to actually do the connection now. I'm going to admit that new connection. And we're going to get the next pending connection. Little minus sign there. Geez. So, kind of curious to know what countries actually celebrate Christmas and what ones don't. I have some coworkers that are not from America and they don't celebrate Christmas. And it's kind of interesting because they expect that everybody will be working on Christmas Day. And here in the States, that's just not going to happen. So what we're doing now is we're just grabbing the next pending connection when there's a new connection. And we're just going to connect it to the, you guessed it, ready read. Now in ready read, we're just going to simply say, all right, we're just going to print it out here. We're going to say arg equal, because this is the arguments that we're passing back. Whoopsie. Somebody actually sent me an email. It was actually really funny. They actually went through all my videos and counted the number of times that I said, whoops or whoopsie. And it was like, in 120 videos it was like 900 times. It was just ridiculous. I was like, oh, that's not good. I probably shouldn't do that anymore. msocket.close. We're going to close that out. msocket.nl And we're going to delete later. Then we do a little bit of memory cleanup. I'm pretty sure Qt handles that under the hood, but just in case we're going to clean that up. All right, so, give a good build. All right, so it builds. It does nothing yet, because we haven't done anything. So let me check my notes. Make sure I'm doing this the right way. All right, so we got single instance. And we're just going to for good measure here. Qtabug. Somebody asked me why have I been doing so many command line applications? I mean, Qt has such an amazing GUI library. Why am I not doing GUI applications? And I'm like, the reason for that is pretty simple. Command line apps take out a lot of the complexity of building a GUI. And when you build a GUI, it takes time. And I try to keep these videos very short, simple and to the point. 902. And I just really want to cut out a lot of the complexity, because some of these topics can get fairly, fairly complex, fairly fast. Let's call this C instance. Now, if you're wondering what this is, this Q string, that's the name we're going to use. And we're going to use calm company application. So it's kind of the reverse of the actual fully quantified name of your application. And that's pretty standard if you've worked with Java or something like that. We're doing that to just avoid name... I can speak name collisions. For example, if you make a program called awesome and somebody else makes a program called awesome and you both try doing this, you're going to start conflicting with each other's applications. So just make sure that your name is very unique here. So we're going to say C instance has previous, and we're going to say name. You know, it would help if I actually put the variable in there. N, Q, core, app, location... There you are. So we're just going to simply say if it has a previous instance and else, previous instance detected. And if there's no previous instance, just for giggles, I want to say there can be only one. So if there's a previous instance, we want to go ahead and just exit out this application by just return zero. If you're wondering what zero is, go back to your C++ tutorials and you see how the main function returns an int. Int is just the error number. That's how you get error 52 or error 38 or whatever. It's just returning an error code. Zero is pretty much universal for there was no error. Now, if we get to here, we're going to say C instance, listen. If you want to just uncomplicate this thing, let's just get rid of that. There we go. I've been criticized for using too many ifs and else and it just gets kind of crazy, so give it a good build. All right, so what we're doing here, quick overview before we run this. We are creating our single instance. We're saying if we have a previous instance of our name, which is this bad boy right here, we're going to pass the command line arguments that were given to the application to the previous instance. Jump in here and what we're really doing under the hood is we're opening a queue local socket and connecting to the host. And if we actually connect, we're just packaging up the command line arguments and shooting them over. And then we're just reading them if we have a new connection. So if somebody connects to us, we're just going to get the pending connection, connect the ready read. And then once ready read, we're just going to read all. Whoo, that's a mouthful. Now, let's see if this thing actually works. So we're going to start one and I may have to drag some windows around because command windows typically just jump wherever they feel like it. All right, so you can see how it says there can be only one. This is the first instance of our app. And you notice there was no arguments passed. I'm going to kind of shove this off to the side here and I'm going to start another one and bring it back over here. And you see previous instance detected. Listening for, there we go. Looks like it crashed. Inferior received because of segmentation fault. Now I'm wondering what I did wrong here. I'll tell you what, I don't want to waste a ton of your guys' time. That's the basic concept. I just want to make sure this thing works. Whoops, I shouldn't have done that. 902, right? File system, there we go. Let's give it a good rebuild and see if we can kind of real-time troubleshoot this. I may actually pause the video and then figure out what's going on here. This usually causes problems, so let's get rid of that. Anyway, I'm going to pause the video and see if I can figure this out. Okay, we're back. I actually did figure out what was wrong here. The technical term for it is complete moron at the keyboard or ID 10 error. Basically, see this, emit new connection. If you look, some of you probably were wondering why I didn't catch this earlier, our signal is actually new instance, not new connection. New connection is a slot. So we're trying to emit a slot, which is why it was crashing. So if we just go save our work, and you can see I've added a few things here. Like I've added the wait for bytes written. I added this little append-yay. I'm just going to take that out here. Anyways, we're going to run our example now. Save all. And you can see I've renamed it application 9. I'm just going to leave it like that for now. I'm going to run this again. And you see, voila. All right, so what was going on here is we are checking for previous instance. Connection was refused, meaning there was no instance. So we said there can be only one and we're running and we're listening on our name here. And then once a new connection is made, new connections loading, we're reading it. And this is the argument from that connection right here. And the actual other instance is down here. And you can see we are checking for an instance. We found an instance, so we're sitting the arguments. And then we're just, you know, the application is done. So we can actually just, you know, leave this up here and run this a few times. And you can see how after we have run it a few times, you know, we get the arguments. Now in, I don't know if this is true in Windows or not, but in Linux, your first argument is almost always the application name itself. So that's how you get the app name. So that's it for this tutorial. Sorry about the goof up. You know, can't have every tutorial be perfect, but we fixed the problem. Thanks for watching. I hope you found this educational and entertaining. Oh, and before I hang up here, we've got 4 million views, 25,000 subscribers. Be sure to visit voidrums.com, my website. Click tutorials for the source code for this and other tutorials. And this tutorial actually came straight out of my petprojectpluginbot.net. The code that you see is actually running in here. Minus the typo that goofed up the tutorial, of course. All right.