This file contains basic documentation for the DosWin32 pack. The use and distribution of DosWin32 pack is permitted ONLY by accordance with the DosWin32 pack license agreement (see file license.txt). DosWin32 is distributed in two archives: basic DW32CORE.ZIP (end-user files) and optional DOSWIN32.ZIP (files for development). According to the license agreement the same files from DW32CORE.ZIP can be included in any other software products. ---------------------------------------------------------------------------- The general concept of DosWin32 pack is the same as that in Borland Power Pack: the main task is not to support the DPMI applications (although some DPMI functionality is present), but to support win32 console applications in pure DOS. The DOSWIN32.RTM file is the "core" of the system. It also includes the win9x and WinNT drivers (for development and debugging in the Windows environment) and the DPMI host (for working under DOS). I. The main restrictions and specifics (end-user information) ----- 1. Required software and hardware configuration: 1.1. Minimal required hardware: x486 (not SX) and at least 16MB RAM. 1.2. The DOS-7 (from the Windows9x package) can be used as "basic" OS. For development and debugging purposes Win9x and WinNT (NT4SP3 and higher) Dos-Box can be used. MS DOS version 5 and higher versions are supported. ----- 2. To run programs created by UniLink (see UniLink description) with DosWin32 auto-loading stub, the DOSWIN32.RTM file must be in the PATH. ----- 3. Inside the emulated win32 system the SystemDirectory and WindowsDirectory variables point to the directory with DOSWIN32.RTM. ----- 4. The DosWin32 program can allocate up to 1Gb physical memory, although it can use about 3Gb of virtual address space under DOS. Under Win9x/WinNT, the accessible memory size depends on the particular OS. DosWin32 can work under "pure" DOS and with loaded HIMEM or HIMEM+EMM386. The last case is slightly slower. ----- 5. If the physical memory is not sufficient (in DOS) then swapping to the disk can be used. To turn on swapping you need to create a swap file of sufficient size. If that file exists when DosWin32 is started, the swap subsystem is automatically initialized. The minimal size of swap file is 0.5Mb and the maximal - 2Gb (DOS restriction). Default swap file name is DOSWIN32.SWP (looked up in the CURRENT directory), but you can specify any file in environment variable DW32SWP. CAUTION: You MUST specify the FULL path to the swap file in the environment variable. NOTE: Swapping in DOS is very slow and should be used when there is no other solution. To maximize the speed, the swap file should be placed in the drive with a cluster size of 4Kb (8 sectors). ----- 6. CAD (Ctrl-Alt-Del) is "blocked" all the time when the DosWin32 is active. The phantom floppy (when only one floppy drive is present) also doesn't work. ----- 7. Don't forget to load all resident programs you use (mouse driver, smartdrv, national keyboard drivers etc.) BEFORE DosWin32 starts. ----- 8. The PE program can be launched under the emulator in three ways: 1. If it was linked by UniLink with -ax[y] option it will load DosWin32 automatically. 2. You can start DosWin32 "by hand" through run32 command. 3. When DosWin32 is resident all PE applications are started in 32-bit mode. ----- 9. There are two small programs in DosWin32 pack: RD32.EXE and RUN32.EXE. The first is a td32 debugger launcher and the second is used by two ways: it starts a PE application or it loads the DosWin32 core and makes it resident in the memory. When you want to start the PE program without the DosWin32 stub under emulator, you need to type: run32 The program is started in the PE mode and after its termination the DosWin32 core will be unloaded. More common is to use run32 to make DosWin32 resident. To do this run run32 without arguments. When DosWin32 is resident, neither run32 nor PE-stub's are needed anymore. All started tasks are checked for the PE header and launched in the appropriate mode. Thus the win32 program start time is significantly shorter. But another side is that 16-bit task executions are very slightly slower. The resident DosWin32 core can be unloaded by the 'exit' command. NOTE: if the loaded program uses "external" (not implemented in the DosWin32 core) DLLs, they have to be found in the search path. ----- 10. The registry database uses the DOSWIN32.RGD file in the DOSWIN32.RTM directory. If it does not exist, it is created when DosWin32 is started. CAUTION: If the registry file is corrupted then the DosWin32 core cannot be loaded. This is a fatal error. The only solution is to delete the corrupted file. If you want to use the registry don't forget to make a backup copy. ----- 11. The functions that use the system ini-file (win.ini) work with the DOSWIN32.INI file placed in the DOSWIN32.RTM ("system") directory. ----- 12. When the DosWin32 core is loaded (is resident or when "child" programs are running) even the DOS applications can use the clipboard. ----- 13. If the program is terminated by an exception, the error information is not only printed on the screen, but can also be stored in the error log file. To turn on this feature you need to define the environment variable DW32LOG with the FULL path to the error log file. NOTE: If the file name is "*" then the log file DOSWIN32.LOG in DOSWIN32.RTM directory is used. If the file name is "." the file DOSWIN32.LOG is created in the current (at the emulator start time) directory. CAUTION: If the file name has the '+' symbol placed before its name then it is interpreted not as a part of the file name, but as a full diagnostic flag. When this flag is set, ALL the messages concerning the program or library loading errors will be written into this file. This flag affects the children processes too (LoadLibrary/CreateProcess/etc). ----- 14. If the unresolved imports are detected in the program loading phase, then the loader asks for program launch confirmation. If the answer is "Y[es]" and some of these unresolved imports are called, the error message would be generated (on the screen and to the log, if active) with the information about the import and where it was called from. ----- 15. DosWin32 works with long file names (LFN), but because DOS does not support LFN, using LFN slows down performance and buffering. However long names are preserved even when old 16-bits programs work. For the proper work with LFN the PROPER current CodePage must be set (the COUNTRY.SYS must be loaded for all countries other than the USA). NOTE: CodePages (countries) with DBCS are not supported. For these Code Pages the LFN features MUST be disabled - otherwise DosWin32 will not be loaded. To disable the LFN suport please set the environment variable DW32LFN=- ----- 16. When working with resources the language is "calculated" from the DOS country code (COUNTRY.SYS). The language can be changed (for example, for countries with more than one language) using the environment variable DW32RLC=nn, where nn is the two low hex digits from LANGID. This is equivalent to the ResourceLocale of the win32 registry, but (for example) if in win32 the code for spanish is 0000040A, in Doswin32 0A must be used. If this variable is set to 00, the ResourceLocale will always be NEUTRAL. NOTE: The DW32RLC variable can be 00 or 09 (english is always available) or MUST be equal to the same CodePage as in DOS. Otherwise the environment variable would be ignored. ----- 17. DosWin32 uses the TZ environment variable. If it is defined and has a xxx[+/-]n[n][yyy] format, the xxx is used as the timezone name and [+/-]n[n] as the time shift from UTC (in range -12 -:- +12 hours). If yyy is present then: a) yyy is the name of the daylight saving mode. b) the +1 hour value is added to the time shift. NOTE: The daylight saving time is not calculated from the date. If yyy is defined, it is used in the current DosWin32 session. --------------------------------------------------------------------------- --------------------------------------------------------------------------- II. The general restrictions and specifications (development information) 1. To run programs under debugger (currently only Borland td32) you use RD32.EXE from the DosWin32 pack or load DosWin32 core to the memory (see above) and run td32 as usual. NOTE: When td32 reports 'error loading program' it is useful to switch to the user screen (Alt-F5) to see the reason. Work this way when you start programs with unresolved imports. CAUTION: TD32 contains some VERY severe errors (in DPMI support): in 'System Information' menu, right click the mouse in the debugger window. The breakpoints are lost when the program is terminated, etc. The information about errors was sent to Borland, but they don't support td32 now. You can use patches and special DLLs on DosWin32 ftp as INFORMATION about a temporary way to bypass these errors. ----- 2. While the context is switching (launching a child process and/or working with the debugger) only the "basic" context is saved (including FPP) for the moment. The SSE-extension context is not saved even if it exists. Perhaps this will be improved in the next versions. ----- 3. The mouse control is different from that under BPP: each task has a "personal" hide/show mouse cursor state. The cursor state can be changed ONLY by ENABLED_MOUSE_INPUT (DISABLED when program is started). ----- 4. Working with registry 4.1. The restrictions are practically the same as in Win9x, but the STRONG recommendation is not to save big sizes of data in the registry. 4.2. The registry is saved to the disk only when the RegFlushKey (with any valid key) function is called or when any task is terminated. (If registry contents are not changed, the registry is not saved). 4.3. The registry file is not locked when the system works. ----- 5. The clipboard implementation only CF_TEXT and CF_OEMTEXT and RegisterClipboardFormat are supported. When DosWin32 core is in resident, the clipboard for DOS tasks is also supported. CAUTION: The translation between ANSI and OEM formats is not performed, because ANSI and OEM codepages are the same. NOTE: Because the MS DOS programs check the presence of Windows enhanced mode before they start to work with the clipboard, the system answers them that the Windows version 22.0 is present. 5.1 Restrictions of RegisterClipboardFormat(): a. Maximum possible name length - 62 chars (without 0) b. Maximum possible registered formats at the same time - 15 c. Clipboard has a single buffer - You cannot store multiple data in it in different formats simultaneously. --------------------------------------------------------------------------- --------------------------------------------------------------------------- III. The system peculiarities (development information) 1. Identification. If you want to determine if your programs work under DosWin32, the simplest method is to use GetVersion/GetVersionEx. 1.1. GetVersionEx Under DosWin32 the szCSDVersion field contains the "DW32" string and the dwPlatformId field - number 3 (this is needed for the correct work of Borland RTL that changes some behaviour under Borland 32rtm). 1.2. GetVersion GetVersion has the possibility to find that the program works under DosWin32 and the basic OS type: if(dwVersion > 0xF0000000) { // doswin32 // dwWindowsMinorVersion -> EMULATOR_VERSION dwBuild = (DWORD)LOWBYTE(HIWORD(dwVersion)); dwExecMode = (DWORD)HIBYTE(HIWORD(dwVersion)) & 3; // 0 - in DOS, 1 - on win9x, 2 - on NT } ----- 2. When working with the memory mapped files, note that the different MapViews are NOT coherent. MapView with FILE_MAP_WRITE would always be written to the file regardless of the data modifications. The use of the file mapping with FILE_MAP_WRITE is not recomended for DosWin32 programs because of poor performance (in some cases). The main goal of the file mapping under DosWin32 is to support "old" programs (such as link v7.1). The restrictions for the lpBaseAddress parameter of the MapViewOfFileEx() function are the same as under Windows NT. ----- 3. There is a nontrivial problem with the OEM-ANSI / ANSI-OEM translations. Console applications get the input string in the ANSI encoding but the output is processed in the OEM encoding (for instance, in the message "File not found: "). Under DosWin32 ANSICP == OEMCP, therefore the translation is a simple copy. On the other hand the data can be read from a file and so must be really translated. We could not find an automatic method to solve this problem and we suggest using two new functions: dpmiOemToChar[Buff]/dpmiCharToOemBuff which replace OemToCar[Buff]/CharToOem[Buff] respectively. These functions perform real translations (but not for all code pages). The current version supports code pages 437, 866, 850, 852, and 775. If you link your program by UniLink you can link these functions statically, if not - you can obtain their addresses by GetProcAddress (in user32). There is no difference in working under Win32 and DosWin32 as these functions perform the real translation. CAUTION: You MUST call dpmiNlsInit() BEFORE using these functions. The prototypes of all these functions can be found in ulnkhdr.h. ----- 4. Peculiarities of using the long names (GetShortPathName/GetLongPathName). 4.1. Usually the console applications work with !AreFileApisANSI. If you call SetFileApisANSI under DosWin32, it does nothing. So you have to translate ANSI strings yourself (dpmiCharToOem[Buff]A). 4.2. The best is to call GetShortPathName before the file operations (if your program can work with long names). 4.3. The GetShortPathName (and GetLongPathName) oddities 4.3.1. The proper error code is always set (Win32 sets FILE_NOT_FOUND even when it should be PATH_NOT_FOUND, and PATH_NOT_FOUND is set only with a bad disk name). CAUTION: If the input name is directory (i.e. it terminates with '\\') and if there is no such directory, the error code is set to PATH_NOT_FOUND. If you try to access the "illegal" device the error code is set to ERROR_BAD_DEVICE (see below). 4.3.2. In all cases the path/filename is checked for its existence. GetLongPathName (under DOS and Win9x) preserves the case in the file names. 4.3.3. The defaults are always expanded i.e. if the input string is something like ".", the output would be the full name of the current directory and for the string "D:" - the full name of the current directory on drive D:. The whole effect is equivalent to calling GetFullPathName followed by GetShortPathName/GetLongPatName under MS Windows. The combinations '.\' are removed and '..\' are processed. In other words, the output string contains the absolute full path (in 8.3 for GetShortPathName). 4.3.4. The functions DO NOT work with the "network" path and with such a path as "\\\\.\\A:". Moreover, the functions work ONLY with direct-access devices. CAUTION: The functions DO NOT work with CD-disks. In such cases you will get an ERROR_BAD_DEVICE error code. These functions do not work with SUBSTed drives neither. 4.3.5. A GetShortPathName extension. Using GetShortPathName solves all problems with long names for OPEN_EXISTING, but not for CREATE_NEW. The GetShortPathName extension should be used for the last case. IF the szBuff counter is less than zero, then -(long)szBuff is used as the counter and the function behaviour is different when it works with the LAST path element (it could be a file or a directory): a) If a file with the given name (long or short) exists, the rest of processing is as usual. b) If no files are found and the name is 8.3, then this name is returned (but the error code is set - so you can check that the file is "new"). c) If no files are found and the name is long, then a short name is generated and returned. It is a guarantee that the returned name is unique (the error code is set too). NOTE: The names returned by GetLongPathName CAN NOT be used for file operations if LFN-support is disabled. CAUTION: GetShortPathName/GetLongPathName under DosWin32 in NT works differently than in DOS - it "understands" NTFS, for instance. NOTE: NT GetLongPathName works ONLY for the file name and for the path parts that are not directly specified. If, for example, you specify the path in uppercase it will not be converted into realcase. NOTE: in NT4 the name remains in the form equivalent to what GetFullPathName returns. ----- 5. SetEnvironmentVariable under Win32 allows you to define the variables such as '=C:' with any value. In these cases, the file operation with an "uncompleted" path will generate an error. Under DosWin32 the error is generated in SetEnvironmentVariable if the path does not exist. In other words such variables are "synchronized" respectively with CurrentDirectory. ----- 6. The phantom floppy drive is absent for all disk operations (including GetLogicalDrives). This is true even for DOS tasks while DosWin32 is active. ----- 7. The maximal length of the value string for the ini-file access functions is 2Kb. Therefore the size of the struct in Get/Write-PrivateProfileStruct must be less than 1Kb. The difference to Win32 is that all these functions set the real GetLastError error codes. ini-files restrictions: maximum file length - 64Kb (as in Win32) maximum section NAME length - 128 bytes maximum key NAME length - 128 bytes maximum section DATA size - file_size - section name length maximum VALUE length - 2Kb maximum STRING length - 2560 bytes (including comment) CAUTION: When one tries to write too long data an error is reported (Win32 simply truncates the data). If the ini-file does not contain a valid struct, working with the file is impossible. ----- 8. The address space for all tasks under DosWin32 is common. Because all exe's are linked on the same base by default, it is impossible to launch one task from another if the relocation table is stripped in the exe-file. To solve this problem the tasks with the relocation tables are loaded and relocated to the highest address in the virtual address space, leaving the lowest memory for tasks without relocations. CAUTION: If some program is expected to be executable in the fixed memory range but includes a relocation table it will not work. NOTE: If in the program (library) header bit IMAGE_FILE_AGGRESIVE_WS_TRIM (UniLink key -GF:AGGRESSIVE) is set then the program will be loaded to the default base address (like a program without relocations). ----- 9. While lpApplicationName==NULL in CreateProcess then the real (full) exe-file name is put into the command line of the loaded program. ----- 10. SetActiveConsoleScreenBuffer is very restricted in functionality. It is made for programs which use it to save the screen on start and to restore it on exit. If the ScreenBuffer is different from the current, the screen is erased (and the video mode 3 is set). ----- 11. SetConsoleScreenBufferSize permits only BIOS supported screen sizes. NOTE: If the screen size is changed the screen is erased. --------------------------------------------------------------------------- --------------------------------------------------------------------------- IY. Working under Win32 (development information) If you want to run the application under Win32 you can change the signature from 'PE' to 'BPE'. Or you can use run32 from the DosWin32 pack. The drivers needed to work under WinNT and Win9x are included in the main DosWin32 file DOSWIN32.RTM. The drivers are loaded dynamically and do not need be to installed. NOTE: UniLink key -aX forces it to use DPMI for the linked program. CAUTION: Working under NT: 1. DosWin32 does not work under NT 3.51 and under NT4 it is tested only for SP6. 2. Under NT the small R0 driver is required. So before running a DPMI-task under DosWin32 for the first time you have to run the ntdinst driver installer (administrator permissions are required). After the driver is installed the administrator permissions are not needed anymore. 3. GetShortPathName/GetLongPathName behaviour is different from DOS/Win9x (see above). NOTE: To uninstall NT driver you can delete the driver file or delete the registry record. 4. The support of FPP errors doesn't work under NT for the programs which disable virtual interrupts. If a 32-bit task launches a 16-bit DOS task which generates an FPP error, the DOS task cannot process this error. The driver reports this error and the task will be terminated when first int 21h will be called. If the DOS task was launched from the DOS session, the better choice in this situation would be to close the DOS session (with 'exit'). --------------------------------------------------------------------------- V. DosWin32 core extensions (development information) 1. Resolving of unresolved imports. The current development model suggests that resolving unimplemented imports by users is "temporary" until this function will be included in the DosWin32 core. In the text below the "system DLLs" are the DLLs that are included in the DosWin32 core. 1.1. Due to the fact that the doswin32 core contains all system DLLs, the GetModuleHandle() function returns a valid HINSTANCE for them even if the LoadLibrary() function has not been called. 1.2. Here is the full list of the system DLLs in the current version: kernel32.dll, user32.dll, advapi32.dll, ole32.dll, shell32.dll, mpr.dll, ntdll.dll, version.dll, winmm.dll, oleaut32.dll, rpcrt4.dll, winspool.drv, gdi32.dll (gdi32.dll is a fake library. its purpose is to prevent the loading of the real gdi32.dll) 1.3. Console applications do not use all functions from the system DLLs. Because of this not all exported functions are implemented in the system DLLs. Also some exported functions are "dummy" functions (returning ERROR_CALL_NOT_IMPLMENTED, ERROR_INVALID_HANDLE, etc). 1.4. If an entry point in a system DLL is not implemented in DosWin32, then the programmer can use the GetProcAddress() function to determine this fact. But this approach leads to a system-dependent code and will not work for existing programs. Any entry point required by a substantial number of programs will be added into the core in the future versions. A temporary workaround is descibed in 1.5. 1.5. To solve the "unresolved imports" problem an extension DLL is introduced. Its name is DOSWIN32.EXT and it resides in the %SystemDirectory%. This DLL may be absent but if it exists, it will be loaded for all programs (exceptions are described in 1.7). When the GetProcAddress() function for an entry point of any system DLL is to return NULL, the exported functions of DOSWIN32.EXT are scanned for the specified name (or number). If the exported function is found then it is used to replace the missing entry point. CAUTON: If %SystemDirectory% contains the DOSWIN32.EXT file and it is NOT a valid DLL, no programs can be started. 1.6. DOSWIN32.EXT is an ordinary DLL, but all its imports can refer ONLY to the system DLLs. The main task for this DLL is to define dummy functions which are not present in the core. CAUTION: If you use Borland's ilink32 to build this DLL, keep in mind that it has a bug and always creates an entry point even if you do not ask for it. 1.7. If you do NOT need to load the extension DLL with your program (to save memory and for quicker load time) you can mark your program not to load this DLL. This is accomplished by setting the IMAGE_FILE_BYTES_REVERSED_LO attribute (this attribute is ignored by Win32 on x86). NOTE: Some old linkers (Borland tlink32 version < 5.0, Watcom wlink) always set this bit. New linkers (ilink32 from BCB >= 4, link from VC >= 4) do not. UniLink sets this bit if you use -ay or -aY command line switches instead of -ax or -aX). ----- 2. "Pseudo-system" DLLs. If a system DLL is not included in the DosWin32 core then you can create your own DLL with the same name (commdlg.dll, for instance, but this is dangerous: imagine that the user copies your DLL to the Win32 system directory and overwrites the standard DLL. To solve this problem the DLL loading process has been modified. For all LoadLibrary() calls (including the static linked DLLs), if the full path to the library is not specified and the file extension is .DLL (or not specified), then DosWin32 will look for a file with an .RTM extension in the %SystemDirectory%. If such a file is found, then it will be loaded, otherwise the normal DLL search sequence will be performed. So, when LoadLibrary("mydll") is called and a file named "mydll.rtm" is present in the %SystemDirectory%, then the mydll.rtm file will be loaded. ----- 3. For the extension DLLs (DOSWIN32.EXT and '.RTM' DLLs) which contain only "dummy" routines a special "forward-export" method was created. In other words the extension DLLs can be an export-only DLLs, i.e. it contains only the exports section (these DLLs can be created by the UniLink linker). 3.1. The forward-exports are created (as usual ones) by using a def-file. To create a def-file from the text description of the "dummy" routines please use the makedef.exe tool from the SAMPLES directory. The file format of this file is described in the makedef.txt file. ---------------------------------------------------------------------------- 4. Working with the third-party plug-ins. If you want that the LoadLibrary() call to be successful in the presence of unresolved imports, you can set bit 0x40 in the FileHeader.Characteristics field of the executable file. This bit is not used in any Win32 system. You can set this bit by using a hex editor (offset 0x16 from the 'PE' signature). 4.1. In additon, if this flag is set and if the library name includes the full path, all calls to LoadLibrary[Ex] will get the short file name using GetShortPathName() before performing the search. ---------------------------------------------------------------------------- 5. Send your requests to include functions and "dummy" routines in the DosWin32 core to support@doswin32.com (please describe the program for which they are needed).