2009-12-08 2 views
6

Я знаю, что это было задано раньше, но ни один из случаев, которые я видел здесь, не похож на этот. я ввожу некоторые функции API во время выполнения, общее заявление о тех функциях, было бы как:Отбрасывание указателя (данных) указателя функции

// Masks for UnmapViewOfFile and MapViewOfFile 
typedef BOOL (WINAPI *MyUnmapViewOfFile)(LPCVOID); 
typedef LPVOID (WINAPI *MyMapViewOfFile)(HANDLE, DWORD, DWORD, DWORD, SIZE_T); 

// Declarations 
MyUnmapViewOfFile LoadedUnmapViewOfFile; 
MyMapViewOfFile LoadedMapViewOfFile; 

Я затем вызвать общую функцию «нагрузку», где она Кальесы GetProcAddress для получения адреса экспортируемой функции из надлежащей DLL. Этот адрес возвращается на void **. Эта пустота ** является одним из параметров общей нагрузки, что-то вроде:

int GenericLoad(char* lib, void** Address, char* TheFunctionToLoad) 

, и я бы назвал эту функцию:

void *Address; 
GenericLoad("kernel32.dll", &Address, "UnmapViewOfFile"); 
LoadedUnmapViewOfFile = (MyUnmapViewOfFile) Address; 

Или что-то похожее на это. Теперь, конечно, компилятор жалуется на попытку передать данные void * в указатель функции. Как мне это сделать?

Я читал бесчисленные сайты и всевозможные неприятные роли, поэтому я был бы признателен, если бы вы добавили код в объяснение.

Благодаря Jess

+0

Новая форма «plz send codez». И, конечно, это обман. – 2009-12-08 15:32:00

+0

Можем ли мы найти, что это такое? –

+3

@ Нет, не могли бы вы указать мне статью, если вы так уверены? и нет, я не прошу код, потому что я ленив, но потому, что не знаю ответа. Вот почему я спросил здесь. – Jessica

ответ

3

Правильный код будет это одна строка:

GenericLoad("kernel32.dll", (void**)&LoadedUnmapViewOfFile, "UnmapViewOfFile"); 

Что делается здесь в основном это: адрес переменной указателя (тот, в котором вы хотите адрес функции, которая должна быть поставлена) передается в GenericLoad, что в основном соответствует ожидаемому. void ** означает «дать мне адрес вашего указателя». Весь тип кастинга - это волшебство вокруг него. C не позволит указывать «указатель на любой указатель на функцию», поэтому автор API предпочтет void **.

+0

Спасибо! Я попробую это и посмотрю, если ничего не сломано. – Jessica

2

Адреса к данным и адресам к функциям являются несовместимыми. Я считаю, что ваша переменная Address должна быть указателем на функцию, как в вашем определении BOOL: (WINAPI *MyUnmapViewOfFile)(LPCVOID). Этот тип декларации требуется, потому что для того, чтобы иметь указатель на функцию, должен быть известен тип возвращаемого значения, а также тип и количество аргументов. Это связано с тем, что когда вы вызываете свою функцию, в стек должен быть выделен правильный объем пространства, чтобы содержать это возвращаемое значение и аргументы.

Учитывая, что я верю, что исправление в ответе Павла верно (FYI, его (void **) cast - это мера безопасности типа).

+0

спасибо за объяснение. – Jessica

3

Теперь, конечно, компилятор жалуется пытаюсь бросить пустые данные * к функции указателю

Моим компиляторы не жалуются вообще с кодом (опять же, я не есть предупреждения, зависающие - я использую более или менее варианты по умолчанию). Это с множеством компиляторов от MS, GCC и других. Можете ли вы дать более подробную информацию о параметрах компилятора и компилятора, которые вы используете, и о том, какое именно предупреждение вы видите?

Тем не менее, C не гарантирует, что указатель функции может быть отброшен в/из указателя void без проблем, но на практике это отлично работает в Windows.

Если вы хотите что-то совместимое со стандартами, вам нужно будет использовать указатель функции «generic» вместо указателя void - C гарантирует, что указатель функции может быть преобразован в любой другой указатель функции и обратно без потерь, поэтому это будет работать независимо от вашей платформы.Вероятно, поэтому возвращаемое значение API Win32 GetProcAddress() возвращает FARPROC, что является просто typedef для указателя функции на функцию, которая не принимает никаких параметров (или, по крайней мере, неопределенных параметров), и возвращает int int. Что-то вроде:

typedef INT_PTR (FAR WINAPI *FARPROC)(); 

FARPROC бы идея Win32 в о «родовой» указатель на функцию. Таким образом, все, что вам нужно нужно сделать, это иметь такой же ЬурейеЕ (если вы не хотите использовать FARPROC по какой-то причине):

typedef intptr_t (*generic_funcptr_t)(); // intptr_t is typedef'ed appropriately elsewhere, 
              // like in <stdint.h> or something 

int GenericLoad(char* lib, generic_funcptr_t* Address, char* TheFunctionToLoad) 

generic_funcptr_t Address; 
GenericLoad("kernel32.dll", &Address, "UnmapViewOfFile"); 
LoadedUnmapViewOfFile = (MyUnmapViewOfFile) Address; 

Или вы можете обойтись без среднего человека и передать указатель вы действительно хотите чтобы получить значение в:

GenericLoad2("kernel32.dll", (generic_funcptr_t *) &LoadedUnmapViewOfFile, "UnmapViewOfFile"); 

Хотя, это более опасно, чем метод с использованием промежуточной переменной - например, компилятор не даст диагностики, если вы оставите от амперсанд в этом последнем примере, однако в предыдущем примере , он обычно выдавал бы хотя бы предупреждение, если бы вы остановили амперсанд из аргумента Address. Подобно Bug # 1 здесь: http://blogs.msdn.com/sdl/archive/2009/07/28/atl-ms09-035-and-the-sdl.aspx

Теперь вы должны быть установлены. Однако, как бы вы ни смотрели на это, вам нужно выполнить какое-то опасное кастинг. Даже в C++ с шаблонами вам нужно будет выполнить бросок на каком-то уровне (хотя вы можете скрыть его в функции шаблона), потому что API GetProcAddress() не знает фактический тип возвращаемого указателя функции.

Также обратите внимание, что ваш интерфейс для GenericLoad() имеет серьезную проблему с дизайном - он не позволяет управлять временем жизни библиотеки. Это может быть не проблема, если вы намерены не разрешать выгрузку библиотеки, но это то, что пользователи могут захотеть, поэтому вы должны рассмотреть эту проблему.

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