Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Tool to replace the DOS stub of an existing Windows application EXE?

450 views
Skip to first unread message

JJ

unread,
Aug 27, 2017, 5:36:39 PM8/27/17
to
For example, I have two Hello-World programs for two different platforms as
EXE files. One is for 32-bit Windows (the message is shown via standard
dialog), and the other is for DOS (shown as text).

Now I want to merge those two into a single EXE file by replacing the DOS
stub of the Windows version of the program. So that the EXE file is dual
platform. I know that this is possible because all compilers simply use the
DOS stub to show a "This program cannot be run in DOS mode." message when
targetting for Windows platform.

One good example for a dual platform program is Windows 9x/ME's Windows
Registry Editor application (REGEDIT.EXE). It's DOS stub is a DOS version of
the application, so it's usable when the system is running in real DOS mode
(i.e. pure DOS; not under Windows).

So, is there a tool to replace the DOS stub of an existing EXE file? Whether
the existing EXE file uses NE, LE/LX, or PE format?

Antony Gordon

unread,
Aug 28, 2017, 12:57:52 AM8/28/17
to
Hi,

Yes, there is a linker option for that in Visual Studio.

https://docs.microsoft.com/en-us/cpp/build/reference/stub-ms-dos-stub-file-name

-T

On Sunday, August 27, 2017 at 5:36:39 PM UTC-4, JJ wrote:
> For example, I have two Hello-World programs for two different platforms as
> EXE files. One is for 32-bit Windows (the message is shown via standard
> dialog), and the other is for DOS (shown as text).
<snip>

JJ

unread,
Aug 28, 2017, 8:07:44 AM8/28/17
to
Ah, thanks. I didn't know Microsoft's linker can do that even though I
already have it for all those years. :)

Rod Pemberton

unread,
Aug 29, 2017, 3:33:51 AM8/29/17
to
On Mon, 28 Aug 2017 04:36:11 +0700
JJ <jj4p...@vfemail.net> wrote:

> For example, I have two Hello-World programs for two different
> platforms as EXE files. One is for 32-bit Windows (the message is
> shown via standard dialog), and the other is for DOS (shown as text).

The DOS version should run on most versions of Windows. Most
versions of Windows support a console window which can run 16-bit DOS
applications and 32-bit DOS DPMI applications. These versions of
Windows support the DPMI version 0.9 specification, internally.
However, it's been said that you may need some registry tweaks for Win
XP for DPMI applications.

Japheth's HXRT project supports running Windows applications in DOS.
His old project had many other tools and programs, e.g., HDPMI a DPMI
host, and HIMEMX a HIMEM replacement. Using HXRT and HXGUI, I managed
to get Quake3 running in DOS. He posted a list of the games and
compilers that worked with it. It's been archived by Wayback:

Japheth's HX RT Win32 Apps Compatibility List (many games and compilers)
https://web.archive.org/web/20080614140750/http://www.japheth.de/HX/COMPAT.TXT

Japheth's website archived by Wayback Archive:
https://web.archive.org/web/20121122163511/http://www.japheth.de/

HX DOS Extender website by Japheth (original links, dead now)
http://www.japheth.de/
http://www.japheth.de/HX/COMPAT.TXT

Wayback Internet Archive
https://web.archive.org

> Now I want to merge those two into a single EXE file by replacing the
> DOS stub of the Windows version of the program. So that the EXE file
> is dual platform. I know that this is possible because all compilers
> simply use the DOS stub to show a "This program cannot be run in DOS
> mode." message when targetting for Windows platform.

In console windows, e.g., DOS console under Win 98/SE etc, the DPMI exe
will use Window's internal DPMI host instead of the one in the stub.

In DOS, a DPMI exe will load the DPMI host that the stub tells it to
load, if /no other/ DPMI host is already resident.

