-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Get poco-w95.exe running #39
Conversation
(On phone sorry for brevity) This looks great so far! I will give a more thorough review when I get to a computer. The changes look pretty right to me, but I expected shell32.rs to be empty, not contain generated code (?) Re the startup info, I think the way the api is supposed to work is the caller provides the size of the struct, because the struct changed size in different windows versions and you want to be sure to only fill in the part they actually allocated space for. However as you observed I am not sure what was supposed to happen when the size param is zero, hm. Maybe there is some default minimum size to use or something like that? I will investigate when I get the chance. Really cool you’re getting this working! |
This is indeed interesting. I had a hard time figuring out how to add a new dll at all, and I thought that I created the I'll remove it 👍
I'll try to find some more info on this as well! How would you prefer that I structure my work forward? I'm thinking now that it might have been better if this would have been two or three pull requests (one for I think that maybe I would prefer having an issue open where I track my progress with links to PRs and list of my next steps. And then I'll submit PRs for each isolated change and rebase my working branch on your main branch after each PR merged. To put it more concretely: I would open a PR for I see a few benefits with this:
Does this sounds good to you? |
I'm happy to merge as you go, with whatever works best for you. Your proposal is sensible. My only caveat is that I have been really short on time lately (kid stuff), I am super embarrassingly behind on another PR that I am close to finally merging. I'd be happy to merge this as you go. |
@@ -77,18 +81,18 @@ pub fn find_resource<'a>( | |||
hInstance: HINSTANCE, | |||
typ: ResourceKey<&Str16>, | |||
name: ResourceKey<&Str16>, | |||
) -> Option<&'a [u8]> { | |||
) -> Option<Range<usize>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This range is a span within the 32-bit memory right? For consistency I've been using u32s for these, which helps a bit with keeping straight which kind of things we're talking about. On wasm usize=u32 anyway but on other platforms it's 32-bit vs 64-bit.
let image = mem.slice(hInstance..); | ||
|
||
let resource = &image[handle.1.clone()]; | ||
|
||
machine.mem().offset_of(resource.as_ptr()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I followed this math, this could be just hInstance + handle.1
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to get all the pointers straight:
- pe::find_resource returns a range that is within the image
- maybe kernel32::find_resource should return a range that is within the process memory (so with hInstance already added)?
- so then this would only need to return handle.1?
win32/src/winapi/user32/resource.rs
Outdated
@@ -75,6 +75,8 @@ fn load_bitmap( | |||
ResourceKey::Id(pe::RT::BITMAP as u32), | |||
name, | |||
)?; | |||
let image = machine.mem().slice(hInstance..); | |||
let buf = &image[buf]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... and if find_resource returns Range, this can be something like mem().slice(range)
or so?
let image = mem.slice(hInstance..); | ||
if hInstance == kernel32.image_base { | ||
let section = kernel32.resources.as_slice(image)?; | ||
Some(&image[pe::find_resource(section, typ.into_pe(), name.into_pe())?]) | ||
pe::find_resource(section, typ.into_pe(), name.into_pe()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I'm looking, I wonder if pe::find_resource ought to return a Range as well, hm. If you look at its impl you can see it has u32s and it only casts to usize on the way out.
@@ -322,8 +322,11 @@ unsafe impl ::memory::Pod for STARTUPINFOA {} | |||
pub fn GetStartupInfoA(_machine: &mut Machine, lpStartupInfo: Option<&mut STARTUPINFOA>) -> u32 { | |||
// MSVC runtime library passes in uninitialized memory for lpStartupInfo, so don't trust info.cb. | |||
let info = lpStartupInfo.unwrap(); | |||
let len = std::cmp::min(info.cb, std::mem::size_of::<STARTUPINFOA>() as u32); | |||
let len = std::mem::size_of::<STARTUPINFOA>() as u32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I checked and I now believe that STARTUPINFOA has never changed in size, so my worries about callers passing in an undersized buffer or something like that are unfounded. And further I checked and at least win2k's kernel32.dll does exactly what you've done here, so I think this is correct.
I have now managed to run enough of the program to realize that I'm running an installer, and not the actual game 😂 |
As I've understand GetStartupInfoA, the caller always passes a pointer to uninitialized memory, and the function will then fill in the values. Before this change, GetStartupInfoA read the value of cb as an input parameter to get the length of the struct. In my program that part of the memory was uninitialized and happened to be 0, so the rest of the values were never zeroed out, leading to garbage data being returned in the other field. This change make sure to zero out the entire struct, and then sets cb to the actual length of the struct.
Thanks for the comments! I've adressed them and also implemented my plan resulting in the following things that replaces this PR: |
Hello! 👋
This is my first contribution so I'm sure that I got a lot of things wrong! 🙈
First of all, I just want to say that I think that this is a really cool project, and as someone who has worked on a gameboy emulator in Rust before, I like that this takes a similar approach. I'm currently trying to get the classic game Pocoman working.
Opening this for some early feedback since I've already made some changes to existing functions in
kernel32.dll
and I think that it would be great to get some feedback on that, and maybe even get those changes merged as I continue on with implementing more functions.The changes to
GetStartupInfoA
was necessary since some garbage pointers was returned incbReserved2
andlpReserved2
otherwise, which made the game crash with an oob error otherwise.This is the binary I'm trying to get running: https://www.sleepless.com/pocoman/poco-w95.exe
Relevant documentation: