Windows 핵심 프로그래밍 학습 노트 -------19장

6845 단어 dll

제19장 DLL 기반


Windows API에서 제공하는 모든 함수는 DLL에 포함됩니다.가장 중요한 세 가지 DLL: Kernel32.dll(메모리, 프로세스 및 스레드 관리), Use32.dll(사용자 인터페이스와 관련된 작업 수행), GDI32.dll.
19.1, DLL 및 프로세스의 주소 공간
Tier 1: DLL 포지셔닝 개요
응용 프로그램 (또는 다른 DLL) 에서 DLL 함수를 호출하기 전에, 이 DLL의 파일 이미지를 호출 프로세스의 주소 공간에 비추어야 합니다.두 가지 방법: 암시적으로 불러올 때 링크와 실행할 때 링크를 표시합니다.
매핑 후 DLL에서 함수를 호출하면 이 함수는 온라인 스택에서 전달된 매개 변수를 얻어 필요한 부분 변수를 스레드 스택에 저장합니다.또한 DLL에서 함수로 작성된 모든 객체는 호출 스레드 또는 프로세스에 의해 소유됩니다.
19.2 전체 국면을 살펴보다
계층 2: 이론 프로세스 개요
EXE가 다른 DLL 모듈에서 함수 또는 변수를 가져와야 하는 경우 다음을 수행합니다.
DLL 구축 전:
1) 먼저 DLL에서 내보낸 함수 원형, 구조 및 기호를 포함하는 헤더 파일을 생성합니다.이 DLL을 구축하려면 DLL의 모든 원본 파일이 이 헤더 파일을 포함해야 합니다.EXE를 구축할 때는 동일한 헤더 파일이 필요합니다.
2) DLL 모듈에서 내보낸 함수와 변수를 위한 소스 파일을 생성합니다.
3) DLL 모듈을 구축하면 컴파일러가 각 소스 파일을 처리하고 생성합니다.obj 모듈.
4) 모든 것.obj 모듈이 모두 만들어지면 링크는 모든.obj 모듈 컨텐트가 결합되어 별도의 DLL이 생성됩니다.
5) 링크가 DLL 소스 파일에서 하나 이상의 함수나 변수를 내보낸 것을 감지하면 링크가 하나 더 생성됩니다.lib 파일그것은 내보낸 함수나 변수의 기호 이름만 보여 줍니다.
EXE 재구성(실행 모듈):
1) 내보낸 함수, 변수, 데이터 구조 또는 기호를 참조하는 모든 소스 파일에는 DLL에 해당하는 헤더 파일이 포함되어야 합니다.
2) EXE를 구축할 때 컴파일러는 각 소스 파일을 처리하고 생성합니다.obj 모듈.
3) 컴파일한 후 링크는 모든 것을 컴파일합니다.obj 모듈 내용 합병은exe를 생성합니다.이 exe(실행 가능한 모듈)에는 필요한 모든 DLL 모듈과 각 DLL 모듈에서 참조하는 기호가 나열된 가져오기 세그먼트가 포함되어 있습니다.exe 를 실행하면 OS 로더가 5 를 수행합니다).
4) 로드러너는 먼저 새 프로세스에 대한 가상 주소 공간을 만들고 실행 가능한 모듈을 새 프로세스의 주소 공간에 비추어 줍니다.로드 프로그램은 이어서 실행 가능한 모듈의 가져오기 세그먼트를 분석합니다.가져오기 세그먼트에 나열된 각 DLL에 대해 로드러너는 사용자 시스템에서 DLL 모듈을 찾아 프로세스의 주소 공간에 매핑합니다.DLL 모듈은 다른 DLL 모듈에서 함수와 변수를 가져올 수 있으므로 DLL 모듈은 자체 가져오기 세그먼트가 있을 수 있으며 모든 DLL 모듈을 프로세스의 주소 공간에 매핑해야 합니다.
로드 프로그램이 EXE와 모든 DLL을 프로세스의 주소 공간에 매핑하면 프로세스의 주 스레드가 시작됩니다.
계층 3: 세부 프로세스 실행
19.2.1 DLL 모듈 구축
DLL은 변수, 함수 또는 C++ 클래스를 내보냅니다.변수 내보내기를 피해야 합니다.내보낸 C++ 클래스의 모듈에서 사용하는 컴파일러와 가져온 C++ 클래스의 모듈에서 사용하는 컴파일러가 같은 업체에서 제공될 때만 C++ 클래스를 내보낼 수 있습니다.
교묘함(코드 P515): DLL 헤더 파일
#ifdef  MYLIBAPI
#else
#define MYLIBAPI  extern  “C”  _declspec(dllimport)
#endif
//내보낸 함수 또는 변수
MYLIBAPI  int Add(int nLeft, int nRight);
DLL 소스 파일
#define  MYLIBAPI  extern  “C”  _declspec(dllexport)//dll 헤더 파일 이전에
#include "dll 헤더 파일"
EXE 소스 파일
#include "dll 헤더 파일"//MYLIBAPI 매크로를 정의할 수 없습니다.
이렇게 하면 DLL 소스 파일에서 MYLIBAPI는 내보내기로 정의되고 EXE 소스 파일에서 MYLIBAPI는 가져오기로 정의됩니다.
_declspec(dllexport): 원본 파일에서 변수와 함수를 내보내기 전에 이 수식을 추가할 필요가 없습니다.컴파일러는 헤더 파일을 해석할 때 어떤 변수와 함수를 내보내야 하는지 기억하기 때문이다.
_declspec(dllimport): DLL의 헤더 파일은 내보낸 함수, 변수 또는 C++ 클래스 앞에 추가됩니다.필요하지는 않지만 효율을 약간 높일 수 있다.EXE의 원본 파일에서 컴파일러는 이 기호를 보고 DLL 모듈에서 이 기호를 가져올 것을 알 수 있습니다.
extern "C": C++ 코드를 작성할 때만 사용합니다. (C는 사용하지 말아야 합니다.)C++ 컴파일러는 일반적으로 함수 이름과 변수 이름을 개편하기 때문에 연결할 때 오류가 발생합니다.이 수식자는 컴파일러에게 변수 이름이나 함수를 개편하지 말라고 알려 줍니다.
_stdcall: C라도 이 약속을 사용하면 Microsoft의 컴파일러가 함수 이름을 개편합니다.구체적인 방법은 함수 이름에 밑줄 접두사와 특수한 접두사를 추가하는 것이다.이 접미사는 @ 기호와 함수에 매개 변수로 전달되는 바이트 수로 구성되어 있습니다.예:declspec(dllexport) LONG _stdcall MyFunc(int a, int b);다음으로 내보내기MyFunc@8.그러니까 개편을 막아야 돼.두 가지 방법: 하나를 만듭니다.def 파일def 파일에는 다음과 같은 세그먼트가 포함되어 있습니다.
EXPORTS
         MyFunc