I.e., normally in DOS, your app will load and unload the DPMI host it
needs. This is specified in the stub somewhere. So, you won't notice
if you run a DJGPP DPMI app followed by a Watcom DPMI app. However, if
you manually load a DPMI from one compiler and leave the DPMI host
resident in memory, when a DPMI app from another compiler executes,
it'll use the incorrect DPMI host, since one is still resident in
memory. Most of the time this is acceptable, but this can be a
problem. If one DPMI host has no DOS extender functions, but the other
host uses extended functions, a problem can arise. Those DOS extender
functions may be missing when the app that needs them attempts to
execute. E.g., this could possibly running an OpenWatcom DPMI app
which needs extended DOS functions after manually loading CWSDPMI for
DJGPP which has no extended DOS functions. I.e., if you execute
CWSDPMI manually, it can stay resident in memory. I don't recall if
that is by default or with a parameter.

> One good example for a dual platform program is Windows 9x/ME's
> Windows Registry Editor application (REGEDIT.EXE). It's DOS stub is a
> DOS version of the application, so it's usable when the system is
> running in real DOS mode (i.e. pure DOS; not under Windows).
>
> So, is there a tool to replace the DOS stub of an existing EXE file?
> Whether the existing EXE file uses NE, LE/LX, or PE format?

Many DPMI hosts have stub/unstub tools.

WDOSX has STUBIT
D3X has STUBX
DOS32A has SB
DJGPP has STUBIFY, COFF2EXE, EXE2COFF, STUBEDIT

One of the DPMI hosts had a generic unstub utility which worked with
most other DPMI applications. From a past post, I think it might be
DOS32A's SB.exe.


Please note that most DPMI hosts generally only support DPMI version
0.9. They usually don't support DPMI version 1.0, or they only support
a random handful of 1.0 functions. Even for DPMI 0.9, some hosts don't
support every function. Windows consoles only support DPMI 0.9 too.
If you need DPMI 1.0 functions, you'll probably have to use DPMIONE.


Rod Pemberton
--
Isn't anti-hate just hate by another name? Isn't
anti-protesting just protesting by another name?
Peace is a choice that both sides rejected.

JJ

unread,
Aug 29, 2017, 5:27:32 AM8/29/17
to
On Tue, 29 Aug 2017 03:35:03 -0400, Rod Pemberton wrote:
>
> The DOS version should run on most versions of Windows. Most
> versions of Windows support a console window which can run 16-bit DOS
> applications and 32-bit DOS DPMI applications. These versions of
> Windows support the DPMI version 0.9 specification, internally.
> However, it's been said that you may need some registry tweaks for Win
> XP for DPMI applications.
>
> Japheth's HXRT project supports running Windows applications in DOS.
> His old project had many other tools and programs, e.g., HDPMI a DPMI
> host, and HIMEMX a HIMEM replacement. Using HXRT and HXGUI, I managed
> to get Quake3 running in DOS. He posted a list of the games and
> compilers that worked with it. It's been archived by Wayback:
>
> Japheth's HX RT Win32 Apps Compatibility List (many games and compilers)
> https://web.archive.org/web/20080614140750/http://www.japheth.de/HX/COMPAT.TXT
>
> Japheth's website archived by Wayback Archive:
> https://web.archive.org/web/20121122163511/http://www.japheth.de/
>
> HX DOS Extender website by Japheth (original links, dead now)
> http://www.japheth.de/
> http://www.japheth.de/HX/COMPAT.TXT
>
> Wayback Internet Archive
> https://web.archive.org

My aim here, is to have a multi platform executable file so that the program
can be at its best in each platform / system mode. Si, I'm not just trying
to make sure that my program can work on both DOS and Windows.

