windows_rpc/server_binding.rs
1//! RPC server binding management.
2//!
3//! This module provides types for creating and managing RPC server bindings,
4//! which control the server lifecycle: registration, listening, and shutdown.
5
6use std::ffi::c_void;
7use windows::Win32::System::Rpc::{
8 RPC_C_LISTEN_MAX_CALLS_DEFAULT, RpcMgmtStopServerListening, RpcServerListen,
9 RpcServerRegisterIf3, RpcServerUnregisterIf, RpcServerUseProtseqEpW,
10};
11use windows::core::{Error, HSTRING, PCWSTR};
12
13use crate::ProtocolSequence;
14
15/// Manages the lifecycle of an RPC server.
16///
17/// This struct handles the low-level details of registering an RPC interface
18/// with the Windows RPC runtime and managing the listen/stop lifecycle.
19///
20/// # Note
21///
22/// You typically don't create `ServerBinding` directly. Instead, use the
23/// generated `{Interface}Server` struct which manages this for you.
24///
25/// # Example
26///
27/// ```rust,no_run
28/// use windows_rpc::rpc_interface;
29///
30/// #[rpc_interface(guid(0x12345678_1234_1234_1234_123456789abc), version(1.0))]
31/// trait MyInterface {
32/// fn hello() -> i32;
33/// }
34///
35/// struct MyImpl;
36/// impl MyInterfaceServerImpl for MyImpl {
37/// fn hello() -> i32 { 42 }
38/// }
39///
40/// # fn main() -> windows::core::Result<()> {
41/// let mut server = MyInterfaceServer::<MyImpl>::new();
42/// server.register("my_endpoint")?;
43/// server.listen_async()?;
44/// // ... server is now accepting calls ...
45/// server.stop()?;
46/// # Ok(())
47/// # }
48/// ```
49pub struct ServerBinding {
50 protocol: ProtocolSequence,
51 endpoint: String,
52 interface_handle: *const c_void,
53 registered: bool,
54}
55
56impl ServerBinding {
57 /// Creates a new server binding for the specified endpoint.
58 ///
59 /// This registers the protocol sequence and endpoint with the RPC runtime,
60 /// but does not yet register the interface. Call [`register()`](Self::register)
61 /// to complete the registration.
62 ///
63 /// # Arguments
64 ///
65 /// * `protocol` - The protocol sequence to use
66 /// * `endpoint` - The endpoint name clients will connect to
67 /// * `interface_handle` - Pointer to the RPC interface specification
68 ///
69 /// # Errors
70 ///
71 /// Returns an error if the protocol sequence and endpoint cannot be registered.
72 pub fn new(
73 protocol: ProtocolSequence,
74 endpoint: impl Into<String>,
75 interface_handle: *const c_void,
76 ) -> Result<Self, Error> {
77 let endpoint = endpoint.into();
78 let endpoint_hstring = HSTRING::from(&endpoint);
79
80 // Register the protocol sequence and endpoint
81 unsafe {
82 RpcServerUseProtseqEpW(
83 protocol.to_pcwstr(),
84 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
85 PCWSTR::from_raw(endpoint_hstring.as_ptr()),
86 None, // No security descriptor
87 )
88 .ok()?;
89 }
90
91 Ok(ServerBinding {
92 protocol,
93 endpoint,
94 interface_handle,
95 registered: false,
96 })
97 }
98
99 /// Registers the RPC interface with the runtime.
100 ///
101 /// After registration, the server can begin accepting calls. This method
102 /// is idempotent - calling it multiple times has no effect.
103 ///
104 /// # Errors
105 ///
106 /// Returns an error if the interface cannot be registered.
107 pub fn register(&mut self) -> Result<(), Error> {
108 if self.registered {
109 return Ok(());
110 }
111
112 unsafe {
113 RpcServerRegisterIf3(
114 self.interface_handle,
115 None, // Interface UUID (use from handle)
116 None, // Manager EPV
117 0, // Flags
118 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
119 u32::MAX, // Max RPC size
120 None, // Security callback
121 None, // Security descriptor
122 )
123 .ok()?;
124 }
125
126 self.registered = true;
127 Ok(())
128 }
129
130 /// Starts listening for RPC calls (blocking).
131 ///
132 /// This method blocks the current thread until [`stop()`](Self::stop) is called
133 /// from another thread. Use [`listen_async()`](Self::listen_async) for non-blocking
134 /// operation.
135 ///
136 /// # Errors
137 ///
138 /// Returns an error if:
139 /// - The interface has not been registered
140 /// - The RPC runtime fails to start listening
141 pub fn listen(&self) -> Result<(), Error> {
142 if !self.registered {
143 return Err(Error::from_hresult(windows::core::HRESULT(-1)));
144 }
145
146 unsafe {
147 RpcServerListen(
148 1, // MinimumCallThreads
149 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
150 0, // DontWait = false (blocking)
151 )
152 .ok()?;
153 }
154
155 Ok(())
156 }
157
158 /// Starts listening for RPC calls (non-blocking).
159 ///
160 /// Returns immediately while RPC calls are processed in background threads
161 /// managed by the Windows RPC runtime. Call [`stop()`](Self::stop) to shut
162 /// down the server.
163 ///
164 /// This is the recommended mode for most applications as it allows the main
165 /// thread to continue other work or wait for a shutdown signal.
166 ///
167 /// # Errors
168 ///
169 /// Returns an error if:
170 /// - The interface has not been registered
171 /// - The RPC runtime fails to start listening
172 pub fn listen_async(&self) -> Result<(), Error> {
173 if !self.registered {
174 return Err(Error::from_hresult(windows::core::HRESULT(-1)));
175 }
176
177 unsafe {
178 RpcServerListen(
179 1, // MinimumCallThreads
180 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
181 1, // DontWait = true (non-blocking)
182 )
183 .ok()?;
184 }
185
186 Ok(())
187 }
188
189 /// Stops the server from accepting new RPC calls.
190 ///
191 /// Outstanding calls may still complete. For a blocking server, this will
192 /// cause [`listen()`](Self::listen) to return.
193 ///
194 /// # Errors
195 ///
196 /// Returns an error if the RPC runtime fails to stop.
197 pub fn stop(&self) -> Result<(), Error> {
198 unsafe {
199 RpcMgmtStopServerListening(None).ok()?;
200 }
201 Ok(())
202 }
203
204 /// Unregisters the RPC interface.
205 ///
206 /// This is called automatically when the `ServerBinding` is dropped.
207 ///
208 /// # Errors
209 ///
210 /// Returns an error if the interface cannot be unregistered.
211 pub fn unregister(&mut self) -> Result<(), Error> {
212 if !self.registered {
213 return Ok(());
214 }
215
216 unsafe {
217 RpcServerUnregisterIf(Some(self.interface_handle), None, 1).ok()?;
218 }
219
220 self.registered = false;
221 Ok(())
222 }
223
224 /// Returns the endpoint name.
225 pub fn endpoint(&self) -> &str {
226 &self.endpoint
227 }
228
229 /// Returns the protocol sequence.
230 pub fn protocol(&self) -> ProtocolSequence {
231 self.protocol
232 }
233}
234
235impl Drop for ServerBinding {
236 fn drop(&mut self) {
237 // Best effort cleanup
238 let _ = self.unregister();
239 }
240}