mod generated {
include!(concat!(env!("OUT_DIR"), "/msvbvm60_exports_generated.rs"));
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CallingConv {
Fastcall,
Stdcall,
Cdecl,
Special,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VbParamType {
Void,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt8,
Float,
Double,
Bool,
Bstr,
BstrPtr,
VariantPtr,
SafeArrayPtr,
SafeArrayPtrPtr,
IUnknownPtr,
IUnknownPtrPtr,
IDispatchPtr,
IDispatchPtrPtr,
Hresult,
GuidPtr,
VoidPtr,
Int32Ptr,
Int16Ptr,
UInt8Ptr,
Int64Ptr,
}
#[derive(Debug, Clone, Copy)]
pub struct ExportParam {
pub ty: VbParamType,
pub name: &'static str,
}
#[derive(Debug, Clone, Copy)]
pub struct ExportSignature {
pub name: &'static str,
pub ordinal: u16,
pub calling_convention: CallingConv,
pub return_type: VbParamType,
pub variadic: bool,
pub params: &'static [ExportParam],
pub category: &'static str,
}
pub fn lookup_export(name: &str) -> Option<&'static ExportSignature> {
generated::lookup_export_by_name(name)
}
pub fn lookup_export_by_ordinal(ordinal: u16) -> Option<&'static ExportSignature> {
generated::lookup_export_by_ordinal(ordinal)
}
pub fn all_exports() -> &'static [ExportSignature] {
generated::EXPORTS
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lookup_vba_free_str() {
let sig = lookup_export("__vbaFreeStr").expect("__vbaFreeStr not found");
assert_eq!(sig.calling_convention, CallingConv::Fastcall);
assert_eq!(sig.return_type, VbParamType::Void);
assert_eq!(sig.params.len(), 1);
assert_eq!(sig.params[0].ty, VbParamType::BstrPtr);
assert!(!sig.variadic);
}
#[test]
fn lookup_vba_free_str_list() {
let sig = lookup_export("__vbaFreeStrList").expect("not found");
assert_eq!(sig.calling_convention, CallingConv::Cdecl);
assert!(sig.variadic);
}
#[test]
fn lookup_by_ordinal() {
let sig = lookup_export_by_ordinal(598).expect("ordinal 598 not found");
assert_eq!(sig.name, "rtcDoEvents");
assert_eq!(sig.calling_convention, CallingConv::Stdcall);
}
#[test]
fn lookup_missing_returns_none() {
assert!(lookup_export("nonexistent_function").is_none());
assert!(lookup_export_by_ordinal(9999).is_none());
}
#[test]
fn table_is_sorted_by_name() {
let exports = all_exports();
for w in exports.windows(2) {
assert!(
w[0].name <= w[1].name,
"table not sorted: {:?} > {:?}",
w[0].name,
w[1].name
);
}
}
#[test]
fn ordinals_are_unique() {
let exports = all_exports();
let ordinals: Vec<u16> = exports
.iter()
.filter(|e| e.ordinal > 0)
.map(|e| e.ordinal)
.collect();
let mut deduped = ordinals.clone();
deduped.sort();
deduped.dedup();
assert_eq!(ordinals.len(), deduped.len(), "duplicate ordinals found");
}
#[test]
fn all_exports_nonempty() {
assert!(
all_exports().len() > 100,
"expected >100 exports, got {}",
all_exports().len()
);
}
}