> In console windows, e.g., DOS console under Win 98/SE etc, the DPMI exe
> will use Window's internal DPMI host instead of the one in the stub.
>
> In DOS, a DPMI exe will load the DPMI host that the stub tells it to
> load, if /no other/ DPMI host is already resident.
>
> I.e., normally in DOS, your app will load and unload the DPMI host it
> needs. This is specified in the stub somewhere. So, you won't notice
> if you run a DJGPP DPMI app followed by a Watcom DPMI app. However, if
> you manually load a DPMI from one compiler and leave the DPMI host
> resident in memory, when a DPMI app from another compiler executes,
> it'll use the incorrect DPMI host, since one is still resident in
> memory. Most of the time this is acceptable, but this can be a
> problem. If one DPMI host has no DOS extender functions, but the other
> host uses extended functions, a problem can arise. Those DOS extender
> functions may be missing when the app that needs them attempts to
> execute. E.g., this could possibly running an OpenWatcom DPMI app
> which needs extended DOS functions after manually loading CWSDPMI for
> DJGPP which has no extended DOS functions. I.e., if you execute
> CWSDPMI manually, it can stay resident in memory. I don't recall if
> that is by default or with a parameter.

I'm aware that there may be compabitility issues when using DPMI, but I
didn't know it could be that severe.

In case of an incompatible DPMI host, I was thinking of detecting whether
the incompatible DPMI host is present or not, before actually starting to go
into protected mode. But I don't know if this is possible because without
using pure assembly, AFAIK, the very first line of a source code statement
would already have been executed in protected mode. i.e. I don't know if I
can enter protected mode manually via high level programming language such
as C or Pascal.

The only way I could think of is to use a separate, pure DOS only program
which detect the presence of any incompatible DPMI host, before actually
running the main program's executable file. The detector program would be
made as the main program while the real main program be made as a
second-stage main program.

> Many DPMI hosts have stub/unstub tools.
>
> WDOSX has STUBIT
> D3X has STUBX
> DOS32A has SB
> DJGPP has STUBIFY, COFF2EXE, EXE2COFF, STUBEDIT
>
> One of the DPMI hosts had a generic unstub utility which worked with
> most other DPMI applications. From a past post, I think it might be
> DOS32A's SB.exe.
>
> Please note that most DPMI hosts generally only support DPMI version
> 0.9. They usually don't support DPMI version 1.0, or they only support
> a random handful of 1.0 functions. Even for DPMI 0.9, some hosts don't
> support every function. Windows consoles only support DPMI 0.9 too.
> If you need DPMI 1.0 functions, you'll probably have to use DPMIONE.

Thank you. I didn't know that there are many of them. And DJGPP's STUBEDIT
sure seems like an interresting tool.

Rod Pemberton

unread,
Aug 30, 2017, 2:56:35 AM8/30/17
to
On Tue, 29 Aug 2017 16:27:02 +0700
JJ <jj4p...@vfemail.net> wrote:

> My aim here, is to have a multi platform executable file so that the
> program can be at its best in each platform / system mode. [Sigh],
> I'm not just trying to make sure that my program can work on both DOS
> and Windows.

Ok. I can't really help further with a multiple operating system
executable type as I'm not familiar with the format of most
executables, except for DOS DPMI's and DOS .com's.

FYI, 32-bit DPMI is a good choice though, as long as you're not running
a recent version of Windows, such as Win 10, and also not running Linux
or a MacIntosh. 32-bit DPMI apps work with the many versions of DOS
and most versions of Windows in a console window. I'd guess that this
is the most widely supported executable type.

FYI, the way I got into development of my own operating system was
because I was wanting an "universal" DPMI host that worked with both
DJGPP and OpenWatcom.

Personally, I'd think it best to define the following as note all code
will execute with all operating systems.
1) which operating system environments you'd like to execute your code
2) which compilers will generate the code and what type of code
3) compare with which types of code the operating system can execute


Also, I'm not sure this is the best group. I'm not sure that there is
a perfect group either, but those on comp.lang.asm.x86 and
alt.os.development has discussed similar issues in the past. One is
for x86 assembly and the other is for operating system development.
A couple hobbyist compiler developers hang around on a.o.d. who've
produced compilers which generate binaries for multiple targets.
I.e., they may be familiar with the executable formats you're using.
The issue of portable code, generally high-level, not binary
executables, has come up on comp.lang.misc from time to time.

