Eric Pouech eric.pouech@wanadoo.fr writes:
this will still cause problems (for example while compiling for mingw) Alexandre, do you have some global plans for splitting further... not linking on compilation unit will not be sufficient, we need a finer grain control
I think linking on compilation units should work just fine. You may need in some cases to add a callback for the 32-bit code; for instance in that case you could have some kind of pLoadWin16Driver function pointer in the 32-bit code that is initialized to NULL, and when the 16-bit part is loaded it makes it point to one of its routines. Of course this kind of things should be avoided as much as possible, but there are a few cases where it will be necessary.
this will still cause problems (for example while compiling for mingw) Alexandre, do you have some global plans for splitting further... not linking on compilation unit will not be sufficient, we need a finer grain control
I think linking on compilation units should work just fine. You may need in some cases to add a callback for the 32-bit code; for instance in that case you could have some kind of pLoadWin16Driver function pointer in the 32-bit code that is initialized to NULL, and when the 16-bit part is loaded it makes it point to one of its routines. Of course this kind of things should be avoided as much as possible, but there are a few cases where it will be necessary.
ok compilation unit is fine when you have two DLLs side by side (one 32 bit, the other one is 16); and 16 bit API is a subset (or equiv) to the 32 bit API what you would need in some cases, for callback, is to create 32 bit callbacks for 16 bit procedure. however, if the address of the 16 callback is not passed back in the callback (DDEML for example), then you should create some 32 bit code to do the glue. I may extend winebuild to create such callbacks (like the old CreateProcInstance, but where instead of setting ds, you'd add another parameter to the callback)
some other cases are not covered. it's the case in any OWA implementation of a DLL, where drivers can be either 16 and 32 bit (that's the case for winmm) in that case, I think your pointer would work just fine. it would take a bit more than just the load driver, but also sendmessage, unload... but that's doable (I'll try that for winmm too)
btw: don't apply my mmio patch yet (I'm working on a better implementation)
A+
Eric Pouech eric.pouech@wanadoo.fr writes:
what you would need in some cases, for callback, is to create 32 bit callbacks for 16 bit procedure. however, if the address of the 16 callback is not passed back in the callback (DDEML for example), then you should create some 32 bit code to do the glue. I may extend winebuild to create such callbacks
In that case you need a small thunk to call the 16-bit proc, we are doing this at a number of places already. I don't really see how you would do that in winebuild since they need to be allocated dynamically.
I don't really see how you would do that in winebuild since they need to be allocated dynamically.
well, address is only known as runtime, but call framework is always the same. if the number of thunks is fixed (which is anyway the assumption made in existing code), then the code can be generated automatically (of course will eat up lots of pages) dynamic generation is a bit more of code, but since it's the way it's done in the rest of the code... A+
Eric Pouech eric.pouech@wanadoo.fr writes:
well, address is only known as runtime, but call framework is always the same. if the number of thunks is fixed (which is anyway the assumption made in existing code), then the code can be generated automatically (of course will eat up lots of pages)
I still don't follow you. Why do you say that the number of thunks is fixed? If you mean the number of different types of callback functions, then yes, that's what the glue code does. But this is already implemented so I don't see why you'd need something else. All the dynamic thunk has to do is to retrieve the 16-bit callback address and call the corresponding glue function. And in the vast majority of cases you can retrieve the callback address without creating any thunk at all; even if the callback doesn't have an lparam you can use, there's usually a handle to an object where you can store the info.
Alexandre Julliard a écrit :
Eric Pouech eric.pouech@wanadoo.fr writes:
well, address is only known as runtime, but call framework is always the same. if the number of thunks is fixed (which is anyway the assumption made in existing code), then the code can be generated automatically (of course will eat up lots of pages)
I still don't follow you. Why do you say that the number of thunks is fixed?
I was referring to allocating them in a fixed size heap
If you mean the number of different types of callback functions, then yes, that's what the glue code does. But this is already implemented so I don't see why you'd need something else. All the dynamic thunk has to do is to retrieve the 16-bit callback address and call the corresponding glue function. And in the vast majority of cases you can retrieve the callback address without creating any thunk at all; even if the callback doesn't have an lparam you can use, there's usually a handle to an object where you can store the info.
well it depends what you want to achieve: whether you want 32 bit code to know if 16 bit procs exist or not I was willing to have the 16 bit code only calling thru the official 32 bit API, so any knowledge of 16 bit entities can be removed from 32 bit code (which of course requires a bit more work) A+
Eric Pouech eric.pouech@wanadoo.fr writes:
well it depends what you want to achieve: whether you want 32 bit code to know if 16 bit procs exist or not I was willing to have the 16 bit code only calling thru the official 32 bit API, so any knowledge of 16 bit entities can be removed from 32 bit code (which of course requires a bit more work)
Well, in general it's better to avoid having the 32-bit code know about the 16-bit one, but there are cases where that cannot be avoided so we can't be 100% "pure" anyway. And if sticking a 16-bit pointer in a 32-bit structure avoids creating all sorts of ugly thunking stuff then it's worth it.
Alexandre Julliard a écrit :
Eric Pouech eric.pouech@wanadoo.fr writes:
well it depends what you want to achieve: whether you want 32 bit code to know if 16 bit procs exist or not I was willing to have the 16 bit code only calling thru the official 32 bit API, so any knowledge of 16 bit entities can be removed from 32 bit code (which of course requires a bit more work)
Well, in general it's better to avoid having the 32-bit code know about the 16-bit one, but there are cases where that cannot be avoided so we can't be 100% "pure" anyway. And if sticking a 16-bit pointer in a 32-bit structure avoids creating all sorts of ugly thunking stuff then it's worth it.
agreed. but if you really want to split, the glue code must be generated from the 16 bit code only, thus the 32 bit code cannot link directly to the glue code (the kind of pointer you suggested in some previous mail).
anyway, the complete mmio implementation (for 16 bit API) would require thunks (we need to export segmented pointers to native 32 bit functions, as well as calling 16 bit segmented pointers without any object at hand). but as a first step (since I don't know any 16 bit app using this), storing both 16 & 32 function pointers in 32 bit code would behave sufficiently correctly (read as it does today)
I think I'll have to rewrite the mmio patch (for a third time)
A+
Eric Pouech eric.pouech@wanadoo.fr writes:
agreed. but if you really want to split, the glue code must be generated from the 16 bit code only, thus the 32 bit code cannot link directly to the glue code (the kind of pointer you suggested in some previous mail).
It seems we are still not understanding each other. Of course the glue code would be in 16-bit code with that technique; *everything* would be in the 16-bit code except for an extra field in the 32-bit structure. SetAbortProc16 is a good example of what I mean.
Alexandre Julliard a écrit :
Eric Pouech eric.pouech@wanadoo.fr writes:
agreed. but if you really want to split, the glue code must be generated from the 16 bit code only, thus the 32 bit code cannot link directly to the glue code (the kind of pointer you suggested in some previous mail).
It seems we are still not understanding each other. Of course the glue code would be in 16-bit code with that technique; *everything* would be in the 16-bit code except for an extra field in the 32-bit structure. SetAbortProc16 is a good example of what I mean.
unfortunately, this doesn't apply to (directly) to the mmio interface: - most (*) the outter functions (mmioOpen/mmioClose...) use a handle to a mmio object - the mmioXXX functions are mapped (from some of them) to ioProc which handle part of the work (one parameter of ioProc being a message describing the action to be taken) - so far, nothing really new, the plain old service/driver architecture (*) however, what some API designs for mmio don't work with your scheme: + ioProc get a handle thru the MMIOINFO structure + however, this field is not always filled (for example, the message MMIOM_RENAME doesn't use it)
which leaves as solutions (assuming we store the 16 bit segmented pointer for the ioProc in the 32 bit part) 1/ use reserved fields of MMIOINFO to store this pointer 1bis/ use extra fields of MMIOINFO to store this pointer. for example, ensure that when a ioProc is called, the pointer to MMIOINFO points to a MMIOINFO struct contiguous to some extra information. this extra information would then be used in the "proxy" (32=>16) ioProc 1bis would a bit safer since, even if MS says the fields are reserved, values stored in them are passed to the ioProc (but I don't know of any app making use of it) 2/ from 32 bit code, call a wrapper for the 16 bit call, with an extra parameter compared to the standard ioProc (the segmented address of callback). It's what is done in user32/ddeml. However, to let the 16 bit DLL to be splitted, the wrapper function must called thru a pointer (the 16 bit library would initialize this pointer if it's loaded, as you suggested before).
sorry for making this discussion so long, but I'd prefer there's an agreement and a clear scheme defined so that it can be safely applied across all DLLs. There are lots of ways for doing it, but it's better we select a few of them. It'll be easier to maintain.
A+
Eric Pouech eric.pouech@wanadoo.fr writes:
2/ from 32 bit code, call a wrapper for the 16 bit call, with an extra parameter compared to the standard ioProc (the segmented address of callback). It's what is done in user32/ddeml. However, to let the 16 bit DLL to be splitted, the wrapper function must called thru a pointer (the 16 bit library would initialize this pointer if it's loaded, as you suggested before).
sorry for making this discussion so long, but I'd prefer there's an agreement and a clear scheme defined so that it can be safely applied across all DLLs. There are lots of ways for doing it, but it's better we select a few of them. It'll be easier to maintain.
Definitely. I think the SetAbortProc method is the easiest so we should use that where possible; but clearly there are cases like mmio where it's not enough. In these cases I'd suggest your method 2/, it's cleaner than generating code on the fly or adding private information in Windows structures.