Доступ к структуре из вызываемой извне функции - PullRequest
0 голосов
/ 17 апреля 2020

Предисловие: У меня есть некоторый опыт работы с Rust, но не очень, поэтому возможно, что есть тривиальное решение моей проблемы. В частности, мне все еще не очень хорошо с тем, как Rust обрабатывает память, хотя я понимаю базовую концепцию c.

Во всяком случае, я использую внешний ящик (winapi, если быть точным, но более об этом позже), что накладывает некоторые ограничения на то, что я пытаюсь сделать. Вот факты:

  • Мне нужно вызвать ящик, чтобы создать что-то, для чего мне затем предоставляется дескриптор.
  • Я хочу сохранить дескриптор вместе с другими соответствующими данные в структуре.
  • Ящик также требует обратного вызова, который он затем часто вызывает.
  • Одним из параметров функции обратного вызова, вызываемой ящиком, является дескриптор.
  • В функции обратного вызова я также хотел бы получить доступ к своим собственным данным, хранящимся в структуре, вместе с дескриптором, поэтому я должен иметь возможность каким-то образом получить структуру из дескриптора. .
  • Ящик не дает хорошего способа предоставить ссылку на мою структуру для функции обратного вызова. В результате я храню глобальную структуру дескриптора ha sh map, но она не работает, как я надеюсь.

Вот некоторый код, который примерно демонстрирует мою проблему:

use std::cell::RefCell;
use std::collections::HashMap;

thread_local!(static WRAPPER_LIST_CELL: RefCell<HashMap<u32, usize>> = RefCell::new(HashMap::new()));

static mut MAX_ID: u32 = 0;

struct Data {
    x: i32
}

fn main() {
    let data = Data { x: 17 };
    let wrapper= create_wrapper(data);
    // For all intents and purposes, do_something below is actually called by
    // the external crate in a loop. This ought to demonstrate the problem
    // well enough though.
    do_something(wrapper.id);
}

struct Wrapper {
    id: u32,
    data: Data,
}

impl Wrapper {
    fn new(data: Data) -> Wrapper {
        // This is the function that would actually call the crate to
        // create the 'something' I need.
        unsafe {
            // No ID is actually needed when using the crate. The crate
            // provides a unique handle instead, which works largely to
            // the same effect as the ID here.
            let id = MAX_ID;
            MAX_ID += 1;
            let wrapper = Wrapper { id: id, data: data };
            WRAPPER_LIST_CELL.with(|cell| {
                let mut list = cell.borrow_mut();
                list.insert(wrapper.id, &wrapper as *const Wrapper as usize);
            });
            wrapper
        }
    }
}

fn create_wrapper(data: Data) -> Wrapper {
    Wrapper::new(data)
}

fn do_something(id: u32) {
    unsafe {
        WRAPPER_LIST_CELL.with(|cell| {
            let list_ptr = cell.as_ptr();
            let list_ptr = (*view_list_ptr)[&id] as *const Wrapper;
            println!("do_something: {}", (*list_ptr).data.x); // not 17
        });
    }
}

По большей части все выглядит хорошо. Однако , когда я пытаюсь получить доступ к моей структуре в do_something, я замечаю, что ее адрес отличается от того, что есть в main. Это приводит к тому, что я пытаюсь получить доступ к неправильному расположению в памяти, что, вероятно, является причиной сбоя программы.

Ящик действительно обеспечивает способ свободного хранения и доступа к указателю на пользовательские данные. Например, моя структура, но он принимает указатель по существу как isize, то есть адрес памяти моей структуры, который, опять же, изменяется между main и do_something. То есть не похоже, что его действительно можно использовать.

Как уже упоминалось, я использую ящик winapi, то есть привязки Rust для Windows API. В случае, если это уместно, я получаю (window) дескрипторы, используя CreateWindowExW, и do_something более или менее WindowPro c. Для простоты использования я хочу обернуть дескриптор окна вместе со своими собственными данными окна в структуру Window. В WindowPro c есть вещи, которые мне нужно сделать, чтобы получить доступ к своим собственным данным окна. Я предоставил упрощенную версию моего реального кода, потому что сама проблема, похоже, может возникнуть и в других ситуациях, и потому что использование Windows API довольно грязно и совсем не относится к вопросу. По запросу я могу предоставить реальный код, используя Windows API.

Наконец, актуальный вопрос: Что я могу сделать, чтобы решить мою проблему, то есть правильно обернуть вещи в структуру и заставить все работать ? Я полагаю, что возможность хранить фактические ссылки в глобальной переменной поможет, но это кажется невозможным, если я что-то упустил.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...