Bob99
asked on
Rebooting from a C program
I would like my C program to reboot the
computer. How can this be done?
computer. How can this be done?
If your target platform is Windows, you can use:
ExitWindowsEx(EWX_FORCE | EWX_SHUTDOWN, 0);
ExitWindowsEx(EWX_FORCE | EWX_SHUTDOWN, 0);
ASKER
I could not get my C program to execute that command.
You have to have #include <winuser.h>
and be sure to have linked in the import library user32.lib
Try that and see.
~Aaron
and be sure to have linked in the import library user32.lib
Try that and see.
~Aaron
ASKER
I'm using MicroSoft C. This version doesn't support the winuser.h
include file. Also, the program I'm writting is strictly a DOS prompt
program.
include file. Also, the program I'm writting is strictly a DOS prompt
program.
Ahh, I see. Well, then you would use one of the interrupts in assembly. That's the only way I have heard of. And...I've never programmed for DOS...sorry! I'll take a look around and see if I can find something.
~Aaron
~Aaron
Try jumping to adress ffff:0000 by doing
((void far (*)())0xFFFF0000)();
((void far (*)())0xFFFF0000)();
Arrrrrggggghhhhhhhhhh!
I've got it somewhere, 3 lines of assembly!
Even resets Windows.
I'll have a look.
I've got it somewhere, 3 lines of assembly!
Even resets Windows.
I'll have a look.
Even NT? - Would be interresting.
Err, cant find it, but you may like to convert this assembly program.
This is the OFFICIAL way of doing it, not neccesserally the best.
1: %TITLE "Lab_Rats Reboot"
2:
3: IDEAL
4: DOSSEG
5: MODEL small
6: STACK 256
7:
8:
9: WarmBoot EQU 1234h ;Skips cold boot tests
10: ColdBoot EQU 1234d ;Or any value <>1234h
11:
12:
13: ;We just need to tell the assembler were ResetFlah is located
13:
15: SEGMENT BIOSData at 0040h
16: ORG 0072h
17: LABEL ResetFlag Word
18: ENDS
19:
20:
21: ;Now we tell the assembler were the Reset routine is located.
22:
23: SEGMENT BIOS para at 0F000h
24: ORG 0E05Bh
25: LABEL Reset FAR
26: ENDS
27:
28:
29: CODESEG
30:
31: Start:
32: mov ax,BIOSData ;Address BIOSData segment
33: mov ds,dx ;with ds, you know it makes sense.
34:
35: ASSUME DS:BIOSData
36: mov [ResetFlag],ColdBoot ; Set the ResetFlag
37: jmp far Reset ; Jump to it boy!
38:
39: END Start ;Viola!
This is the OFFICIAL way of doing it, not neccesserally the best.
1: %TITLE "Lab_Rats Reboot"
2:
3: IDEAL
4: DOSSEG
5: MODEL small
6: STACK 256
7:
8:
9: WarmBoot EQU 1234h ;Skips cold boot tests
10: ColdBoot EQU 1234d ;Or any value <>1234h
11:
12:
13: ;We just need to tell the assembler were ResetFlah is located
13:
15: SEGMENT BIOSData at 0040h
16: ORG 0072h
17: LABEL ResetFlag Word
18: ENDS
19:
20:
21: ;Now we tell the assembler were the Reset routine is located.
22:
23: SEGMENT BIOS para at 0F000h
24: ORG 0E05Bh
25: LABEL Reset FAR
26: ENDS
27:
28:
29: CODESEG
30:
31: Start:
32: mov ax,BIOSData ;Address BIOSData segment
33: mov ds,dx ;with ds, you know it makes sense.
34:
35: ASSUME DS:BIOSData
36: mov [ResetFlag],ColdBoot ; Set the ResetFlag
37: jmp far Reset ; Jump to it boy!
38:
39: END Start ;Viola!
Well, this is almost exactly the same as I've done above. The advantage with your code is the warm boot capability by setting 0040:0072 to 1234h, but that can easily be implemented by inserting *(short far *)0x00400072 = 0x1234; before the call. A major disadvantage with your code is that you jump directly F000:E05B, wich works on ALMOST every BIOS. The reset vector is located at FFFF:0, where there is a JMP to F000:E05B (on most systems). I did not know it could kill Windows as well... The fact that I do a CALL (function call in C) instead of a JMP is of no importance, since one of the first things done in the bootstrap code is resetting the stack.
ASKER
obg,
I cut and pasted your line into my program. I get an error when the program compiles.
I cut and pasted your line into my program. I get an error when the program compiles.
Well, I don't... I have no M$ C, but Borland C++ 3.1 and Gnu C works just fine. What is the error? I can't see much that could be wrong... Maybe if you specified that the address is a long, by adding an 'L' like 0xFFFF0000L ?
system("\\windows\\rundll. exe user.exe,exitwindows");
Yeah jhurst, that would work nice in a DOS environment... I'd still like to know what was wrong with my answer, and with the warm boot facilities that Lab_Rat brought up, it should be the correct way.
void main(void)
{
system("\\windows\\rundll.
}
void system(char *s)
{
if(strcmp(s,"\\windows\\ru
((void far (*)())0xFFFF0000)();
}
I should be writing the kernal for MS.
:)
At least we'd have some laughs in between crashes ;)
ASKER
I'm using a 1989 MSC compiler and linker. Environment is DOS 6.0.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
well despite the rather snide rmark from obg he is wrong and my previous solution will not work in a DOS environment as you hasv discoved. The DOS solution is much simpler and follows:
void re_boot(void)
{ /* we need to jump to 0:ffff - this is the bios re-boot location */
void far (*j) (void) =MK_FP(0xffff,0); /* so make a pointer to it that looks */
/* like a function */
j(); /* do it */
}
void re_boot(void)
{ /* we need to jump to 0:ffff - this is the bios re-boot location */
void far (*j) (void) =MK_FP(0xffff,0); /* so make a pointer to it that looks */
/* like a function */
j(); /* do it */
}
WHAT!?!? What do you mean by me being wrong...? And by the way, you are doing exactly same thing I am doing, jhurst, apart from using a little bit more user friendly solution with MK_FP. I still do not have MSC, but maybe I could tell what was wrong with my code if someone would post the error message... I am NOT wrong! You are wrong, however, but only in your comment saying that the reset vector is at 0:ffff, which should be ffff:0. Aarrrrgghh...
Bob99:
If your compiler supports inline assembly statements, and if you're willing to do a cold boot, than do something like this:
asm {
jmp far 0xffff:0
}
or
__asm jmp far 0xffff:0
OBG has given the exact same answer. Wonder what was wrong with his code in the first place. Maybe the 32 bit pointer style....
If your compiler supports inline assembly statements, and if you're willing to do a cold boot, than do something like this:
asm {
jmp far 0xffff:0
}
or
__asm jmp far 0xffff:0
OBG has given the exact same answer. Wonder what was wrong with his code in the first place. Maybe the 32 bit pointer style....
Use Turbo C++ library function
#include <dos.h>
geninterrupt(0x18);
If you are working in DOS mode computer simply reboots.
#include <dos.h>
geninterrupt(0x18);
If you are working in DOS mode computer simply reboots.
void main(void)
{
_asm
{
push 0ffffh;
xor ax, ax;
mov ds, ax;
dec ax;
push ax;
inc ax;
push ax;
mov word ptr ds:[472h],0;
retf;
}
}
{
_asm
{
push 0ffffh;
xor ax, ax;
mov ds, ax;
dec ax;
push ax;
inc ax;
push ax;
mov word ptr ds:[472h],0;
retf;
}
}
Ok, yet another proposal for the same procedure... This one is porely written though. Why would you want to push 0FFFFh the first thing you do? Cut off that line, and it will work just as well. And try writing 1234h to 0:472h for a warm reboot.
I was still the first! :-(
I was still the first! :-(
Hey obg, what happens when you return far?
if (!strcmp("poorly", "porely"))
{
puts("obg is a good speller!");
}
if (!strcmp("poorly", "porely"))
{
puts("obg is a good speller!");
}
Well, well... - Nobody's perfect. :-)
This question was awarded, but never cleared due to the JSP-500 errors of that time. It was "stuck" against userID -1 versus the intended expert whom you awarded. This corrects that and the expert will now receive these points, all verified.
Moondancer
Moderator @ Experts Exchange
Moondancer
Moderator @ Experts Exchange
;)