두 번째 방법은 개편되지 않은 함수 이름을 내보내는 것입니다.DLL의 소스 파일에 다음을 추가합니다.
#pragma comment(linker, “/export:MyFunc=_MyFunc@8”)
.def 파일 형식:
LIBRARY XX (dll 이름 이것은 필수는 아니지만 생성된 dll 이름과 동일해야 함)
EXPORTS
[함수 이름] @ [함수 번호]
내보내기 클래스: 내보내기 클래스와 내보내기 클래스를 사용하는 것은 내보내기 함수와 유사하지만 내보내기 클래스에서 extern "C"기호를 사용할 수 없습니다.
내보내기 세그먼트: Microsoft C/C++ 컴파일러가 를 볼 때declspec(dllexport) 수식된 변수, 함수, C++ 클래스가 생성됩니다.obj 파일에 추가 정보가 포함되어 있습니다.링크가 DLL의 모든 링크에 있는 경우obj 파일은 이러한 정보를 해석합니다.링크는 결과 DLL 파일에 내보내기 기호 테이블을 포함합니다.이 내보내기 세그먼트는 내보낸 변수, 함수, 클래스의 기호 이름을 보여 줍니다.각 기호가 DLL 모듈에서 어디에 있는지 나타내는 상대 가상 주소도 저장됩니다.(DumpBin.exe 도구-exports를 사용하여 DLL의 내보내기 세그먼트를 볼 수 있음)
세그먼트 가져오기: 링크에 이 표시되면declspec(dllimport) 장식된 가져오기 기호는 실행 가능한 모듈에 특수한 세그먼트를 삽입합니다. 이름은 가져오기 세그먼트입니다.가져오기 세그먼트에는 모듈에 필요한 DLL 모듈과 각 DLL 모듈에서 참조하는 기호가 나열됩니다.(DumpBin.exe 도구-imports를 사용하여 DLL 내보내기 세그먼트를 볼 수 있음)
/***********************************
Moudle: MyLib.h
***********************************/

