gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

OffTopic > Help with Visual C++ Express 2008

#176725 - mymateo - Wed Sep 21, 2011 6:13 am

Hey all, me again. Well a project that I needed help getting to function is nearing its completion, and now I have to work out a few kinks. I started a new topic because this isn't really a question on programming (and that was the issue at hand when I created the last topic).

The operation is as such: The program is required to load up with Windows as it is designed to automatically install programs, set registry entries, and do all of the Windows Updates (automatic updates is too passive, need something that aggressively downloads and installs updates until they're all done).

The ISSUE is this: When the program loads up, it is SO gung-ho to just pick up and start going on its next task (or continue on with updates, whichever is the case) that it doesn't even bother to take the time to draw its own window before it starts doing all its work. What ends up happening is that it will run as if it's in the background (can see in Task Manager, but not the taskbar... not right away) until it's finished doing the grunt work; when it finally slows down enough to allow user interaction THEN it will draw the window. But because it's on automatic on reboot, it doesn't REQUIRE any user input until it's ready for the next reboot!

The issue, in short, is that when the tool is doing exactly what it is suppsed to then you cannot SEE it.

I've added a Sleep(); command on load, but even then when you just open it up to select your options (and therefore it's not going to be doing anything until you tell it to) it decides that running the Sleep(); command is more important than running the program. I have a section where I output information to a text box and I have it count down from 5, waiting a second then counting down 1 number, but all that happens is the program is invisible for 5 seconds, then pops open with the countdown fully completed.