> I'm aware that there may be compabitility issues when using DPMI, but
> I didn't know it could be that severe.
>
> In case of an incompatible DPMI host, I was thinking of detecting
> whether the incompatible DPMI host is present or not, before actually
> starting to go into protected mode.

You should be able to detect PM by using the SMSW instruction, since
MOV CR0 is privileged and will GP fault, if not executing code in ring
zero. IIRC, you may need an operand size override on SMSW.

http://qcd.phys.cmu.edu/QCDcluster/intel/vtune/reference/vc296.htm

DPMI v0.9 lists INT 0x2F, AX=1686h "Get CPU Mode" as bimodal. It must
work for both RM and the PM (either 16-bit or 32-bit) of the DPMI host,
if the DPMI host is present. It should not be called unless DPMI is
available. So, if DPMI is present, you can call this to determine the
processor mode of the code, i.e., in RM w/DPMI host loaded but no PM
code is executing, or in PM w/DPMI host loaded and PM code is executing.

As for detecting the DPMI host itself, calling INT 0x2F, AX=1687h
"Obtain Real-to-Protected Mode Switch Entry Point" should be
sufficient. This is a RM interrupt function. This tests for the
presence of DPMI *AND* provides an address for RM to PM entry. I.e.,
if this fails, no DPMI host is loaded. Of course, if you're using
compiled code, you need to know what mode you're code is in to determine
your languages' appropriate call-interrupt routine. High-level
languages usually have at least two routines, one for making RM
interrupt calls from RM code, and one for making RM interrupt calls from
PM code. You should know this from the commands you use to produce
the executable, e.g., 16-bit RM or 32-bit DPMI.

Also see SMSW above to determine PM or RM.

Also note that some DPMI hosts are 16-bit PM, not 32-bit. Most of the
DPMI hosts for high-level languages are 32-bit PM. INT 2Fh, AX=1687h
will also tell you whether the DPMI host is 16-bit PM or 32-bit PM.

> I don't know if I can enter protected mode
> manually via high level programming language such as C or Pascal.

The compiler should link in the code that sets the appropriate
processor mode for the code if required, i.e., 16-bit RM (nothing),
16-bit PM w/DPMI (DPMI stub), 32-bit PM w/DPMI (DPMI stub). So, you
shouldn't need to enter PM unless your compiler produces 16-bit RM code.

If 16-bit RM code, yes, you'll probably have to code some assembly to
effect the RM to PM switch, if you're not using a DPMI host (call INT
0x2F, AX=1687h) and not executing under an OS like Windows or Linux
which use PM. Without a DPMI host and not executing under Windows or
Linux, a PM environment implementation is entirely up to you. Of
course, you can't switch into PM while executing under a PM OS like
Windows or Linux as they are PM operating systems. Of course, most
versions of Windows except Win 10, offer a console window for 16-bit RM
v86 mode code that can call Windows 32-bit DPMI and execute 32-bit code.

There is also a BIOS call that switches into PM from RM, but I don't
know if it's reliable. See:

INT 15h, AH=89h "Switch to Protected Mode"
http://www.delorie.com/djgpp/doc/rbinter/ix/15/89.html

INT 15h, AH=87h "Copy Extended Memory"
http://www.delorie.com/djgpp/doc/rbinter/id/35/15.html

> The only way I could think of is to use a separate, pure DOS only
> program which detect the presence of any incompatible DPMI host,
> before actually running the main program's executable file.

If you are executing from DOS or a Windows console, your code starts as
16-bit RM code, for DOS as either in RM or v86 (modified 16-bit RM under
PM control), or for Windows console as v86 mode.

From RM or v86 mode, your codes' DPMI stub will, or your code can, call
INT 2FH, AX=1687H to detect DPMI. If your code is PM, you should know
that, but you can call this function from PM code too. From PM, you'll
need to know you're in PM, i.e., 32-bit DPMI code, so you know which
library call to use. The appropriate interrupt function will switch
from PM to RM to call RM interrupts, and return to PM.
0 new messages