2013-05-07 2 views
0

Вопрос в значительной степени сводится к «Могу ли я безопасно использовать указатель на функцию с параметрами, конвертируемыми в эти типы?», Но это звучит крайне подозрительно без практического примера.Соответствует ли подпись функции, полученной из GetProcAddress?

Я сделал небольшую функцию полезности для вызова чего-либо из DLL, учитывая имя DLL, имя функции, соответствующий тип возвращаемого значения, а также типы и аргументы параметров. Тем не менее, при использовании этой утилиты может потребоваться дополнительное раздувание, а не то, что необходимо. Мне интересно, безопасно ли явно указывать типы параметров. Принимая Windows API, MessageBoxW в качестве примера:

callStdcallDllFunction<int, HWND, PCWSTR, PCWSTR, UINT>(
    L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0 
); 

Здесь я явно указать тип возвращаемого значения и четыре типа параметрических MessageBoxW. Конечно, если аргументы, начиная с правого, имеют типы, эквивалентные тем, что есть в функции, мне не нужно указывать их. Но нормально ли выводить типы, если аргументы действительны для перехода к функции в первую очередь (что это все)?

callStdcallDllFunction<int>(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0); 

Здесь, я считаю, что результат GetProcAddress будет приведен к int(__stdcall *)(std::nullptr_t, std::nullptr_t, std::nullptr_t, int);. Однако аргументы, которые все еще соответствуют фактической функции. Является ли это все еще четко определенным поведением и всегда будет делать то, что я хочу? Он работает до сих пор каждый раз, когда я его тестировал.

В то время как я нахожусь, это нормально оставить возвращаемый тип как void, если он не используется?

//return type is void instead of the actual int 
callStdcallDllFunction(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0); 

Насколько я могу судить, это работало каждый раз, когда я пытался. Если они действительно гарантированно работают, я бы хотел использовать их так, но я действительно не знаю, будут ли они всегда, и я не собираюсь рисковать тем, что я пишу, будучи неопределенным поведением ,

Точный код не имеет отношения к проблеме, но вы можете найти версии stdcall (например, MessageBox), которые вы можете использовать для тестирования here. Единственная разница между ними и версиями cdecl заключается в добавлении __stdcall в подпись функции.

ответ

1

Вы должны знать точную информацию о вызывающем соглашении и использовать ABI, чтобы дать точные ответы.

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

Обычно типы с одинаковой длиной не являются проблемой. Но будьте осторожны с более экзотическими типами, такими как указатели-члены (функции), они не обязательно имеют тот же размер, что и void *.

Быть конвертируемым не является достаточно строгим. Символ может быть преобразован в длинный, но в стеке они занимают различное количество байтов, поэтому такой приведение указателя функции может приводить к по-разному интерпретируемому содержимому стека.

+0

Ну, единственные варианты, которые я предоставил, были stdcall и cdecl. У этих двух есть разница в том, как очищается стек. Если мне приходится иметь дело с типом размеров, я, вероятно, не буду утруждать себя отсутствием типов, когда он будет работать для этого вызова, но не другой. – chris

+0

http://stackoverflow.com/a/12465133/59019 – jmihalicza

Смежные вопросы