This is already fixed, I'll post an updated launcher a bit later.[*]Since one of the easiest ways to get a full file path is to Shift+Right-Click a filename and select "Copy as Path" (which quotation-wraps the path), it would really help to have quotation marks handled correctly (I know you're working on it).
I agree with you, but this would require some internal redesign. The easiest method would be to open the log file automatically on crash, and to set LogLevel=1 by default.[*]Although the latest launcher is better about providing failure messages, it would still help a lot to have it show something in all failure cases. For example, if a required DLL can't be found, it exits silently right now (ideally, it would mention the specific file needed).
Launcher is just a temporary solution. Later there would be automatic detection of x86 apps without a launcher and the programs would be run transparently to end-user. You'd be able to create shortcuts, and so on.[*]Rather than using the system tray, why not just have the launcher sit in the taskbar? That's a lot more touch-friendly.
As far as I remember, image file execution options are applied after the OS checks for the file validity. I'll be using a different method to automate running of x86 EXEs.[*]Please implement passing EXE paths as parameters (either to launcher or peloader). This would make it easy to script the launcher, would allow drag-and-drop on the launcher EXE or right-click-> Send To if a shortcut to the launcher was added there, or automatically launching the emulation layer using filetype associations (.exe_x86 or similar) or possibly Image File Execution Options. Might be required MRU lists to work right anyhow.
set EMU_PROGRAM=%1
:loop
"c:\program files\win86emu\peloader.exe" %2 %3 %4 %5 %6 %7 %8 %9
if %errorlevel%==3134193664 goto loop
There would be no problem launching executables that contain relocations information. But most of the old EXEs does not, so I'm using this trick:[*]Non-ASLR large programs (for example, many installers) can be really hard to start. The thing is, most of those programs are perfectly compatible with ASLR, they just don't know it (it's just a flag in the binary); having an option to force the dynamic base behavior would be good just to see if it will work anyhow.
This is exactly what I'm doing now. peloader.exe - is a tiny loader that reserves the memory at its start. It determines the program image base and image size and reserves the memory at that address. If the address is already used - it exits complaining about ASLR. Here I abuse ASLR for my own needs - at next program start OS would be using different addresses for its data (environment block and so on), so I usually can reserve needed memory at 1-2 restarts.[*]Lacking that / as an alternative solution to the ASLR problem, it might work to create a really tiny launcher program that temporarily reserves a bunch of memory at the default load address, then dynamically loads the actual launcher code to help ensure that the launcher code doesn't get loaded into the default space.
I'm really curious how you're going to implement the auto-detection.
My vivotab rt is being delivered today. So, forgive me for my question. Will this allow starcraft (the original) to run? Please don't kill me.
As far as I can tell yes, but not yet and maybe not ever at the speeds required to play properly. Lots of dlls would need implementing etc...
Trying to run Slender x86, it say that i miss Opengl32.dll
What can i do?
[092DF098]W: 051B0000-05201000 : D:\The Sims 1\IMM32.dll
[092DF0A7]E: Import User32InitializeImmEntryTable not found in C:\Program Files\win86emu\System32\USER32.86.dll
[092DF0A7]E: Import WCSToMBEx not found in C:\Program Files\win86emu\System32\USER32.86.dll
[092DF0D6]W: 05210000-05214000 : D:\The Sims 1\API-MS-Win-Core-LocalRegistry-L1-1-0.dll
[092DF0E6]E: PeLdr can't open file: API-MS-Win-Security-Base-L1-1-0.dll
[092DF0E6]E: Import dll API-MS-Win-Security-Base-L1-1-0.dll not found
[092DF0E6]E: Import dll IMM32.dll not found
[092DF0F6]E: Error loading program: 1168
[092DF0F6] Logger unloaded
In an effort to curtail the sudden deluge of "what can I run?/Why can't I run.../It doesn't work!" posts on here (which I admit I may have contributed to), it may help to start up a second thread for win86emu app compatibility. Leave this thread for development and bug reports. Use the other thread to list compatible apps and help people solve incompatibilities, and to give people a place they can request support for certain DLLs or entire apps.
I could create this thread if you wish, although the "ported apps" thread already takes up a noticeable amount of time what with testing things.
Not exactly a port, it is a clean remake based on the old ideas.heh, is this a port of the app you showed off back in the CE days? -awesome getting that ported over
The idea is very simple:
#define DEFINE_FUNC1(name) \
static const ModuleDef str_##name={DLL_NAME,#name}; \
EXTERN_C DW STUB_EXPORT stub_##name(DW p1) \
{ \
DW *p=&p1; \
__asm { mov eax,p } \
__asm { jmp f1 } \
__asm { mov eax,offset str_##name } \
f1: __asm { in eax,0xe5 } \
__asm { mov p,eax } \
return (DW)p; \
}
.....
#define DEFINE_FUNC3(name) \
static const ModuleDef str_##name={DLL_NAME,#name}; \
EXTERN_C DW STUB_EXPORT stub_##name(DW p1,DW p2,DW p3) \
{ \
DW *p=&p1; \
__asm { mov eax,p } \
__asm { jmp f1 } \
__asm { mov eax,offset str_##name } \
f1: __asm { in eax,0xe5 } \
__asm { mov p,eax } \
return (DW)p; \
}
....
DEFINE_FUNC1(AddAtomA)
DEFINE_FUNC1(AddAtomW)
DEFINE_FUNC7(CreateFileA) -- number in macro == number of parameters to a __stdcall WinAPI function.
Compiler automatically generates "ret N*4" at the end of such function.
I've decided to use such c+asm approach instead of making a tiny assebler stub,
as I can easily implement some of such functions in C directly in a stub DLL plus it
simplifies debugging. And the functions have a usual C prologue/epilogue, so that
the emulated program may even patch them in runtime, for example for hooks.
...
#define DEFINE_FUNC1(name) \
EXTERN_C DW STUB_IMPORT name(DW); \ -- this behaves like a function prototype to compiler
EXTERN_C DW STUB_EXPORT yact_##name(DW *R) \ -- R - pointer to the x86 stack
{ \
DW r=name(p1); \ // call the func passing it paramers from the emulated stack, p1==R[0], p2==R[1] and so on
LEAVE(1); \ // empty macro, as the stack is unwinded in x86 stub DLL now
return r; \
}
...
#define DEFINE_FUNC3(name) \
EXTERN_C DW STUB_IMPORT name(DW,DW,DW); \
EXTERN_C DW STUB_EXPORT yact_##name(DW *R) \
{ \
DW r=name(p1,p2,p3); \
LEAVE(3); \
return r; \
}
...
DEFINE_FUNC1(AddAtomA)
DEFINE_FUNC1(AddAtomW)
DEFINE_FUNC7(CreateFileA) // as you see - implementation part is identical to an x86 stub, so I can use the same stub-generator tool
static DWORD WINAPI ThreadProc(
LPVOID lpParameter // [0] == orig func, [1] == orig param
)
{
__EXCEPTION_REGISTRATION_RECORD R;
DWORD *Parm=(DWORD*)lpParameter;
DWORD *TEB=(DWORD*)PeLdrGetCurrentTeb();
R.Next=(__EXCEPTION_REGISTRATION_RECORD*)-1;
R.Handler=(void*)CbReturnToHost();
TEB[0]=(DWORD)&R; // in case of unhandled exception - just return
PeLdrNotifyNewThread(NULL,DLL_THREAD_ATTACH);
DWORD Ret=EmuExecute(Parm[0],1,Parm[1]); // 1 == number of parameters to the emulated function
delete Parm;
return Ret;
}
EXTERN_C DW STUB_EXPORT yact_CreateThread(DW *R)
{
DWORD* Parm=new DWORD[2];
Parm[0]=p3; // TODO: no out-of-memory checking for now
Parm[1]=p4;
DWORD StackSize=p2;
if(StackSize)
StackSize+=1024*1024; // I reserve some space for my own needs (debugging)
else
StackSize=2*1024*1024; // TODO: I don't support autogrow stacks, so reserve 2 Mb
DWORD t=(DWORD)CreateThread((LPSECURITY_ATTRIBUTES)p1,StackSize,ThreadProc,Parm,p5,(LPDWORD)p6);
LEAVE(6);
return t;
}