The current service control API directly accesses the registry for most things. In native those fucntions are simple wrappers around RPC calls to the actual service.exe application. Mikolaj Zalewski offered about 3 months ago a possible aproach to implement the service.exe program.
In there the proxy code generated through widl directly calls various RPC functions to communicate with the service manager executable. When doing some tests with native advapi32 under Wine I found that those fucntions seem to be implemented by simply calling more or less directly NdrCallClient2. Widl obviously doesn't generate code yet using this API and I'm sure wire compatibility can be achieved without using NdrCallClient2.
But a few questions that came up here: - How good or complete is Wine's NdrCallClient(2) implementation? Would it be feasable to use it for the implementation of the service rpc calls? - Assuming it would be not a whole lot of work to make NdrCallClient(2) work for this, would it be desirable to use this API instead of the code generated by widl currently from complexity and/or performance view? - Of course this would mean that widl would have to support (some of) the {Oi | Oic | Oif | Oicf} flags to generate the proxy code but as it seems the necessary code generator at least for the client side would be fairly trivial as it is mostly just a wrapper around NdrClientCall(2) and most of the nitty gritty work is done in in that function. A midl generated proxy code using -Oicf looks at least quite trivial.
Any opinions about this anyone?
Rolf Kalbermatter
Rolf Kalbermatter wrote:
The current service control API directly accesses the registry for most things. In native those fucntions are simple wrappers around RPC calls to the actual service.exe application. Mikolaj Zalewski offered about 3 months ago a possible aproach to implement the service.exe program.
Yes, we need to dig that out again. I forget what was blocking it being committed.
In there the proxy code generated through widl directly calls various RPC functions to communicate with the service manager executable. When doing some tests with native advapi32 under Wine I found that those fucntions seem to be implemented by simply calling more or less directly NdrCallClient2. Widl obviously doesn't generate code yet using this API and I'm sure wire compatibility can be achieved without using NdrCallClient2.
Exactly. The whole point of IDL in DCE/RPC is that it is independent of the DCE/RPC implementation as long as the generated code conforms to the NDR rules. With Microsoft's implementation, most of the NDR rules are implemented in rpcrt4 and all the IDL compiler as to do is output code to call the buffer size, marshall, unmarshall and free functions in the right order. widl should be correct in this respect. (There are some shortcuts that midl/widl take for marshalling base types and the alignments would have to be correct for these, but these are simple to get right.)
There is no reason to use NdrClientCall2 for any purpose in Wine.
But a few questions that came up here:
- How good or complete is Wine's NdrCallClient(2) implementation?
Pretty good, IMHO. We use exactly the code that's in Wine here at CodeWeavers for connecting to Exchange servers (the RPC code is MIDL-compiled code in DLLs used by Outlook).
Would it be feasable to use it for the implementation of the service rpc calls?
No. Everything (except multi-dimensional arrays, possibly) can already be done by the code we output already. Adding code to output -Oicf proc format strings in widl would be possible, but unnecessary.
It also adds problems because gcc and MSVC have differing opinions on how to return unions from functions. For this reason, we have implemented NdrClientCall2 in Wine by pretending it returns a LONG_PTR instead. widl would have to decide on whether it wanted to be compatible with our signature of the function or the MS one.
- Assuming it would be not a whole lot of work to make NdrCallClient(2) work
for this, would it be desirable to use this API instead of the code generated by widl currently from complexity and/or performance view?
It reduces code size (and on modern processors that is supposed to lead to performance gains), but that is the only advantage that it gives us.
- Of course this would mean that widl would have to support (some of) the
{Oi | Oic | Oif | Oicf} flags to generate the proxy code but as it seems the necessary code generator at least for the client side would be fairly trivial as it is mostly just a wrapper around NdrClientCall(2) and most of the nitty gritty work is done in in that function. A midl generated proxy code using -Oicf looks at least quite trivial.
Any opinions about this anyone?
Robert Shearman [mailto:rob@codeweavers.com] wrote:
The current service control API directly accesses the registry for most things. In native those fucntions are simple wrappers around RPC calls to the actual service.exe application. Mikolaj Zalewski offered about 3 months ago a possible aproach to implement the service.exe program.
Yes, we need to dig that out again. I forget what was blocking it being committed.
I'm myself not exactly sure what the reasons where. It looks pretty ok to me except that the way it is now with no real parameter verification in the API function itself anymore before calling into the proxy stub, the test framework will cause various debugger breaks because of the RpcRaiseExceptions() in the proxy stubs. Also Mikolaj himself mentioned at one point that this is not ready for commitment yet and I guess that might influence Alexandre's decision quite a bit :-)
Exactly. The whole point of IDL in DCE/RPC is that it is independent of the DCE/RPC implementation as long as the generated code conforms to the NDR rules. With Microsoft's implementation, most of the NDR rules are implemented in rpcrt4 and all the IDL compiler as to do is output code to call the buffer size, marshall, unmarshall and free functions in the right order. widl should be correct in this respect. (There are some shortcuts that midl/widl take for marshalling base types and the alignments would have to be correct for these, but these are simple to get right.)
There is no reason to use NdrClientCall2 for any purpose in Wine.
<snip>
No. Everything (except multi-dimensional arrays, possibly) can already be done by the code we output already. Adding code to output -Oicf proc format strings in widl would be possible, but unnecessary.
Ok, but I have made some parameter protocols to NdrClientCall2 from native advapi32 and believe that using those MIDL format informations could allow to make an idl file that would result in a fully wire compatible protocol to the MS services.exe one. It's not exactly trivial to decode the MIDL_ProcFormatString but by verifying the generated MIDL generated code against those protocolled parameters would certainly help a lot. A first not through check seems to indicate that almost every service control API has its own services.exe rpc message, so no ANSII to Widechar translation in the Advapi32.dll! Probably because there was a services.exe implementation before the widechar APIs got introduced. Also the protocol message numbers seem to have some holes, probably some undocumented APIs here.
It also adds problems because gcc and MSVC have differing opinions on how to return unions from functions. For this reason, we have implemented NdrClientCall2 in Wine by pretending it returns a LONG_PTR instead. widl would have to decide on whether it wanted to be compatible with our signature of the function or the MS one.
Isn't te difference with structs too?
Ok I let it at the way widl generates the svcctl code for now. It's not like that code generates MBs of code and if widl is good enough for most datatypes already then let it work that way. It's also possible that the performance gain by the smaller code is compensated by the more direct Ndr routine calls compared to NdrClientCall(2) which has to marshall the data entirely based on its own runtime type format parsing.
Rolf Kalbermatter
Rolf Kalbermatter wrote:
Robert Shearman [mailto:rob@codeweavers.com] wrote:
No. Everything (except multi-dimensional arrays, possibly) can already be done by the code we output already. Adding code to output -Oicf proc format strings in widl would be possible, but unnecessary.
Ok, but I have made some parameter protocols to NdrClientCall2 from native advapi32 and believe that using those MIDL format informations could allow to make an idl file that would result in a fully wire compatible protocol to the MS services.exe one. It's not exactly trivial to decode the MIDL_ProcFormatString but by verifying the generated MIDL generated code against those protocolled parameters would certainly help a lot.
We really don't want to do development in that way. It would be much better to use the information that Samba have gained in a clean way combined with documentation with the equivalent Win32 function to figure out the compatible IDL file.
A first not through check seems to indicate that almost every service control API has its own services.exe rpc message, so no ANSII to Widechar translation in the Advapi32.dll! Probably because there was a services.exe implementation before the widechar APIs got introduced. Also the protocol message numbers seem to have some holes, probably some undocumented APIs here.
This kind of work has already been done and the interface fairly well documented, so I'll point you at this documentation: http://www.hsc.fr/ressources/articles/win_net_srv/msrpc_svcctl.html