Есть MSVC2010 на winXP.
Создаю в MSVC2010 DLL с именем example_load_dll.dll.
Потом создаю в MSVC2010 приложение, которое загружает эту DLL.
После загрузке DLL с помощью LoadLibrary читаю GetLastError.
GetLastError возвращает значение 127, что означает "не найдена указанная процедура".
Подробнее, что именно есть:
Есть DLL, которая ничего не делает. Эта DLL создана в MSVC2010 визардом для DLLек.
// dllmain.cpp : Defines the entry point for the DLL application.#include"stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// example_load_dll.cpp : Defines the exported functions for the DLL application.
//#include"stdafx.h"#include"example_load_dll.h"// This is an example of an exported variable
EXAMPLE_LOAD_DLL_API int nexample_load_dll=0;
// This is an example of an exported function.
EXAMPLE_LOAD_DLL_API int fnexample_load_dll(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see example_load_dll.h for the class definition
Cexample_load_dll::Cexample_load_dll()
{
return;
}
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//#pragma once
#include"targetver.h"#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:#include <windows.h>
// TODO: reference additional headers your program requires here#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.#include <SDKDDKVer.h>
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the EXAMPLE_LOAD_DLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// EXAMPLE_LOAD_DLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.#ifdef EXAMPLE_LOAD_DLL_EXPORTS
#define EXAMPLE_LOAD_DLL_API __declspec(dllexport)
//#define EXAMPLE_LOAD_DLL_API #else
#define EXAMPLE_LOAD_DLL_API __declspec(dllimport)
//#define EXAMPLE_LOAD_DLL_API #endif// This class is exported from the example_load_dll.dllclass EXAMPLE_LOAD_DLL_API Cexample_load_dll {
public:
Cexample_load_dll(void);
// TODO: add your methods here.
};
extern EXAMPLE_LOAD_DLL_API int nexample_load_dll;
EXAMPLE_LOAD_DLL_API int fnexample_load_dll(void);
Далее есть приложение, которое тоже ничего не делает, а только загружает DLL.
После запуска приложения получаю GetLastError()=127.
У меня есть другие DLL (не мои), при загрузке которых GetLastError()=0.
Вопросы:
1. Почему при загрузке возникает GetLastError()=127?
2. Как сделать, чтобы GetLastError() был равен 0?
3. Почему при загрузке других DLL GetLastError() равен 0?
Здравствуйте, MasterZiv, Вы писали:
MZ>On 10/20/2011 05:49 PM, pepsicoca wrote:
MZ>Неужели ответы на эти вопросы не очевидны ?
>> 1. Почему при загрузке возникает GetLastError()=127?
MZ>Потому, что твоя библиотека не загружается.
В том то и дело, что библиотека загружается, несмотря на диагностику GetLastError()=127.
На самом деле у меня есть реальная библиотека (тоже сделанная на MSVC2010), которая тоже возвращает GetLastError()=127.
Это не пустая библиотека из примера, а другая, в которой есть экспортируемые функции.
LoadLibrary возвращает для нее ненулевой указатель.
Если начать дергать адреса функций из этой библиотеки с помощью GetProgAdress, то адреса нормально получаются и эти функции нормально отрабатывают свою функциональность.
Вроде бы все хорошо.
Но тем не менее мне было подозрительно, что эта библиотека возвращает GetLastError()=127.
И я сделал пустую библиотеку с помощью библиотекогенератора MSVC.
Оказалось, что пустая библиотека тоже при загрузке возвращает GetLastError()=127.
Вот я и хочу узнать, правильно ли это, что заведомо правильная библиотека нормально загружается, но тем не менее возвращает GetLastError()=127.
>> 2. Как сделать, чтобы GetLastError() был равен 0?
MZ>Загрузить библиотеку правильно (устранить ошибки).
>> 3. Почему при загрузке других DLL GetLastError() равен 0?
MZ>Потому что те библиотеки загружаются.
MZ>p.s. http://www.dependencywalker.com/
Там нет никаких зависимых модулей.
Это пустая библиотека, созданная визардом для библиотек в MSVC.
Re[2]: Продолжение вопросов о работе с DLL.
От:
Аноним
Дата:
21.10.11 14:41
Оценка:
Здравствуйте, MasterZiv, Вы писали:
MZ>On 10/20/2011 05:49 PM, pepsicoca wrote:
MZ>Неужели ответы на эти вопросы не очевидны ?
>> 1. Почему при загрузке возникает GetLastError()=127?
MZ>Потому, что твоя библиотека не загружается.
Да, и еще одно.
Когда библиотека не загружается, то GetLastError()=1 или GetLastError()=2.
А в моем случает GetLastError()=127.
То есть получается, что библиотека загрузилась, но диагностика такая, как будто не найдена функция.
Хотя при DllMain в библиотеке присутствует, а другие функции при загрузке вроде-бы не нужны.
>> 2. Как сделать, чтобы GetLastError() был равен 0?
MZ>Загрузить библиотеку правильно (устранить ошибки).
>> 3. Почему при загрузке других DLL GetLastError() равен 0?
MZ>Потому что те библиотеки загружаются.
MZ>p.s. http://www.dependencywalker.com/
Здравствуйте, pepsicoca, Вы писали:
P>Есть MSVC2010 на winXP. P>Создаю в MSVC2010 DLL с именем example_load_dll.dll. P>Потом создаю в MSVC2010 приложение, которое загружает эту DLL. P>После загрузке DLL с помощью LoadLibrary читаю GetLastError. P>GetLastError возвращает значение 127, что означает "не найдена указанная процедура".
Я вот чего не понимаю — что возвращает LoadLibrary ?
Если она возвращает ненулевое значение, значит все в порядке, библиотека загружена.
То, что GetLastError при этом возвращает какое-то число, отличное от нуля, вообще не
должно беспокоить. Если бы после вызова каждой функции Win32 API нужно было еще
звать на помощь GetLastError и проверять полученный код, это было бы не программирование,
а сущий кошмар.
А логика вызывающего должна быть проста:
HMODULE hDll = LoadLibraryW(L"some_library.dll");
if (NULL == hDll)
{
throw (std::exception("Error: Unable to load some_library.dll."));
}
// ...
FreeLibrary(hDll);
>>> 1. Почему при загрузке возникает GetLastError()=127? MZ>>Потому, что твоя библиотека не загружается. А>В том то и дело, что библиотека загружается, несмотря на диагностику GetLastError()=127.
если win32 API функция выполнена успешно, то значение, возвращаемое GetLastError после этого не имеет смысла. GetLastError имеет смысл тока если API выполнилась с ошибкой, если в MSDN не указано обратного для вызванной API.
Как много веселых ребят, и все делают велосипед...
Не надо такую такую "логику" . Бессмысленная строка "Error: Unable to load some_library.dll." имеет только одно назначения — спрятать от самого себя причину неудачи. После такой "логики" и возникают на форумах диалоги типа
- Помигите, у меня программа не работает!!!
— Что именно не работает?
— Программа!!!
Здравствуйте, Jolly Roger, Вы писали:
JR>Не надо такую такую "логику" . Бессмысленная строка "Error: Unable to load some_library.dll." имеет только одно назначения — спрятать от самого себя причину неудачи.
Не понял.
Все, что делает этот код (условно) — пытается загружать и использовать dll.
Если LoadLibrary обламывается, кидается исключение с соответствующим текстом.
Которое можно будет перехватить где-то выше и узнать в чем проблема.
Где тут прятанье причин неудачи — не понимаю. Да, можно в exception добавить
код из GetLastError и stack trace, но, кажется, тема о другом.
Здравствуйте, okman, Вы писали:
O> Да, можно в exception добавить O>код из GetLastError и stack trace, но, кажется, тема о другом.
Не можно, а нужно Потому, что выше по стеку вполне можно снабдить эксепшин более "высокоуровневым" сообщением "Unable to load some_library.dll.", а вот вызывать GetLastError с очень высокой вероятностью будет уже поздно.
O>но, кажется, тема о другом.
Может быть и так. Но это очень уж распространённая (и раздражающая) ошибка новичков, а автор топика явно новичёк.
Здравствуйте, ononim, Вы писали:
>>>> 1. Почему при загрузке возникает GetLastError()=127? MZ>>>Потому, что твоя библиотека не загружается. А>>В том то и дело, что библиотека загружается, несмотря на диагностику GetLastError()=127. O>если win32 API функция выполнена успешно, то значение, возвращаемое GetLastError после этого не имеет смысла. GetLastError имеет смысл тока если API выполнилась с ошибкой, если в MSDN не указано обратного для вызванной API.
Я тоже раньше так думал, что если LoadLibrary вернула не ноль, то на GetLastError можно не смотреть.
Если бы после успешной загрузки ЛЮБОЙ DLL GetLastError возвращала бы 127, я бы понял, что это особенность работы функции LoadLibrary.
Однако, есть другие DLL, после загрузки которых GetLastError()=0.
Это кажется довольно странным.
Таким образом имеем такие факты:
— Некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 127.
— Некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 0.
Можно сделать вывод, что дело в содержимом DLL.
Поэтому вопросы еще раз (в другой формулировке):
1. Почему некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 127, в то время как другие DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 0?
2. Как сделать так(что изменить в DLL), чтобы всегда после загрузки DLL с помощью LoadLibrary значение в GetLastError было равно 0?
Спасибо.
Re[5]: Продолжение вопросов о работе с DLL.
От:
Аноним
Дата:
26.10.11 11:38
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, ononim, Вы писали:
>>>>> 1. Почему при загрузке возникает GetLastError()=127? MZ>>>>Потому, что твоя библиотека не загружается. А>>>В том то и дело, что библиотека загружается, несмотря на диагностику GetLastError()=127. O>>если win32 API функция выполнена успешно, то значение, возвращаемое GetLastError после этого не имеет смысла. GetLastError имеет смысл тока если API выполнилась с ошибкой, если в MSDN не указано обратного для вызванной API.
А>Я тоже раньше так думал, что если LoadLibrary вернула не ноль, то на GetLastError можно не смотреть. А>Если бы после успешной загрузки ЛЮБОЙ DLL GetLastError возвращала бы 127, я бы понял, что это особенность работы функции LoadLibrary. А>Однако, есть другие DLL, после загрузки которых GetLastError()=0. А>Это кажется довольно странным.
А>Таким образом имеем такие факты: А> — Некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 127. А> — Некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 0.
А>Можно сделать вывод, что дело в содержимом DLL.
А>Поэтому вопросы еще раз (в другой формулировке):
А>1. Почему некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 127, в то время как другие DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 0?
А>2. Как сделать так(что изменить в DLL), чтобы всегда после загрузки DLL с помощью LoadLibrary значение в GetLastError было равно 0?
А>Спасибо.
Похоже дело в том, что MSVC2010 подключает какие-то функции, которые отсутствуют в winXP.
Под win7 загрузка завершается с GetLastError()=0.
Здравствуйте, Аноним, Вы писали:
А>Поэтому вопросы еще раз (в другой формулировке):
Ответы (те же самые, но формулировка новая).
А>1. Почему некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 127, в то время как другие DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 0?
Так захотел Билл Гейтс.
А>2. Как сделать так(что изменить в DLL), чтобы всегда после загрузки DLL с помощью LoadLibrary значение в GetLastError было равно 0?
Здравствуйте, Аноним, Вы писали:
А>Я тоже раньше так думал, что если LoadLibrary вернула не ноль, то на GetLastError можно не смотреть. А>Если бы после успешной загрузки ЛЮБОЙ DLL GetLastError возвращала бы 127, я бы понял, что это особенность работы функции LoadLibrary. А>Однако, есть другие DLL, после загрузки которых GetLastError()=0. А>Это кажется довольно странным.
Значения, возвращаемые функцией rand(0 вам тоже кажутся странными?
Здравствуйте, Аноним, Вы писали:
А>1. Почему некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 127, в то время как другие DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 0?
DLL тут ни при чём. Функция GetLastError возвращает значение переменной, расположенной в TLS (Thread Local Storage) потока. В теле функций WinApi предусмотрен вызов функции SetLastError при возникновении каких-либо проблем. Т.е. если при выполнении функции возникает проблема, то вызывается SetLastError, которая сохраняет в last_error соответствующий код ошибки, после чего происходит возврат их функции. Некоторые из функций (но далеко не все) выполняют вызов SetLastError(0) в случае успеха.
Такми образом, если мы выполняем вызов
SetLastError(0);
func_1();
func_2();
func_3();
x = GetLastError();
то мы не можем знать, к какой из трёх функций будет относиться полученный в x код ошибки.
А>2. Как сделать так(что изменить в DLL), чтобы всегда после загрузки DLL с помощью LoadLibrary значение в GetLastError было равно 0?
Вы можете, конечно, попробовать вызывать SetLastError(0) перед LoadLibrary, но далеко не факт, что это что-то даст. Правильная стратегия тут только одна — (вызывать GetLastError только в случае неудачи) AND (только сразу после вызова самой функции) AND (только для тех функций, для которых это указано в документации).