If a dll exports some functions and the functions have only ordinal numbers, how can I call the functions?
Give me a short example please.
The documentation for GetProcAddress explains that you pass the integer ordinal in the low-order word of the lpProcName parameter. The MAKEINTRESOURCE macro can actually be used to make this a little easier:
int ordinal = 123;
HANDLE dll = LoadLibrary("MyDLL.dll");
FARPROC fn = GetProcAddress(dll, MAKEINTRESOURCE(ordinal));
Related
I am trying to write a wrapper on top of winapi. I want to wrap functions that accept pointers for callback functions.
As an example, consider this:
// The unsafe callback type the FFI function accepts
type UnsafeCallback = unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32;
// The safe callback type my function should accept
type SafeCallback = fn(exception_info: &ConvertedExceptionInfo) -> u32;
The functions that will be used:
// The function exposed by winapi
unsafe extern "system" fn SetExceptionHandler(handler: UnsafeCallback);
// The function I want to expose in my library
fn SetExceptionHandler(handler: SafeCallback);
I want to create a wrapping function that looks like this:
unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32 {
let result = panic::catch_unwind(|| {
// Convert ExceptionInfo into ConvertedExceptionInfo. I know this is undefined behavior, but its only here
// to demonstrate program flow
let converted_exception_info: ConvertedExceptionInfo = (*exception_info).into();
// Call the corresponding safe function (as to how we get the function pointer here, that's
// the whole question)
return safe_callback(&converted_exception_info);
});
return match result {
Ok(val) => val,
Err(_) => _
};
}
I can think of two possibilities to create this wrapping function:
Creating a wrapping function at runtime
Create a closure or similar construct inside the safe
SetExceptionHandler method.
I have no idea how to get the closure across the FFI boundary.
Exposing a conversion macro and generating the function at compile time
Edit the SetExceptionHandler function to accept the UnsafeCallback
type.
Then I could create a macro that generates the wrapping function at compile time and expose this macro to the user.
I would have to expose unsafe extern parameters again, so it is not
how I would prefer to do it.
I have no idea how to structure such a macro or if this is even possible.
Is my first idea possible and feasible? If so, how could this be done?
If not, is writing a macro like the second idea possible and feasible? If so, how could this be done?
Based on
How do I create a Rust callback function to pass to a FFI function?
How do I convert a Rust closure to a C-style callback?
How do I pass a closure through raw pointers as an argument to a C function?
I get the impression that my first idea is probably not possible with the exception of something called trampolining.
Is trampolining possible in safe Rust and in this situation?
After much searching, i have found a blog post that explains a nice solution for the problem of wrapping callbacks. Article here
In Vector CANoe, is it possible to define a function that takes a system variable argument like the system function TestWaitForSignalMatch()?
For my use case it is not sufficient to supply the current value of the system variable because I want to pass the system variable to TestWaitForSignalMatch() or similar system functions.
The CANoe help seems to show examples:
long TestWaitForSignalMatch (Signal aSignal, float aCompareValue, dword aTimeout); // form 1
long TestWaitForSignalMatch (sysvar aSysVar, float aCompareValue, dword aTimeout); // form 3
I tried like this
void foo(sysvar aSysvar) {}
^
or this
void foo(sysvar *aSysvar) {}
^
but I get a parse error at the marked position of the sysvar keyword in both cases.
I successfully created functions that take a signal argument, but unlike the syntax in the CANoe help I have to use a pointer.
This works:
void foo(signal *aSignal) {}
Obviously the documentation in the help is not correct in this point. It results in a parse error after the signal keyword when I omit the * as shown in the help:
void bar(signal aSignal) {}
^
So what's the correct syntax for defining a function that takes a sysvar argument? (if possible)
In case the version matters, I'm currently testing with CANoe 9.0.53(SP1), 9.0.135(SP7) or 10.0.125(SP6).
You have to use the correct type. You have the following possibilities to declare system variables in functions:
Integer: sysvarInt*
Float: sysvarFloat*
String: sysvarString*
Integer Array: sysvarIntArray*
Float Array: sysvarFloatArray*
Data: sysvarData*
Examples:
void PutSysVarIntArrayToByteArray (sysvarIntArray * from, byte to[], word length)
{
word ii;
for (ii = 0; ii < length; ii++)
{
to[ii] = (byte)#from[ii];
}
}
You can also write to the system variable:
void PutByteToSysVarInt (byte from, sysvarInt * to) {
#to = from;
}
See also CANoe Help page "Test Features » XML » Declaration and Transfer of CAPL Test Case and Test Function Parameters"
Yes, you can. Just define a bit further your sysvar type, not just sysvar.
System variables, with indication of type and *. Possible types:
Data, Int, Float, String, IntArray, and FloatArray. Example
declaration: sysvarFloat * sv
You didn't specify the CANoe SP version, so it may not be supported in older versions, but to make sure of this, search for Function parameter in Help/Index, then you should get the full list of possible function parameters you can use in your current CANoe setup. Should start like this:
Integers (byte, word, dword, int, long, qword, int64) Example
declaration: long 1
Integers (byte, word, dword, int, long, qword, int64) Example
declaration: long 1
Individual characters (char) Example declaration: char ch
Enums Example declaration: enum Colors c
Associative fields Example declaration: int m[float]. Associative
fields are transferred as reference automatically.
.............
System variables, with indication of type and *. Possible types:
Data, Int, Float, String, IntArray, and FloatArray. Example
declaration: sysvarFloat * sv
I'm replacing a DLL written in C++ with one written in Rust.
Currently the function in the DLL is called as follows:
BOOL calledFunction(wchar_t* pFileName)
I believe that in this context wchar_t is a 16-bit Unicode character, so I chose to expose the following function in my Rust DLL:
pub fn calledFunction(pFileName: *const u16)
What would be the best way to convert that raw pointer to something I could actually use to open the file from the Rust DLL?
Here is some example code:
use std::ffi::OsString;
use std::os::windows::prelude::*;
unsafe fn u16_ptr_to_string(ptr: *const u16) -> OsString {
let len = (0..).take_while(|&i| *ptr.offset(i) != 0).count();
let slice = std::slice::from_raw_parts(ptr, len);
OsString::from_wide(slice)
}
// main example
fn main() {
let buf = vec![97_u16, 98, 99, 100, 101, 102, 0];
let ptr = buf.as_ptr(); // raw pointer
let string = unsafe { u16_ptr_to_string(ptr) };
println!("{:?}", string);
}
In u16_ptr_to_string, you do 3 things:
get the length of the string by counting the non-zero characters using offset (unsafe)
create a slice using from_raw_parts (unsafe)
transform this &[u16] into an OsString with from_wide
It is better to use wchar_t and wcslen from the libc crate and use another crate for conversion. This is maybe a bad idea to reimplement something that is already maintained in a crate.
You need to use OsString, which represents the native string format used by the operating system. In Windows these are specifically 16-bit character strings (usually UTF-16).
Quoting the doc:
OsString and OsStr are useful when you need to transfer strings to and from the operating system itself, or when capturing the output of external commands. Conversions between OsString, OsStr and Rust strings work similarly to those for CString and CStr.
You first need to convert the pointer into a slice, using unsafe code:
use std::slice;
// manifest a slice out of thin air!
let ptr = 0x1234 as const *u16;
let nb_elements = 10;
unsafe {
let slice = slice::from_raw_parts(ptr, nb_elements);
}
This assumes you know the size of your string, meaning your function should also take the number of characters as argument.
The from_wide method should be the one needed to convert from a native format:
use std::ffi::OsString;
use std::os::windows::prelude::*;
// UTF-16 encoding for "Unicode".
let arr = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
let string = OsString::from_wide(&arr[..]);
I have a legacy template function I'm trying to call that has a slew of specializations for function pointers with different numbers of arguments. I'm writing a new template function of my own that take some arbitrary kind of non-capturing lambda and needs to pass it to the other library. If I do this directly, then the template resolution fails. If however I explicitly cast it to be related function pointer type, things work.
The problem then is how to make my template code get that function pointer type from the lambda's type or force the explicit conversion without explicitly referencing the type.
Just use unary-plus to convert a lambda to a function pointer, as in:
auto* f = +[]{ std::cout << "Hello, world!\n"; }; // f is of type void (*)()
I'm using IDebugSymbols::GetNameByOffset and I'm finding that I get the same symbol name for different functions that overload the same name.
E.g. The code I'm looking up the symbols for might be as follows:
void SomeFunction(int) {..}
void SomeFunction(float) {..}
At runtime, when I have an address of an instruction from each of these functions I'd like to use GetNameByOffset and tell the two apart somehow. I've experimented with calling SetSymbolOptions toggling the SYMOPT_UNDNAME and SYMOPT_NO_CPP flags as documented here, but this didn't work.
Does anyone know how to tell these to symbols apart in the debugger engine universe?
Edit: Please see me comment on the accepted answer for a minor amendment to the proposed solution.
Quote from dbgeng.h:
// A symbol name may not be unique, particularly
// when overloaded functions exist which all
// have the same name. If GetOffsetByName
// finds multiple matches for the name it
// can return any one of them. In that
// case it will return S_FALSE to indicate
// that ambiguity was arbitrarily resolved.
// A caller can then use SearchSymbols to
// find all of the matches if it wishes to
// perform different disambiguation.
STDMETHOD(GetOffsetByName)(
THIS_
__in PCSTR Symbol,
__out PULONG64 Offset
) PURE;
So, I would get the name with IDebugSymbols::GetNameByOffset() (it comes back like "module!name" I believe), make sure it is an overload (if you're not sure) using IDebugSymbols::GetOffsetByName() (which is supposed to return S_FALSE for multiple overloads), and look up all possibilities with this name using StartSymbolMatch()/EndSymbolMatch(). Not a one liner though (and not really helpful for that matter...)
Another option would be to go with
HRESULT
IDebugSymbols3::GetFunctionEntryByOffset(
IN ULONG64 Offset,
IN ULONG Flags,
OUT OPTIONAL PVOID Buffer,
IN ULONG BufferSize,
OUT OPTIONAL PULONG BufferNeeded
);
// It can be used to retrieve FPO data on a particular function:
FPO_DATA fpo;
HRESULT hres=m_Symbols3->GetFunctionEntryByOffset(
addr, // Offset
0, // Flags
&fpo, // Buffer
sizeof(fpo), // BufferSize
0 // BufferNeeded
));
and then use fpo.cdwParams for basic parameter size discrimination (cdwParams=size of parameters)