Продолжение вопросов о работе с DLL.
От: pepsicoca  
Дата: 20.10.11 13:49
Оценка:
Добрый день.

Есть 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.dll
class 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.


#include <windows.h>
#include <iostream>

using namespace std;

int main(int argc, char* argv[]){

SetLastError(0);

HINSTANCE hi=LoadLibrary("example_load_dll.dll");

DWORD le=GetLastError();

cout<<endl<<"HINSTANCE ="<<hi;
cout<<endl<<"GetLastError()="<<le;

return 0;
}


После запуска приложения получаю GetLastError()=127.

У меня есть другие DLL (не мои), при загрузке которых GetLastError()=0.

Вопросы:

1. Почему при загрузке возникает GetLastError()=127?
2. Как сделать, чтобы GetLastError() был равен 0?
3. Почему при загрузке других DLL GetLastError() равен 0?

Спасибо
Re: Продолжение вопросов о работе с DLL.
От: MasterZiv СССР  
Дата: 21.10.11 08:43
Оценка:
On 10/20/2011 05:49 PM, pepsicoca wrote:

Неужели ответы на эти вопросы не очевидны ?

> 1. Почему при загрузке возникает GetLastError()=127?


Потому, что твоя библиотека не загружается.

> 2. Как сделать, чтобы GetLastError() был равен 0?


Загрузить библиотеку правильно (устранить ошибки).

> 3. Почему при загрузке других DLL GetLastError() равен 0?


Потому что те библиотеки загружаются.

p.s. http://www.dependencywalker.com/
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Продолжение вопросов о работе с DLL.
От: Аноним  
Дата: 21.10.11 14:22
Оценка:
Здравствуйте, 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/
Re: Продолжение вопросов о работе с DLL.
От: okman Беларусь https://searchinform.ru/
Дата: 21.10.11 19:01
Оценка: +2
Здравствуйте, 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);
Re[3]: Продолжение вопросов о работе с DLL.
От: ononim  
Дата: 21.10.11 19:09
Оценка: 1 (1) +2
>>> 1. Почему при загрузке возникает GetLastError()=127?
MZ>>Потому, что твоя библиотека не загружается.
А>В том то и дело, что библиотека загружается, несмотря на диагностику GetLastError()=127.
если win32 API функция выполнена успешно, то значение, возвращаемое GetLastError после этого не имеет смысла. GetLastError имеет смысл тока если API выполнилась с ошибкой, если в MSDN не указано обратного для вызванной API.
Как много веселых ребят, и все делают велосипед...
Re[2]: Продолжение вопросов о работе с DLL.
От: Jolly Roger  
Дата: 22.10.11 06:40
Оценка: -1
Здравствуйте, okman, Вы писали:

O>А логика вызывающего должна быть проста:

O>
O>HMODULE hDll = LoadLibraryW(L"some_library.dll");

O>if (NULL == hDll)
O>{
O>    throw (std::exception("Error: Unable to load some_library.dll."));
O>}

O>// ...

O>FreeLibrary(hDll);
O>


Не надо такую такую "логику" . Бессмысленная строка "Error: Unable to load some_library.dll." имеет только одно назначения — спрятать от самого себя причину неудачи. После такой "логики" и возникают на форумах диалоги типа

- Помигите, у меня программа не работает!!!
— Что именно не работает?
— Программа!!!

"Нормальные герои всегда идут в обход!"
Re[3]: Продолжение вопросов о работе с DLL.
От: okman Беларусь https://searchinform.ru/
Дата: 22.10.11 11:37
Оценка: +1
Здравствуйте, Jolly Roger, Вы писали:

JR>Не надо такую такую "логику" . Бессмысленная строка "Error: Unable to load some_library.dll." имеет только одно назначения — спрятать от самого себя причину неудачи.


Не понял.
Все, что делает этот код (условно) — пытается загружать и использовать dll.
Если LoadLibrary обламывается, кидается исключение с соответствующим текстом.
Которое можно будет перехватить где-то выше и узнать в чем проблема.
Где тут прятанье причин неудачи — не понимаю. Да, можно в exception добавить
код из GetLastError и stack trace, но, кажется, тема о другом.
Re[4]: Продолжение вопросов о работе с DLL.
От: Jolly Roger  
Дата: 22.10.11 13:05
Оценка: 1 (1)
Здравствуйте, okman, Вы писали:

O> Да, можно в exception добавить

O>код из GetLastError и stack trace, но, кажется, тема о другом.

Не можно, а нужно Потому, что выше по стеку вполне можно снабдить эксепшин более "высокоуровневым" сообщением "Unable to load some_library.dll.", а вот вызывать GetLastError с очень высокой вероятностью будет уже поздно.

O>но, кажется, тема о другом.


Может быть и так. Но это очень уж распространённая (и раздражающая) ошибка новичков, а автор топика явно новичёк.
"Нормальные герои всегда идут в обход!"
Re[4]: Продолжение вопросов о работе с DLL.
От: Аноним  
Дата: 24.10.11 09:38
Оценка: -1
Здравствуйте, 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.
Re[5]: Продолжение вопросов о работе с DLL.
От: okman Беларусь https://searchinform.ru/
Дата: 26.10.11 12:09
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Поэтому вопросы еще раз (в другой формулировке):


Ответы (те же самые, но формулировка новая).

А>1. Почему некоторые DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 127, в то время как другие DLL после загрузки с помощью LoadLibrary оставляют в GetLastError значение 0?


Так захотел Билл Гейтс.

А>2. Как сделать так(что изменить в DLL), чтобы всегда после загрузки DLL с помощью LoadLibrary значение в GetLastError было равно 0?


Напишите Биллу.
Re[5]: Продолжение вопросов о работе с DLL.
От: баг  
Дата: 26.10.11 23:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я тоже раньше так думал, что если LoadLibrary вернула не ноль, то на GetLastError можно не смотреть.

А>Если бы после успешной загрузки ЛЮБОЙ DLL GetLastError возвращала бы 127, я бы понял, что это особенность работы функции LoadLibrary.
А>Однако, есть другие DLL, после загрузки которых GetLastError()=0.
А>Это кажется довольно странным.
Значения, возвращаемые функцией rand(0 вам тоже кажутся странными?
Re[5]: Продолжение вопросов о работе с DLL.
От: Jolly Roger  
Дата: 27.10.11 03:13
Оценка: 1 (1) +2
Здравствуйте, Аноним, Вы писали:

А>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 (только для тех функций, для которых это указано в документации).
"Нормальные герои всегда идут в обход!"
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.