Open LinusU opened 2 months ago
This looks great so far, thanks for breaking it up! Also if you need any help or advice looking into your binary please reach out. I would love to flesh out the docs with anything useful for you.
By the way, if a function is missing, retrowin32 logs a warning about it but keeps running. So it will only matter if your binary actually calls it (where it will crash after calling a null pointer). Functions like ExitThread might not matter until you get to the end of the program, not sure.
It seems like the threading is just used to kick of one thread that connects to the internet and check some kind of latest news, stores it in the registry, and then exits. Without ExitThread
it crashed the entire program when it tried to exit, which since I've only stubbed the internet connect functions is basically immediately 😅
I'm at a point now where the program can run more than a few milliseconds! Unfortunately, it's a very tiny window, and something with the rendering seems broken. And as soon as I press anywhere it tries to call WideCharToMultiByte
.
INFO win32/src/winapi/user32/window.rs:324 user32/window/CreateWindowExA(dwExStyle:Err(300), lpClassName:Name("PocoMan Class"), lpWindowName:Some("PocoMan"), dwStyle:Ok(BORDER | DLGFRAME | SYSMENU | GROUP), X:80000000, Y:0, nWidth:1, nHeight:1, hWndParent:HANDLE(0), hMenu:0, hInstance:400000, lpParam:0) -> HANDLE(1)
This part seems a bit suspicious: X:80000000, Y:0, nWidth:1, nHeight:1
One idea is you could maybe locally stub out the CreateThread impl such that it never starts the thread in the first place, just to see what happens next. Depends on if it waits for the thread to come back though. I saw in your above list you had CreateEvent/SetEvent which are typically used for thread synchronization...
I ran the installer (via wine 😊 ) and I get this:
Running `target/debug/retrowin32 --win32-trace - '/Users/evmar/.wine/drive_c/Program Files (x86)/PocoMan/pocoman.exe'`
WARN win32/src/winapi/kernel32/dll.rs:216 load_library("wsock32.dll"): not found
WARN win32/src/winapi/kernel32/misc.rs:152 IsProcessorFeaturePresent(Ok(FLOATING_POINT_PRECISION_ERRATA)) => false
thread 'main' panicked at x86/src/ops/basic.rs:478:16:
attempt to shift left with overflow
I guess I need more of your patches?
The window size could indicate a problem, but also some apps I've seen create a window with an unknown size, then resize it later in response to some window messages. ... since I have the exe anyway I checked and that is what it does.
ghidra says:
g_hwnd = CreateWindowExA(0x300,s_PocoMan_Class_00418174,s_PocoMan_00418184,0xca0000,local_14,
local_18,1,1,(HWND)0x0,(HMENU)0x0,pHVar2,(LPVOID)0x0);
and there is some function called by the wndproc that does
GetWindowRect(g_hwnd,&local_3c);
GetClientRect(g_hwnd,&tStack_4c);
SetWindowPos(g_hwnd,(HWND)0x0,0,0, ...
My above crash is fixed in 6427aededc6dc4e161b2ad9a93788af3e342e0c5, which now reveals the actual problem was running from the wrong directory
MessageBox: PocoMan
Can't open PocoMan.map for reading
If it helps you any, feel free to send a PR that is just like "here are all the stubs I need". You don't need to send separate PRs for them if it's too much effort. (I'm fine with separate PRs, just trying to save you some effort...)
Sorry, I have had limited with time today and just cherry picked som already done work. Will give some more time to the comments later!
If it helps you any, feel free to send a PR that is just like "here are all the stubs I need"
Hehe, yeah I realized that that would probably have been a good strategy 😅
At this point I think that they are all merged though! Well, as far as I have gotten at least, will probably be a bit more when I get more time to dig further!
Thanks for all the help, and for looking into the binary yourself! As said, I'll try to read thru all your comments properly and answer in a few days
Making progress!
Updating SetWindowPos
to actually resize the host window fixed the sizing issue!
Need to implement stretching in StretchDIBits
now 🐎
...and it seems like there are some flags to flip/rotate tiles that needs to be implemented
I'm running into a really strange problem. For some reason, the application is closing its file handle whilst in the middle of reading from it. It's reading the map data, and since it then errors out goes into an error state. Making CloseHandle
a no-op fixes the issue:
diff --git a/win32/src/winapi/kernel32/file.rs b/win32/src/winapi/kernel32/file.rs
index 79e7b8a1..c8a6946f 100644
--- a/win32/src/winapi/kernel32/file.rs
+++ b/win32/src/winapi/kernel32/file.rs
@@ -382,7 +382,7 @@ pub fn SetFilePointer(
lDistanceToMove |= (**high as i64) << 32;
}
let Some(file) = machine.state.kernel32.files.get_mut(hFile) else {
- log::debug!("SetFilePointer({hFile:?}) unknown handle");
+ log::warn!("SetFilePointer({hFile:?}) unknown handle");
set_last_error(machine, ERROR_INVALID_HANDLE);
return u32::MAX;
};
diff --git a/win32/src/winapi/kernel32/misc.rs b/win32/src/winapi/kernel32/misc.rs
index d6d06472..49de0c85 100644
--- a/win32/src/winapi/kernel32/misc.rs
+++ b/win32/src/winapi/kernel32/misc.rs
@@ -279,6 +279,7 @@ pub fn FormatMessageW(
#[win32_derive::dllexport]
pub fn CloseHandle(machine: &mut Machine, hObject: HFILE) -> bool {
+ return true; // FIXME: remove this line
if machine.state.kernel32.files.remove(hObject).is_none() {
log::debug!("CloseHandle({hObject:?}): unknown handle");
set_last_error(machine, ERROR_INVALID_HANDLE);
It's happening right after the call to InternetOpenA
, which I think is called by a background thread. I'm wondering if the file handles are somehow interfering with each other from the different threads 🤔
Reading the disassembled source, there are calls to InternetCloseHandle
at the end of the function that runs in the background thread...
With the CloseHandle
patch from last comment, the first map now loads! 🙌
(something seems broken with the time in the titlebar, I just started the game in the screenshot)
Re time, I just monkeyed with it here, maybe I got something wrong: https://github.com/evmar/retrowin32/commit/0c3e48507dc5f6424d5b10b6e230046a4c2095cd
Re CloseHandle, I looked at the places where it's called in pocoman and most seemed to be error paths. But the one at address 00410419 might be it(?).
I wrote all of the threading-related stubs before retrowin32 supported threads so they are all definitely wrong. I see some use of thread-local storage in pocoman and that also is certainly wrong right now, not sure how serious it is. The function passed to CreateThread immediately calls TlsSetValue, probably to stash some sort of "current state" object.
Hm wait, the call at 0040c77d seems to be the thread function shutting down and is closing a handle found in the Tls, that seems very likely it.
(moving TLS discussion to #70 to not clutter this up)
With https://github.com/evmar/retrowin32/commit/8c1713aff5eedd229aaf1319adb5d96801ae27c2 it now plays "I am pocoman" audio on startup. Might get annoying, we can put it behind a flag if so!
With 8c1713a it now plays "I am pocoman" audio on startup. Might get annoying, we can put it behind a flag if so!
That's amazing!! 🤩
Although it seems like the audio then underflows and crashes the entire application 😅
WARN cli/src/sdl.rs:319 audiobuf underflow
thread '<unnamed>' panicked at cli/src/sdl.rs:315:34:
range start index 44544 out of range for slice of length 44100
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
libc++abi: terminating due to uncaught foreign exception
zsh: abort cargo run -p retrowin32 -F x86-emu,sdl -- --win32-trace '*' PocoMan.exe
Oh no! I pushed another commit to disable it by default until I have it all working, sorry!
I added a --audio
flag to the command line, and verified that after clicking through the first screen audio continues to work on the map if you click around. I think with StretchBlt and some keyboard support this would be pretty solid.
The bitmap code is still gross but I made it a lot less gross in https://github.com/evmar/retrowin32/commit/af32dd4fa1c63638c8dfae5d23db5c2a2e5c85c2 , with a special eye to making StretchBlt easy to implement.
sample program in exe/rust/bin/dib.rs that runs some of these functions
oh and i can run it in wine to compare!
Implemented some missing file stuff on the web site, now runs in my browser!
This issue is to track my work in getting PocoMan v4.0 running. See more background in #39
My working branch is here: https://github.com/LinusU/retrowin32/tree/pocoman
kernel32.dll
GetStartupInfoA
#40SizeofResource
#42SetEnvironmentVariableA
#44CreateEventA
/SetEvent
#45ResumeThread
#52ExitThread
#56WideCharToMultiByte
advapi32.dll
RegCreateKeyA
/RegQueryValueExA
#41RegSetValueExA
#48ole32.dll
OleInitialize
#46user32.dll
LoadMenuA
#47GetWindowRect
#53SetMenuItemInfoA
#54GetWindowPlacement
#59 + #67CreatePopupMenu
#60GetSubMenu
#61KillTimer
#63SetWindowPos
#69gdi32.dll
hdcSrc
withBLACKNESS
#50CreatePalette
#68SelectPalette
/RealizePalette
#49SetTextAlign
#66wininet32.dll
InternetOpenA
#51imul_r16_rm16
#55