Also, the draw time for the window is horrendous. I started this app in VC++E2010 and had to move to VC++E2008 becuase the 2010 version wouldn't compile with .NET 3.5; it was 4.0 or bust, and Windows 7 doesn't come with .NET 4 out of the box (and this tool is to basically set my computer back up from scratch every time I decide to format my computer - and I don't want to have to install .NET 4 before running the tool). In 2010 the app, once compiled and run, would open up all at once (you know how W7 will have that kind of "expanding" animation it does, where the app kind of fades into existence?), but in 2008 the outline appears and you can see all of the elements (text boxes, check boxes, radio buttons, buttons, progress bar and all that) pop on one after another. It's quick, yes, but in 2010 it was instantaneous and happened in the split second before the app showed its window.

Phew, I'm almost at an end here, just a bit longer!

Basically, I'm hoping someone has some experience with these issues. Most important is I'd like to find a way to get the program to fully initialize (and draw) before proceeding with reckless abandon and plowing through the code.

And if someone knows WHY the window doesn't draw as nicely as it did for the 2010 version and knows how to set the options in 2008 to make it match, that would be super!

I'm not holding my breath, but there are a lot of really smart and really helpful people who still read these forums so I feel it's a better gamble than posting on a MSDN forum and having people tell me to RTFM. (I don't HAVE a ******* manual to read! And Microsoft isn't known for writing clear, easy-to-follow instructions anyways!)

Thanks, all!

#176726 - Dwedit - Wed Sep 21, 2011 10:37 am

Use a second thread for the task, or call Applicaiton.DoEvents. (Do either with caution, calling DoEvents is basically invoking the windows message loop, and it can trigger GUI events whether you like it or not.)

If the user can interact with the program in any way (such as hitting a STOP button), use a secondary thread. That way the program stays responsive all the time. You just need a good way for the thread to poll the "Are we trying to stop" variable and stop not too long after hitting the stop button.
But calling DoEvents is just easier. Secondary threads are complicated, since only the GUI thread can interact directly with the GUI.

Do NOT use sleep. Sleep stops the program, it's not taking anything off the Win32 message queue. Just say no. Use Timers instead, that way the program is perfectly responsive while waiting for the WM_TIMER message
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#176727 - mymateo - Thu Sep 22, 2011 4:26 am

Hey Dwedit

So I tried adding aa Application::DoEvents(); line just in the beginning (basically after the form is drawn... or rather, the commands to draw the form have been called) and it still doesn't help. I've got the Sleep(); and UpdateResults(); (adds lines to my text box to show progress) entries in there still, just so the application has something to do when it starts up... the application STILL runs quietly in the background until all the messages are done and all the sleep events have completed.

Ideally, I'll know this will work once the application opens, draws the window, then starts writing outputs.

I don't plan on using Sleep() ANYWHERE in the final build, I'm just using it as a bit of busywork for the app to give it something harmless to do that I can track the progress easily.

It's a great lead, though, so I'll play around in MSDN to see if there's maybe something more I can do.

Appreciate the help! (And I'm not sure how I'd ever figure out using a second thread, though the results sound very appealing! I'd like to be able to have my main window be fully responsive while it's doing the Windows Updates... like being able to scroll the list to read what updates it's installing, especially as the list can top 100 items on a fresh install!)

#176728 - mymateo - Fri Sep 23, 2011 5:42 am

Well, I solved the mystery.

The problem, which would not have been obvious without anyone SEEING my project, is that I was invoking code on the Form1_Load event. This, of course, started the code once the form was LOADED.

I changed the project so now it runs the code under the Form1_Shown event.

Still, I would have liked to figure out how to get all of the code to run in a separate thread, becuase as the program runs it spews out status updates in a listbox and it would be nice to peruse it as it's doing its job, but it's too busy to let me do anything, so I just get the last dozen or so tasks it's run. Still, not bad.

So another little n00b issue easily solved, once my brain started working.

Still, the bits I learned about threading looks like it would be useful to have for my next project; but I have too much code now to try and rearrange it into threads. I have a function DoSetup() that calls all of the other functions and makes changes to the form which makes it impossible to simply call DoSetup() from a new thread due to the stupid way Visual C++ 2008 Express lays things out. I'm sure it can probably be done, but I'm SO close to finishing my project at this point that I just want it done; I can make it "pretty" later; fast & dirty code for something that functions is good enough for now.

I DO appreciate the help that I continue to receive on these forums, though!

#176729 - Dwedit - Fri Sep 23, 2011 7:15 am

Look at the BackgroundWorker class. Three event handlers, and the DoWork method, and you are doing stuff in another thread.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#176730 - mymateo - Sat Sep 24, 2011 6:55 am

I took a quick look into that; it still looks a bit confusing. I'm sure I could figure it out, but the biggest pain would be all of the different functions that I have each have their own calls to update a listbox on the main form to show what is currently happening; which from what I've read will cause your application to throw up; there's a bunch of other work that needs to be done to pass the info to the main thread to let IT do the update. I think since I'm so close to being done I'll just leave it alone for now; I'll probably come back to it in a week or so and see if I'm a little more encouraged to try. Thanks for the lead though, it definitely looks a lot easier than trying to handle threads myself!



While I'm here, I might as well see if someone can shed some light on a weird behaviour I've come across. I'm trying to get this program so you open it, click GO, then it does everything else, including resuming after a reboot.

I've got the code WORKING just fine, but HOW I made it work just makes me feel sick and a bit stupid. This is how it creates the entry to start itself up; it basically finds the working path, adds the filename to it, then plops it into the registry. Take a peek:

Code:
   String ^AppPath;
   char sCurrentPath[FILENAME_MAX];
   GetCurrentDir(sCurrentPath, sizeof(sCurrentPath));
   AppPath = gcnew String(sCurrentPath) + TEXT("\\Auto Setup.exe");
   UpdateResults(AppPath);  // Shows the full string in a listbox so I can see what I'm writing without having to go into the Registry
   char achar[FILENAME_MAX];
   int max = strlen(sCurrentPath) + 15;
   for (int i=0; i < max; i++) achar[i] = AppPath[i];
   RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0L,  KEY_ALL_ACCESS, &Registry);
   RegSetValueExA(Registry, "Automated Setup", 0, REG_SZ, (LPBYTE)&achar, max);
   RegCloseKey(Registry);


The concern I have is why the hell do I have to copy the entire contents of a char into the contents of... another char?! If I bypass that step, add the "\\Auto Setup.exe" to the string and pass the string into RegSetvalueExA, then I get a few gibberish characters, the full path all nice and neat, but no filename on the end.

I've got to stop programming after my bedtime; I have a feeling if I HAD time to do this stuff during the day I'd probably be able to figure it out. I've spent a few hours, but to no avail. If someone has an explanation then I'm all ears! (I'm not looking for someone to outright give me working code, just a finger in the right direction... I hate asking others to do my work for me, I try to keep it to simple answers, and I really appreciate all the help I keep getting!)

#176731 - Dwedit - Sat Sep 24, 2011 7:27 am

Probably because you're passing a Unicode string into an ANSI Win32 function (one that ends with capital A). Use the W version instead.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#176732 - mymateo - Sat Sep 24, 2011 8:58 pm

Hey Dwedit

Yeah, that thought had crossed my mind... but after ensuring everything was using the same format (I went with Unicode) I was getting... nothing! Quite literally, NO path was returned. So then I went to try to append my filename onto the empty path to see what would happen, and I ran into some issues trying to get that done.

A bit of google later, and I came across the strcat function. Of course, my compiler told me it was unsafe and to use strcat_s.

Long story short, I'm back to exactly where I was BEFORE I had it working "dirty" style, except now that I'm using strcat_s instead of just using + to ram some lines onto the end of a new string it's working properly! No more gibberish at the beginning (which I now suspect was my filename being added improperly) and I get a filename at the end. The code is half as long as well, which makes it a lot easier to read!

Live and learn. :P

Now I'm fighting with the stupid RegDeleteValueEx command... keeps returning code 2 "File not found"... which is bull! argh, this'll probably end up being another one of those stupid little mistakes... though there's practically no code involved; 3 lines to open the registry, write the entry, and close the registry; 3 more to re-open it, delete the value, then close it again. It writes no problem, but won't delete. It succeeds in OPENING the key, but it won't delete the value... I had a sinking feeling it was looking elsewhere when trying to delete (it's going into HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run when I write, so I thought maybe it was trying to delete from HKLM\Software\Microsoft\Windows\CurrentVersion\Run... but even with a duplicate key there it still fails...)

No matter, I'll get this in the long run... eventually...

** Edit **
Yeah, insomia gives you more time to program, but much less brain power. Even though I KNEW I had to use RegDeleteVALUE I was using RegDeleteKEY. So of COURSE it couldn't find it... argh, my head hurts.

Maybe I should just get a job flipping burgers, sell my laptop to some hobo, and live my life in a very ordinary way. Maybe become Amish... no programming woes there... *smacks head against wall*