windows_rpc/
lib.rs

1//! Windows RPC client and server library for Rust.
2//!
3//! This crate, together with [`windows_rpc_macros`](https://docs.rs/windows-rpc-macros), provides
4//! a way to define Windows RPC interfaces using Rust traits and automatically generate all the
5//! necessary client and server code. The generated code handles NDR (Network Data Representation)
6//! marshalling, format strings, and Windows RPC runtime integration.
7//!
8//! # Features
9//!
10//! - **Simple trait-based interface definition** - Define RPC interfaces using familiar Rust syntax
11//! - **Automatic code generation** - Client and server code generated at compile time
12//! - **Type safety** - Full Rust type system integration
13//! - **NDR marshalling** - Automatic Network Data Representation encoding/decoding
14//! - **String support** - Native handling of string parameters and return values
15//! - **Integer types** - Support for i8, i16, i32, i64, u8, u16, u32, u64
16//! - **ALPC protocol** - Fast local RPC using Advanced Local Procedure Call
17//!
18//! # Quick Start
19//!
20//! Define an RPC interface as a trait with the [`rpc_interface`] macro:
21//!
22//! ```rust
23//! use windows_rpc::rpc_interface;
24//! use windows_rpc::{ProtocolSequence, client_binding::ClientBinding};
25//!
26//! #[rpc_interface(guid(0x12345678_1234_1234_1234_123456789abc), version(1.0))]
27//! trait Calculator {
28//!     fn add(a: i32, b: i32) -> i32;
29//!     fn multiply(x: i32, y: i32) -> i32;
30//!     fn strlen(string: &str) -> u64;
31//!     fn greet(name: &str) -> String;
32//! }
33//! ```
34//!
35//! This generates three types:
36//! - `CalculatorClient` - for making RPC calls
37//! - `CalculatorServerImpl` - trait to implement for the server
38//! - `CalculatorServer<T>` - generic server wrapper for RPC dispatch
39//!
40//! # Server Example
41//!
42//! Implement the generated `ServerImpl` trait with static methods:
43//!
44//! ```rust,no_run
45//! use windows_rpc::rpc_interface;
46//!
47//! #[rpc_interface(guid(0x12345678_1234_1234_1234_123456789abc), version(1.0))]
48//! trait Calculator {
49//!     fn add(a: i32, b: i32) -> i32;
50//!     fn greet(name: &str) -> String;
51//! }
52//!
53//! struct CalculatorImpl;
54//!
55//! impl CalculatorServerImpl for CalculatorImpl {
56//!     fn add(a: i32, b: i32) -> i32 {
57//!         a + b
58//!     }
59//!
60//!     fn greet(name: &str) -> String {
61//!         format!("Hello, {}!", name)
62//!     }
63//! }
64//!
65//! fn main() -> Result<(), Box<dyn std::error::Error>> {
66//!     // Create server with the implementation type
67//!     let mut server = CalculatorServer::<CalculatorImpl>::new();
68//!     server.register("calculator_endpoint")?;
69//!
70//!     // Non-blocking: returns immediately, processes calls in background
71//!     server.listen_async()?;
72//!
73//!     println!("Server is running...");
74//!
75//!     // Keep the server running
76//!     std::thread::sleep(std::time::Duration::from_secs(60));
77//!
78//!     // Clean shutdown
79//!     server.stop()?;
80//!     Ok(())
81//! }
82//! ```
83//!
84//! # Client Example
85//!
86//! Make RPC calls using the generated client:
87//!
88//! ```rust,no_run
89//! use windows_rpc::rpc_interface;
90//! use windows_rpc::{ProtocolSequence, client_binding::ClientBinding};
91//!
92//! #[rpc_interface(guid(0x12345678_1234_1234_1234_123456789abc), version(1.0))]
93//! trait Calculator {
94//!     fn add(a: i32, b: i32) -> i32;
95//!     fn greet(name: &str) -> String;
96//! }
97//!
98//! fn main() -> Result<(), Box<dyn std::error::Error>> {
99//!     // Create a client binding
100//!     let binding = ClientBinding::new(ProtocolSequence::Alpc, "calculator_endpoint")?;
101//!     let client = CalculatorClient::new(binding);
102//!
103//!     // Make RPC calls - integers
104//!     let result = client.add(10, 20);
105//!     println!("10 + 20 = {result}");  // Prints: 10 + 20 = 30
106//!
107//!     // Make RPC calls - strings
108//!     let greeting = client.greet("Alice");
109//!     println!("{greeting}");  // Prints: Hello, Alice!
110//!
111//!     Ok(())
112//! }
113//! ```
114//!
115//! # Complete Example with String Operations
116//!
117//! Here's a more comprehensive example showcasing various string operations:
118//!
119//! ```rust,no_run
120//! use windows_rpc::{rpc_interface, ProtocolSequence, client_binding::ClientBinding};
121//!
122//! #[rpc_interface(guid(0xabcdef12_3456_7890_abcd_ef1234567890), version(1.0))]
123//! trait StringService {
124//!     fn to_uppercase(text: &str) -> String;
125//!     fn reverse(text: &str) -> String;
126//!     fn count_words(text: &str) -> u32;
127//!     fn concat(a: &str, b: &str) -> String;
128//! }
129//!
130//! struct StringServiceImpl;
131//!
132//! impl StringServiceServerImpl for StringServiceImpl {
133//!     fn to_uppercase(text: &str) -> String {
134//!         text.to_uppercase()
135//!     }
136//!
137//!     fn reverse(text: &str) -> String {
138//!         text.chars().rev().collect()
139//!     }
140//!
141//!     fn count_words(text: &str) -> u32 {
142//!         text.split_whitespace().count() as u32
143//!     }
144//!
145//!     fn concat(a: &str, b: &str) -> String {
146//!         format!("{}{}", a, b)
147//!     }
148//! }
149//!
150//! fn main() -> Result<(), Box<dyn std::error::Error>> {
151//!     // Start server
152//!     let mut server = StringServiceServer::<StringServiceImpl>::new();
153//!     server.register("string_service")?;
154//!     server.listen_async()?;
155//!
156//!     // Create client
157//!     let client = StringServiceClient::new(
158//!         ClientBinding::new(ProtocolSequence::Alpc, "string_service")?
159//!     );
160//!
161//!     // Test string operations
162//!     println!("{}", client.to_uppercase("hello"));              // Output: HELLO
163//!     println!("{}", client.reverse("hello"));                   // Output: olleh
164//!     println!("{}", client.count_words("hello world"));         // Output: 2
165//!     println!("{}", client.concat("Hello, ", "World!"));        // Output: Hello, World!
166//!
167//!     server.stop()?;
168//!     Ok(())
169//! }
170//! ```
171//!
172//! # Supported Types
173//!
174//! The following types can be used for parameters and return values:
175//!
176//! | Rust Type | Parameters | Return Values | Notes |
177//! |-----------|------------|---------------|-------|
178//! | `i8`, `u8` | ✓ | ✓ | 8-bit integers |
179//! | `i16`, `u16` | ✓ | ✓ | 16-bit integers |
180//! | `i32`, `u32` | ✓ | ✓ | 32-bit integers |
181//! | `i64`, `u64` | ✓ | ✓ | 64-bit integers |
182//! | `&str` | ✓ | ✗ | String input parameters |
183//! | `String` | ✗ | ✓ | String return values |
184//!
185//! # Protocol Support
186//!
187//! Currently only ALPC (Advanced Local Procedure Call) is supported via the `ncalrpc`
188//! protocol sequence. This allows RPC communication between processes on the same machine.
189//!
190//! # What This Library Does
191//!
192//! - Generates all MIDL stub metadata (`MIDL_STUB_DESC`, `MIDL_SERVER_INFO`, etc.)
193//! - Handles NDR 2.0 and NDR64 format strings for type marshalling
194//! - Manages RPC binding handles and server lifecycle
195//! - Converts between Rust types and Windows ABI types
196//! - Provides clean async (non-blocking) and sync (blocking) server modes
197//!
198//! # Limitations
199//!
200//! This library is currently limited in scope:
201//!
202//! - **Protocol**: Only local RPC (ALPC/ncalrpc) is supported. TCP, UDP, and named pipes
203//!   are not yet implemented.
204//! - **Parameter direction**: Only input (`[in]`) parameters and return values (`[out]`) are
205//!   supported. Input-output parameters are not available.
206//! - **Types**: Only primitive integers and strings are supported. No pointers, structs,
207//!   arrays, unions, or other complex types.
208//! - **Security**: No interface security (authentication, authorization, encryption) is
209//!   implemented.
210//! - **Exceptions**: SEH exceptions from the RPC runtime are not caught or handled.
211//! - **Callbacks**: RPC callbacks from server to client are not supported.
212//!
213//! # Interoperability
214//!
215//! The generated code produces standard Windows RPC interfaces that are compatible with
216//! MIDL-generated C/C++ clients and servers. You can use a Rust server with a C++ client
217//! (or vice versa) as long as the interface GUID, version, and method signatures match.
218//!
219//! # Safety
220//!
221//! This crate uses `unsafe` code extensively to interact with the Windows RPC runtime.
222//! The generated client and server code manages memory carefully to ensure:
223//!
224//! - RPC metadata structures remain valid for the lifetime of the client/server
225//! - String conversions between Rust and Windows types are handled correctly
226//! - Memory allocated by the server for return values is properly managed
227//! - Static trait methods are called correctly via monomorphization
228//!
229//! However, bugs in this crate could lead to memory corruption or undefined behavior.
230//!
231//! # Implementation Details
232//!
233//! The server implementation uses:
234//! - **Generic server structs**: `{Interface}Server<T>` is generic over the implementation type
235//! - **Static trait methods**: Server trait methods don't take `&self`, making implementations stateless
236//! - **Monomorphization**: Each instantiation of `Server<ConcreteType>` generates type-specific wrapper functions
237//! - **Extern "C" wrappers**: Generated wrapper functions bridge the RPC runtime to Rust static methods
238#![cfg(windows)]
239
240#[doc(hidden)]
241pub mod alloc;
242pub mod client_binding;
243pub mod server_binding;
244
245pub use windows_rpc_macros::rpc_interface;
246
247/// Protocol sequence for RPC communication.
248///
249/// Specifies the transport protocol used for RPC calls.
250///
251/// # Example
252///
253/// ```rust,no_run
254/// use windows_rpc::{ProtocolSequence, client_binding::ClientBinding};
255///
256/// # fn main() -> windows::core::Result<()> {
257/// // Connect using local RPC (ALPC)
258/// let binding = ClientBinding::new(ProtocolSequence::Alpc, "my_endpoint")?;
259/// # Ok(())
260/// # }
261/// ```
262#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
263pub enum ProtocolSequence {
264    /// ALPC (Advanced Local Procedure Call) - local RPC on the same machine.
265    ///
266    /// Uses the `ncalrpc` protocol sequence. This is the fastest option for
267    /// communication between processes on the same Windows machine.
268    Alpc,
269    // TODO: test and add
270    //Tcp,
271    //Udp,
272    //NamedPipe
273}
274
275impl ProtocolSequence {
276    fn to_pcwstr(self) -> windows::core::PCWSTR {
277        match self {
278            ProtocolSequence::Alpc => windows::core::w!("ncalrpc"),
279        }
280    }
281}