#ifdef MYLIBAPI
//MYLIBAPI should be defined in all of the DLL's source code 
//moudles before this header file is included.

//All functions/variables are being exported.

#else
//This header file is included by an EXE source code moudle/
//Indicate that all functions/variables are being imported.
#define MYLIBAPI extern "C" _declspec(dllimport)

#endif

//////////////////////////////////////////////

//Define any data structures and symbols here.

//////////////////////////////////////////////

//Define exported variables here.(Note:Avoid exporting variables.)
MYLIBAPI int g_nResult;

/////////////////////////////////////////////

//Define exported function prototypes here.
MYLIBAPI int Add(int nLeft, int nRight);

////////////////////////End of File///////////////////////

/****************************************
Moudle:MyLibFile1.cpp
****************************************/

#include <windows.h>

#define MYLIBAPI extern "C" _declspec(dllexport)

#include "MyLib.h"

/////////////////////////////////////////

int g_nResult;

int Add(int nLeft, int nRight)
{
	g_nResult = nLeft + nRight;
	return g_nResult;
}
///////////////////End of File/////////////

19.2.2. 실행 가능한 모듈 구축
1) dll이 포함된 내보내기 헤더 파일: #include <>;MYLIBAPI 매크로를 정의하지 마십시오.
2)lib 파일이 포함됩니다. #pragma comment(lib, "");코드에서 가져온 기호가 어떤 DLL에서 왔는지 링크에서 확인할 수 있도록 합니다.
3) 내보낸 변수, 함수 또는 C++ 클래스를 직접 사용합니다.
19.2.3, 실행 가능한 모듈 실행
OS 로드러너는 먼저 프로세스에 대한 가상 주소 공간을 만든 다음 EXE를 주소 공간에 매핑한 다음 로드러너는 EXE의 가져오기 세그먼트를 다시 검사하여 필요한 DLL을 찾아 프로세스의 주소 공간에 매핑합니다.
가져오기 세그먼트에는 DLL 이름만 포함되고 DLL 경로는 포함되지 않으므로 로드러너는 다음 순서로 DLL을 검색해야 합니다.
1) 실행 파일이 포함된 디렉토리
2) GetSystemDirectory를 통한 Windows 시스템 디렉토리
3) 16비트 시스템 디렉토리(Windows 디렉토리의 System 하위 디렉토리)
4) Windows 디렉토리는 GetWindowsDirectory를 통해 제공
5) 프로세스의 현재 디렉토리
6) PATH 환경 변수에 나열된 디렉토리입니다.
예를 들어 현재 DLL을 만들어서 CMyClass 클래스를 내보냈는데 고객도 이 DLL을 정상적으로 사용할 수 있다. 만약에 CMyClass 대상의 크기가 30바이트라고 가정하자.DLL의 CMyClass 클래스를 같은 함수와 구성원 변수를 가지도록 수정해야 하는데, 개인 구성원 변수인 int 형식을 추가했습니다. 현재 CMyClass 대상의 크기는 34바이트입니다.이 새로운 DLL을 고객에게 직접 사용해서 원래의 30바이트 크기의 DLL을 바꾸면, 고객 응용 프로그램은 30바이트 크기의 대상을 원하지만, 지금은 34바이트 크기의 대상이 된다. 야단났다. 클라이언트 프로그램이 잘못되었다.
비슷한 질문입니다. CMyClass 클래스를 내보내지 않고 내보내는 함수에 CMyClass를 사용하면 대상의 크기를 바꾸는 데 문제가 있을 수 있습니다.이때 이 문제를 수정하는 유일한 방법은 클라이언트 프로그램의 CMyClass 헤더 파일을 교체하고 전체 응용 프로그램을 다시 컴파일하여 클라이언트 프로그램이 34바이트 크기의 대상을 사용하도록 하는 것이다.
이것은 심각한 문제이다. 때때로 클라이언트 프로그램의 원본 코드가 없으면 우리는 이 새로운 DLL을 사용할 수 없다.
구체적으로는 그때 쓰도록 하겠습니다.

좋은 웹페이지 즐겨찾기