프로그래밍 기술의 급속한 발전으로 인해 점점 더 많은 사람들이 프로그램의 기능을 향상시키는 문제에 직면하고 있습니다. 이 기사는 이 문제, 즉 볼랜드 델파이에서 DLL 프로그래밍에 전념합니다. 또한 DLL 사용 문제를 다루기 때문에 다른 사람의 DLL(시스템 DLL 포함, 즉 WinAPI)에서 함수를 가져오는 방법도 다룰 것입니다.

DLL 응용 프로그램

그렇다면 DLL이 필요한 이유는 무엇이며 어디에 사용됩니까?. 다음은 응용 프로그램 영역 중 일부입니다.

  • 별도의 라이브러리, 프로그래머에게 유용한 추가 기능이 포함되어 있습니다. 예를 들어 문자열 작업을 위한 함수나 이미지 변환을 위한 복잡한 라이브러리가 있습니다.
  • 리소스 저장소. DLL에는 프로그램과 기능뿐만 아니라 아이콘, 그림, 문자열 배열, 메뉴 등 모든 종류의 리소스를 저장할 수 있습니다.
  • 지원 라이브러리. 다음과 같은 잘 알려진 패키지의 라이브러리가 한 예입니다. 다이렉트X, ICQAPI(ICQ용 API), OpenGL등.
  • 프로그램의 일부. 예를 들어 DLL은 프로그램 창(양식) 등을 저장할 수 있습니다.
  • 플러그인(플러그인). - 그것이 프로그래머의 생각의 진정한 범위입니다! 플러그인은 기능을 확장하는 프로그램에 추가된 것입니다. 예를 들어, 이 기사에서 우리는 자신의 프로그램을 위한 플러그인을 만드는 이론을 살펴볼 것입니다.
  • 공유 리소스. DLL( 동적 링크 라이브러리) 여러 프로그램이나 프로세스에서 동시에 사용할 수 있습니다(소위. 나누는- 공유 리소스)

DLL 작업을 위한 기능 및 트릭에 대한 간략한 설명

그렇다면 DLL로 작업하려면 어떤 트릭과 기능을 사용해야 합니까? 라이브러리에서 함수를 가져오는 두 가지 방법을 분석해 보겠습니다.

편도. DLL을 프로그램에 바인딩합니다.이것은 DLL에서 가져온 함수를 사용하는 가장 간단하고 쉬운 방법입니다. 그러나 이 방법에는 매우 중요한 단점이 있습니다. 프로그램에서 사용하는 라이브러리를 찾을 수 없으면 프로그램이 시작되지 않고 오류가 발생하고 DLL 리소스를 찾을 수 없다고 보고합니다. 그리고 라이브러리는 현재 디렉토리, 프로그램 디렉토리, WINDOWS\SYSTEM 디렉토리 등에서 검색됩니다.
따라서 우선 이 기술의 일반적인 형태는 다음과 같습니다.

구현
...
기능 FunctionName(Par1: Par1Type; Par2: Par2Type; ...): ReturnType; 표준 호출; 외부"DLLNAME.DLL" 이름"기능 이름" 인덱스함수 인덱스;
// 또는 (함수가 아니라 프로시저인 경우):
절차 ProcedureName(파1: Par1Type; Par2: Par2Type; ...); 표준 호출; 외부"DLLNAME.DLL" 이름"절차명" 인덱스프로시저 인덱스;

여기: 함수 이름(또는 프로시저 이름) - 프로그램에서 사용될 함수(또는 프로시저)의 이름.
파1, 파2, ...- 함수 또는 프로시저 매개변수의 이름;
Par1Type, Par2Type, ...- 함수 또는 프로시저의 매개변수 유형(예: 정수);
반환 유형- 반환 값 유형(함수에만 해당)
표준 호출- DLL 자체에서 사용된 것과 정확히 일치해야 하는 지시문.
외부 "DLLNAME.DLL"- 주어진 함수 또는 프로시저를 가져올 외부 DLL의 이름을 지정하는 지시문(이 경우 - DLLNAME.DLL);
이름 "FunctionName"("ProcedureName")- DLL 자체에 있는 함수의 정확한 이름을 지정하는 지시문. 이것은 (라이브러리에 있는) 실제 이름과 다른 이름을 가진 프로그램에서 함수를 사용할 수 있도록 하는 선택적 지시문입니다.
인덱스 FunctionIndex(ProcedureIndex)- DLL에 있는 함수 또는 프로시저의 서수를 지정하는 지시문. 이것은 선택적 지시문이기도 합니다.

투웨이. 동적 DLL 로딩.이것은 훨씬 더 복잡하지만 더 우아한 방법입니다. 첫 번째 방법의 단점이 없습니다. 유일하게 불편한 점은 이 기술을 구현하는데 필요한 코드의 양이 많고, 어려움은 DLL에서 가져온 함수가 이 DLL이 로드되어 메모리에 있을 때만 사용할 수 있다는 것입니다... 아래 예제를 읽을 수 있습니다. 하지만 지금은 이 방법에서 사용하는 WinAPI 함수에 대한 간단한 설명입니다.

로드 라이브러리(lib파일명: PChar) - 지정된 라이브러리 LibFileName을 메모리에 로드합니다. 성공하면 함수는 핸들( 핸들) 메모리의 DLL.
GetProcAddress(기준 치수: 핸들; 프로시저 이름: PChar) - 내보낸 라이브러리 함수의 주소를 읽습니다. 성공하면 함수는 핸들( TFarProc) 로드된 DLL의 기능.
무료 도서관(LibModule: 핸들) - LibModule을 무효화하고 관련된 메모리를 해제합니다. 이 프로시저를 호출한 후에는 이 라이브러리의 기능을 더 이상 사용할 수 없습니다.

실습 및 예

자, 이제 위의 방법과 기술을 사용하는 몇 가지 예를 들어보겠습니다.

이제 동일하지만 두 번째 방법으로 - 동적 로딩:

(... 여기에 파일 헤더와 TForm1 형식의 정의 및 해당 Form1 인스턴스가 있습니다)

var
Form1: TForm1;
GetSimple텍스트: 기능(LangRus: 부울): PChar;
LibHandle: T핸들;

절차 Button1Click(보낸 사람: TObject);
시작하다
("dirt"에서 함수의 주소를 "청소")
@GetSimpleText:= 없음;
(라이브러리를 로드하려고 함)
LibHandle:= LoadLibrary("MYDLL.DLL");
(모든 것이 괜찮다면)
LibHandle >= 32이면 시작
(... 그런 다음 라이브러리에 있는 함수의 주소를 얻으려고 합니다.)
@GetSimpleText:= GetProcAddress(LibHandle,"GetSimpleText");
(여기서 모든 것이 괜찮다면)
@GetSimpleText인 경우<>그럼 제로
(... 그런 다음 이 함수를 호출하고 결과를 표시합니다)
ShowMessage(StrPas(GetSimpleText(True)));
끝;
(그리고 메모리를 해제하고 DLL을 언로드하는 것을 잊지 마십시오)
FreeLibrary(LibHandle);
끝;

노트 : 라이브러리 함수에서 문자열 유형을 사용하는 것을 삼가해야 합니다. 사용할 때 "메모리 공유"에 문제가 있습니다. 델파이가 생성하는 빈 DLL 프로젝트(파일 -> 새로 만들기 -> DLL)의 텍스트에서 이에 대한 자세한 내용(영어로 되어 있음)을 읽을 수 있습니다. 따라서 PChar를 사용한 다음 필요한 경우 StrPas를 사용하여 문자열로 변환하는 것이 좋습니다.

이제 DLL 자체를 직접 분석해 보겠습니다.

DLL 리소스 및 양식에 배치

DLL에는 기능뿐만 아니라 커서, 그림, 아이콘, 메뉴, 텍스트 라인도 배치할 수 있습니다. 우리는 이것에서 멈추지 않을 것입니다. 리소스를 로드하려면 DLL을 로드한 다음 해당 설명자를 받은 후 적절한 기능(LoadIcon, LoadCursor 등)을 사용하여 리소스 자체를 로드해야 합니다. 이 섹션에서는 DLL에서 응용 프로그램 창(예: Delphi의 양식) 배치에 대해서만 간략하게 설명합니다.

이렇게 하려면 새 DLL을 만들고 여기에 새 양식을 추가해야 합니다(파일 -> 새로 만들기 -> DLL, 파일 -> 새 양식). 또한 양식이 대화 상자(모달 양식(bsDialog))인 경우 DLL에 다음 함수를 추가합니다(예: 양식은 Form1이고 해당 클래스는 TForm1임).

DLL에 비모달 양식을 배치해야 하는 경우 양식 열기 및 닫기의 두 가지 기능을 만들어야 합니다. 이 경우 DLL이 이 양식에 대한 핸들을 기억하도록 해야 합니다.

플러그인 만들기

여기에서는 플러그인을 자세히 고려하지 않을 것입니다. 위에 이미 제공된 예제는 DLL 프로그래밍의 가장 큰 부분을 쉽게 이해하는 데 도움이 될 것입니다. 플러그인은 기능을 확장하는 프로그램에 추가된 것임을 상기시켜 드리겠습니다. 동시에 프로그램 자체는 반드시 그러한 추가 사항의 존재를 제공하고 목적을 달성할 수 있도록 해야 합니다.

즉, 예를 들어 이미지 변환을 수행하는 그래픽 편집기용 플러그인을 만들려면 플러그인에 최소한 두 가지 기능을 제공해야 합니다(따라서 프로그램에서 이러한 기능을 호출해야 함). 이 플러그인을 메뉴(또는 도구 모음)에 추가하기 위해 플러그인(및/또는 해당 유형)의 이름을 반환하고 주요 기능은 이미지를 보내고 받는 것입니다. 저것들. 먼저 프로그램은 플러그인을 검색한 다음 발견된 각 플러그인에 대해 엄격하게 정의된 이름(예: GetPluginName)으로 식별 기능을 호출하고 원하는 항목을 메뉴에 추가한 다음 사용자가 이 항목을 선택하면 다음을 호출합니다. 입력 이미지(또는 이 이미지를 포함하는 파일 이름)를 전달하는 두 번째 함수와 이 함수는 차례로 이미지를 처리하고 새 형식(또는 새 이미지가 있는 파일 이름)으로 반환합니다. 이것이 플러그인의 요점입니다... :-)

발문

이 기사는 Borland Delphi에서 DLL을 사용하고 생성하는 주요 측면을 보여줍니다. 질문이 있으시면 이메일로 저에게 보내주십시오: [이메일 보호됨], 그리고 더 나은 방법 - 다른 사용자가 귀하의 질문을 보고 답변할 수 있도록 이 사이트의 회의에 글을 작성하십시오!

카리크 니콜라이. 모스크바 지역, Zhukovsky


프로그래밍 기술의 급속한 발전으로 인해 점점 더 많은 사람들이 프로그램의 기능을 향상시키는 문제에 직면하고 있습니다. 이 기사는 이 문제, 즉 볼랜드 델파이에서 DLL 프로그래밍에 전념합니다. 또한 DLL 사용 문제를 다루기 때문에 다른 사람의 DLL(시스템 DLL 포함)에서 함수를 가져오는 방법도 다룰 것입니다. WinAPI).

DLL 응용 프로그램

그렇다면 DLL이 필요한 이유는 무엇이며 어디에 사용됩니까?. 다음은 응용 프로그램 영역 중 일부입니다.

프로그래머에게 유용한 추가 기능을 포함하는 별도의 라이브러리.

예를 들어 문자열 작업을 위한 함수나 이미지 변환을 위한 복잡한 라이브러리가 있습니다.

리소스 저장소. DLL에는 프로그램과 기능뿐만 아니라 아이콘, 그림, 문자열 배열, 메뉴 등 모든 종류의 리소스를 저장할 수 있습니다.

지원 라이브러리. 예를 들어 DirectX, ICQAPI(ICQ용 API), OpenGL 등과 같은 잘 알려진 패키지의 라이브러리가 있습니다.

프로그램의 일부입니다. 예를 들어 DLL은 프로그램 창(양식) 등을 저장할 수 있습니다.

플러그인. - 그것이 프로그래머의 생각의 진정한 범위입니다! 플러그인은 기능을 확장하는 프로그램에 추가된 것입니다. 예를 들어, 이 기사에서 우리는 자신의 프로그램을 위한 플러그인을 만드는 이론을 살펴볼 것입니다.

공유 리소스. DLL(Dynamic Link Library)은 한 번에 여러 프로그램이나 프로세스에서 사용할 수 있습니다(소위 공유는 공유 리소스입니다).

DLL 작업을 위한 기능 및 트릭에 대한 간략한 설명

그렇다면 DLL로 작업하려면 어떤 트릭과 기능을 사용해야 합니까? 라이브러리에서 함수를 가져오는 두 가지 방법을 분석해 보겠습니다.

편도. DLL을 프로그램에 바인딩합니다. 이것은 DLL에서 가져온 함수를 사용하는 가장 간단하고 쉬운 방법입니다. 그러나 이 방법에는 매우 중요한 단점이 있습니다. 프로그램에서 사용하는 라이브러리를 찾을 수 없으면 프로그램이 시작되지 않고 오류가 발생하고 DLL 리소스를 찾을 수 없다고 보고합니다. 그리고 라이브러리는 현재 디렉토리, 프로그램 디렉토리, WINDOWSSYSTEM 디렉토리 등에서 검색됩니다.

따라서 우선 이 기술의 일반적인 형태는 다음과 같습니다.

구현
...
함수 FunctionName(Par1: Par1Type; Par2: Par2Type; ...): ReturnType; 표준 호출; 외부 "DLLNAME.DLL" 이름 "FunctionName" 인덱스 FuncIndex;
// 또는 (함수가 아니라 프로시저인 경우):
프로시저 ProcedureName(Par1: Par1Type; Par2: Par2Type; ...); 표준 호출; 외부 "DLLNAME.DLL" 이름 "ProcedureName" 인덱스 ProcIndex;

여기: FunctionName(또는 ProcedureName) - 프로그램에서 사용할 함수(또는 프로시저)의 이름.

Par1, Par2, ... - 함수 또는 프로시저 매개변수의 이름.
Par1Type, Par2Type, ...- 함수 또는 프로시저의 매개변수 유형(예: 정수)
반환 유형- 반환 값 유형(함수에만 해당)
표준 호출- DLL 자체에서 사용된 것과 정확히 일치해야 하는 지시문.
외부 "DLLNAME.DLL"- 주어진 함수 또는 프로시저를 가져올 외부 DLL의 이름을 지정하는 지시문(이 경우 DLLNAME.DLL)
이름 "함수 이름"("ProcedureName")은 DLL 자체에 있는 함수의 정확한 이름을 지정하는 지시문입니다.

이것은 (라이브러리에 있는) 실제 이름과 다른 이름을 가진 프로그램에서 함수를 사용할 수 있도록 하는 선택적 지시문입니다.
index FunctionIndex(ProcedureIndex) - DLL에 있는 함수 또는 프로시저의 서수를 지정하는 지시문. 이것은 선택적 지시문이기도 합니다.

투웨이. 동적 DLL 로딩. 이것은 훨씬 더 복잡하지만 더 우아한 방법입니다. 첫 번째 방법의 단점이 없습니다. 유일하게 불편한 점은 이 기술을 구현하는데 필요한 코드의 양이 많고, 어려움은 DLL에서 가져온 함수가 이 DLL이 로드되어 메모리에 있을 때만 사용할 수 있다는 것입니다... 아래 예제를 읽을 수 있습니다. 하지만 지금은 이 방법에서 사용하는 WinAPI 함수에 대한 간단한 설명입니다.

로드 라이브러리(LibFileName: PChar) - 지정된 라이브러리 LibFileName을 메모리에 로드합니다. 성공하면 함수는 메모리의 DLL에 대한 핸들(THandle)을 반환합니다.
GetProcAddress(모듈: THandle ; ProcName: PChar) - 내보낸 라이브러리 함수의 주소를 읽습니다. 성공하면 함수는 로드된 DLL의 함수에 대한 핸들(TFarProc)을 반환합니다.
무료 도서관(LibModule: THandle) - LibModule을 무효화하고 관련된 메모리를 해제합니다. 이 프로시저를 호출한 후에는 이 라이브러리의 기능을 더 이상 사용할 수 없습니다.

실습 및 예

자, 이제 위의 방법과 기술을 사용하는 몇 가지 예제를 제공할 시간입니다. 예제 1. DLL을 프로그램에 바인딩

구현

(외부 라이브러리 함수 정의)

함수 GetSimpleText(LangRus: 부울): PChar; 표준 호출; 외부 "MYDLL.DLL";


시작하다
(그리고 그것을 사용)
ShowMessage(StrPas(GetSimpleText(False)));
(ShowMessage - 지정된 캡션이 있는 대화 상자 표시, StrPas - PChar 문자열을 문자열로 변환)
끝;

이제 동일하지만 두 번째 방법 - 동적 로딩 사용: 예제 2. DLL의 동적 로딩

(... 여기에 파일 헤더와 TForm1 형식의 정의 및 해당 Form1 인스턴스가 있습니다)

바르
Form1: TForm1;
GetSimpleText: 함수(LangRus: 부울): PChar;
LibHandle: T핸들;

ProcedureButton1Click(발신자: TObject);
시작하다
("dirt"에서 함수의 주소를 "청소")
@GetSimpleText:= 없음;
(라이브러리를 로드하려고 함)
LibHandle:= LoadLibrary("MYDLL.DLL");
(모든 것이 괜찮다면)
LibHandle >= 32이면 시작
(... 그런 다음 라이브러리에 있는 함수의 주소를 얻으려고 합니다.)
@GetSimpleText:= GetProcAddress(LibHandle,"GetSimpleText");
(여기서 모든 것이 괜찮다면)
@GetSimpleText nil이면
(... 그런 다음 이 함수를 호출하고 결과를 표시합니다)
ShowMessage(StrPas(GetSimpleText(True)));
끝;
(그리고 메모리를 해제하고 DLL을 언로드하는 것을 잊지 마십시오)
FreeLibrary(LibHandle);
끝;

노트: 라이브러리 함수에서 문자열 유형을 사용하는 것을 삼가해야 합니다. 사용할 때 "메모리 공유"에 문제가 있습니다. 델파이가 생성하는 빈 DLL 프로젝트(파일 -> 새로 만들기 -> DLL)의 텍스트에서 이에 대한 자세한 내용(영어로 되어 있음)을 읽을 수 있습니다. 따라서 PChar를 더 잘 사용하고 함수와 함께 필요한 경우 문자열로 변환하십시오. StrPas.

이제 DLL 자체를 직접 분석해 보겠습니다. 예제 3. 프로젝트 소스 MYDLL.DPR
라이브러리 mydll;

SysUtils, 클래스를 사용합니다.

(우리는 함수를 stdcall로 정의합니다)
함수 GetSimpleText(LangRus: 부울): PChar; 표준 호출;
시작하다
(LangRus에 따라 러시아어(True) 또는 영어(False) 구문을 반환합니다.)
그렇다면 LangRus
결과:= PChar("Hello World!")
또 다른
결과:= PChar("안녕하세요, 세계입니다!");
끝;

(export 지시문은 이 DLL이 내보낼 함수를 지정합니다)
GetSimpleText를 내보냅니다.

시작하다
끝.

DLL 리소스 및 양식에 배치

DLL에는 기능뿐만 아니라 커서, 그림, 아이콘, 메뉴, 텍스트 라인도 배치할 수 있습니다. 우리는 이것에서 멈추지 않을 것입니다. 리소스를 로드하려면 DLL을 로드한 다음 해당 설명자를 받은 후 적절한 기능(LoadIcon, LoadCursor 등)을 사용하여 리소스 자체를 로드해야 합니다. 이 섹션에서는 DLL에서 응용 프로그램 창(예: Delphi의 양식) 배치에 대해서만 간략하게 설명합니다.

이렇게 하려면 새 DLL을 만들고 여기에 새 양식을 추가해야 합니다(파일 -> 새로 만들기 -> DLL, 파일 -> 새 양식). 또한 양식이 대화 상자(모달 양식(bsDialog))인 경우 DLL에 다음 함수를 추가합니다(예: 양식의 이름은 Form1이고 해당 클래스는 TForm1). 예 4. DLL
함수 ShowMyDialog(Msg: PChar): 부울; 표준 호출;

...
ShowMyDialog 내보내기;

함수 ShowMyDialog(Msg: PChar): 부울;
시작하다
(TForm1에서 Form1의 인스턴스 생성)
Form1:= TForm1.Create(응용 프로그램);
(Label1에는 Msg가 표시됩니다.)
Form1.Label1.Caption:= StrPas(메시지);
(OK를 눌렀을 때만 True 반환(ModalResult = mrOk))
결과:= (Form1.ShowModal = mrOk);
(메모리 해제)
Form1.무료;
끝;

DLL에 비모달 양식을 배치해야 하는 경우 양식 열기 및 닫기의 두 가지 기능을 만들어야 합니다. 이 경우 DLL이 이 양식에 대한 핸들을 기억하도록 해야 합니다.

플러그인 만들기

여기에서는 플러그인을 자세히 고려하지 않을 것입니다. 위에 이미 제공된 예제는 DLL 프로그래밍의 가장 큰 부분을 쉽게 이해하는 데 도움이 될 것입니다. 플러그인은 기능을 확장하는 프로그램에 추가된 것임을 상기시켜 드리겠습니다. 동시에 프로그램 자체는 반드시 그러한 추가 사항의 존재를 제공하고 목적을 달성할 수 있도록 해야 합니다.

즉, 예를 들어 이미지 변환을 수행하는 그래픽 편집기용 플러그인을 만들려면 플러그인에 최소한 두 가지 기능을 제공해야 합니다(따라서 프로그램에서 이러한 기능을 호출해야 함). 이 플러그인을 메뉴(또는 도구 모음)에 추가하기 위해 플러그인(및/또는 해당 유형)의 이름을 반환하고 주요 기능은 이미지를 보내고 받는 것입니다. 저것들. 먼저 프로그램은 플러그인을 검색한 다음 발견된 각 플러그인에 대해 엄격하게 정의된 이름(예: GetPluginName)으로 식별 기능을 호출하고 원하는 항목을 메뉴에 추가한 다음 사용자가 이 항목을 선택하면 다음을 호출합니다. 입력 이미지(또는 이 이미지를 포함하는 파일 이름)를 전달하는 두 번째 함수와 이 함수는 차례로 이미지를 처리하고 새 형식(또는 새 이미지가 있는 파일 이름)으로 반환합니다. 이것이 플러그인의 요점입니다... :-)

델파이에서 DLL 사용하기
  • DLL의 개념
  • Delphi에서 DLL 만들기(내보내기)
  • Delphi에서 DLL 사용(가져오기)
  • VCL 개체를 사용하여 데이터 작업을 수행하는 DLL
  • DLL의 예외
  • DLL의 개념

DOS에서 프로그래밍하는 과정을 생각해 보십시오. 프로그램의 소스 코드를 기계어로 변환하는 작업에는 컴파일과 링크라는 두 가지 프로세스가 포함됩니다. 연결 과정에서 개별 프로그램 모듈을 연결하는 링커는 함수 및 프로시저의 선언뿐만 아니라 전체 코드를 프로그램 코드에 배치합니다. 이런 식으로 하나의 프로그램을 준비했습니다. 다른 하나, 세 번째... 그리고 모든 곳에서 동일한 기능의 코드가 프로그램에 완전히 배치되었습니다.

Program1 Program2: : MyFunc(:) MyFunc(:) : : 기능 코드 MyFunc 기능 코드 다른 기능의 MyFunc 코드 다른 기능의 코드

멀티태스킹 환경에서 이러한 접근 방식은 최소한 무모할 것입니다. 왜냐하면 수많은 동일한 기능이 사용자 인터페이스 요소 그리기, 시스템 리소스 액세스 등을 담당한다는 것이 분명하기 때문입니다. 모든 응용 프로그램에서 완전히 복제되어 가장 비싼 리소스인 RAM이 빠르게 고갈됩니다. 이 문제를 해결하기 위해 UNIX 계열 플랫폼에서도 동적 연결 개념이 제안되었습니다(그림 2 참조).

그러나 동적 링크 라이브러리(DLL)와 일반 응용 프로그램의 차이점은 무엇입니까? 이를 이해하기 위해서는 task(task), application(instance)의 instance(copy), module(module)의 개념을 명확히 할 필요가 있다.

단일 응용 프로그램의 여러 인스턴스를 실행할 때 Windows는 코드 및 리소스의 복사본 하나만 RAM에 로드합니다. 응용 프로그램 모듈은 여러 개의 개별 데이터 세그먼트, 스택 및 메시지 대기열을 생성합니다(그림 3 참조). 각 세트는 다음과 같습니다. 작업, 이해 Windows. 애플리케이션 사본은 애플리케이션 모듈이 실행되는 컨텍스트입니다.

DLL - 라이브러리도 모듈입니다. 단일 복사본으로 메모리에 상주하며 코드 세그먼트와 리소스, 데이터 세그먼트를 포함합니다(그림 4 참조).

DLL은 응용 프로그램과 달리 라이브러리이며 스택이나 메시지 큐가 없습니다. DLL에 배치된 함수는 스택을 사용하여 호출 응용 프로그램의 컨텍스트에서 실행됩니다. 그러나 이러한 동일한 기능은 응용 프로그램의 복사본이 아니라 라이브러리의 데이터 세그먼트를 사용합니다.

DLL의 이러한 구성으로 인해 실행 중인 모든 응용 프로그램이 해당 모듈에 특정 표준 기능을 포함하지 않고 하나의 DLL 모듈을 사용하기 때문에 메모리가 절약됩니다.

종종 DLL의 형태로 별도의 기능 세트가 생성되어 하나 또는 다른 논리적 기능에 따라 결합됩니다. 이는 Pascal에서 모듈이 개념적으로(단위의 의미에서) 계획되는 방식과 유사합니다. 차이점은 Pascal 모듈의 기능은 연결 단계에서 정적으로 연결되고 DLL의 기능은 런타임에 동적으로 연결된다는 것입니다.

Delphi에서 DLL 만들기(내보내기)

DLL 프로그래밍을 위해 Delphi는 다양한 키워드와 구문 규칙을 제공합니다. 중요한 것은 - 델파이의 DLL은 프로그램과 같은 프로젝트입니다.

DLL 템플릿을 고려하십시오.


이러한 템플릿의 프로젝트 파일 이름은 MYDLL.DPR이어야 합니다.

안타깝게도 델파이 IDE에서는 프로그램 프로젝트만 자동으로 생성되기 때문에 DLL 프로젝트를 수동으로 준비해야 합니다. Delphi 2.0은 이러한 불편함을 제거했습니다.

프로그램과 마찬가지로 DLL에는 uses 섹션이 있습니다. 초기화 부분은 선택 사항입니다. 내보내기 섹션에는 외부 응용 프로그램에서 액세스해야 하는 기능이 나열됩니다.

함수(및 프로시저) 내보내기는 여러 가지 방법으로 수행할 수 있습니다.

  • 숫자로(색인)
  • 이름으로

이에 따라 다른 구문이 사용됩니다.


Windows에는 DLL의 "상주 함수", 즉 메모리에 있는 DLL의 수명 내내 메모리에 있는 함수라는 개념이 있기 때문에 Delphi에는 구성 및 이러한 종류의 내보내기 도구가 있습니다.


그러면 내보낸 함수의 인덱싱이 Delphi에서 자동으로 수행되고 이러한 내보내기는 함수 이름과 일치하는 이름으로 내보내기로 간주됩니다. 그런 다음 응용 프로그램에서 가져온 함수의 선언은 DLL의 함수 선언 이름과 일치해야 합니다. 이미 가져온 함수에 부과된 지시문에 대해서는 아래에서 이에 대해 설명합니다.

Delphi에서 DLL 사용(가져오기)

수입품 정리, 즉 DLL에서 내보낸 함수에 액세스하고 이를 내보내는 델파이는 표준 기능을 제공합니다.

위에 표시된 예의 경우 프로그램은 다음과 같이 DLL에서 가져온 함수를 선언해야 합니다.


이 방법을 정적 가져오기라고 합니다.

눈치채셨겠지만 DLL이 포함된 파일의 확장자는 지정되지 않았습니다. 기본적으로 *.DLL 및 *.EXE 파일이 사용됩니다. 파일의 확장자가 다른 경우(예: Delphi의 COMPLIB.DCL) 또는 DLL 및 가져온 함수의 동적 정의가 필요한 경우(예: 프로그램이 다른 그래픽 형식으로 작동하고 각각에 대해 그들에게는 별도의 DLL이 있습니다.)?

이러한 종류의 문제를 해결하기 위해 소위 동적 가져오기를 사용하여 Windows API에 직접 액세스할 수 있습니다.


용도 WinTypes, WinProcs, ... ; 유형 TMyProc = 절차 ; var핸들: THandle; MyImportProc: TMyProc; 시작하다핸들:= LoadLibrary("MYDLL"); 만약에핸들 >= 32 그 다음에 (만약에 시작하다@MyImportProc:= GetProcAddress(핸들, "MYEXPORTPROC"); 만약에 MyImportProc 그 다음에 ... (가져온 프로시저 사용) ; FreeLibrary(핸들); ;

내보내기/가져오기 선언의 구문 다이어그램, DLL 종료점 대체 및 기타 예제는 온라인 도움말 Delphi, Borland RAD Pack for Delphi에 포함된 Object Pascal Language Guide 및 예를 들어 "Teach Yourself" 책에서 찾을 수 있습니다. 21일 만에 델파이"

컴파일러에 의해 생성된 코드(이제 더 최적화됨)를 제외하고 모든 구문 규칙은 Borland Pascal 7.0에서와 동일하게 유지됩니다.

VCL 개체를 사용하여 데이터 작업을 수행하는 DLL

고유한 동적 라이브러리를 생성할 때 다른 DLL에서 함수 호출을 사용할 수 있습니다. 이러한 DLL의 예는 델파이 배포판(X:\DELPHI\DEMOS\BD\BDEDLL)에 있습니다. 이 DLL에는 테이블의 데이터를 표시하고 VCL 개체(TTable, TDBGrid, TSession)를 사용하여 액세스하는 형식이 포함되어 있으며, 이 개체는 차례로 BDE 함수를 호출합니다. 이 예제에 대한 주석에서 다음과 같이 이러한 DLL에는 제한이 있습니다. 여러 작업에서 동시에 사용할 수 없습니다. DB 모듈이 연결될 때 자동으로 생성되는 Session 객체는 태스크가 아닌 모듈에 대해 초기화되기 때문이다. 다른 응용 프로그램에서 이 DLL을 두 번째로 로드하려고 하면 오류가 발생합니다. 여러 작업이 동시에 DLL을 로드하는 것을 방지하려면 몇 가지 단계를 수행해야 합니다. 예제에서 DLL이 현재 다른 작업에서 사용 중인지 확인하는 절차입니다.

DLL의 예외

델파이에서 만든 DLL에서 예외를 던지면 DLL 내에서 예외가 처리되지 않은 경우 전체 애플리케이션이 종료됩니다. 따라서 DLL을 개발할 때 발생할 수 있는 모든 문제를 제공하는 것이 바람직합니다. 가져온 함수의 결과를 문자열이나 숫자로 반환하고 필요한 경우 프로그램에서 예외를 다시 throw하는 것이 좋습니다.


기능마이펑크: ; 시작하다 노력하다 (실제 기능 코드) 제외하고 ~에결과: 예외 하다결과:=형식(DllErrorViewingTable, ) 또 다른결과:= 형식(DllErrorViewingTable, ["알 수 없는 오류"]); ; ;

프로그램의 코드:


StrResult:= MyFunc; 만약에결과 "" 그 다음에 들어올리다예외 생성(StrResult);

기사 델파이에서 DLL 사용하기 DLL 파일 시스템 및 플러그인 섹션은 Delphi 및 FreePascal 개발자에게 유용할 수 있습니다.

나는 계속해서 논의할 뉴스레터의 다음 호에 주의를 기울입니다.
Borland Delphi에서 DLL의 개발 및 사용 문제. 신규 구독자 여러분께 알려드립니다.
메일링 리스트 아카이브, 13호에서 기사의 첫 부분을 볼 수 있습니다.
저에게 편지를 썼지만 답장을 받지 못한 분들께 사과드립니다. 가까운 시일 내에 이 문제를 해결하도록 노력하겠습니다.
계속합시다.

동적 라이브러리에 있는 프로시저나 함수를 사용하기 전에,
DLL을 RAM에 로드해야 합니다. 라이브러리 로딩 가능
정적 로딩과 동적 로딩의 두 가지 방법 중 하나입니다.
두 방법 모두 장점과 단점이 있습니다.
정적 로딩은 동적 라이브러리가 자동으로 로드됨을 의미합니다.
그것을 사용하는 응용 프로그램이 시작될 때. 이 다운로드 방법을 사용하려면
에서 내보낸 것을 설명할 때 외부 키워드를 사용해야 합니다.
동적 라이브러리 함수 또는 프로시저. DLL은 프로그램이 시작될 때 자동으로 로드되며,
동일한 방식으로 내보낸 모든 서브루틴을 사용할 수 있습니다.
마치 애플리케이션 모듈 내부에 설명된 것처럼.
이것은 DLL에 있는 코드를 사용하는 가장 쉬운 방법입니다.
이 방법의 단점은 라이브러리 파일이
응용 프로그램에 링크가 있고 없는 경우 프로그램이 로드를 거부합니다.
동적 방법의 의미는 응용 프로그램 시작 시 라이브러리를 로드하지 않고,
그리고 당신이 정말로 그것을 필요로 하는 순간. 기능이 설명되어 있으면 스스로 판단하십시오.
동적 라이브러리에서는 프로그램 실행의 10%에서만 사용되며 그 다음에는 절대 사용되지 않습니다.
정적 로드 방법을 사용하는 것은 의미가 없습니다. 이 경우 메모리에서 라이브러리 언로드
또한 귀하의 통제하에 있습니다. 이 방법의 또 다른 장점
DLL 로딩은 (명백한 이유로) 애플리케이션 시작 시간의 감소입니다.
그리고 이 방법의 단점은 무엇입니까? 가장 중요한 것은 나에게 보이는 것입니다.
이 방법은 위에서 논의한 정적 로딩보다 더 번거롭습니다.
먼저 LoadLibrary Windows API 함수를 사용해야 합니다.
내보낸 프로시저 또는 함수에 대한 포인터를 얻으려면
GetProcAddress 함수를 사용합니다. DLL 사용을 마친 후
FreeLibrary를 사용하여 다운로드해야 합니다.
DLL에서 로드된 프로시저 및 함수를 호출합니다.
프로시저와 함수가 호출되는 방식은 동적 라이브러리를 로드한 방법에 따라 다릅니다.
이 서브루틴이 있는 위치.
정적으로 로드된 DLL에서 함수와 프로시저를 호출하는 것은 매우 간단합니다. 처음에는 응용 프로그램에서
내보낸 기능(절차)에 대한 설명을 포함해야 합니다. 그 후에 당신은 그들을 사용할 수 있습니다
애플리케이션의 모듈 중 하나에서 설명된 것과 같은 방식으로.
DLL에 포함된 함수나 프로시저를 가져오려면 다음을 사용해야 합니다.
선언의 외부 수정자. 예를 들어 위에서 논의한 HelloWorld 절차의 경우
다음 라인은 호출 애플리케이션에 배치되어야 합니다.
프로시저 SayHello(AForm: TForm); 외부 myfirstdll.dll";
외부 키워드는 프로시저가 다음 위치에서 찾을 수 있음을 컴파일러에 알립니다.
동적 라이브러리(이 경우 myfirstdll.dll).
이 프로시저에 대한 호출은 다음과 같습니다.
...
HelloWorld(자신);
...
함수와 프로시저를 가져올 때 이름과 인터페이스를 작성할 때 특히 주의하십시오!
사실은 응용 프로그램을 컴파일하는 과정에서 개체 이름의 정확성에 대한 확인이 이루어지지 않으며,
DLL에서 내보낸 것은 구현되지 않으며, 기능을 잘못 설명하면
그러면 예외는 응용 프로그램의 런타임에만 throw됩니다.
DLL에서 가져오기는 프로시저(함수) 이름, 서수 또는
다른 이름으로.
첫 번째 경우에는 가져오는 프로시저와 라이브러리의 이름을 선언하기만 하면 됩니다.
(우리는 이것을 조금 더 높게 논의했습니다). 일련 번호로 가져오려면 다음 번호를 지정해야 합니다.
절차 HelloWorld(AForm: TForm); 외부 myfirstdll.dll 인덱스 15;
이 경우 가져오기 절차에 지정한 이름이 다음과 같을 필요는 없습니다.
DLL 자체에 지정되어 있습니다. 저것들. 위의 항목 의미
동적 라이브러리 myfirstdll.dll에서 가져오고 있음을 내보낸 프로시저
열다섯 번째, 애플리케이션 내에서 이 절차의 이름은 SayHello입니다.
어떤 이유로 위에서 설명한 가져오기 방법을 사용하지 않는 경우,
그러나 여전히 가져온 함수(프로시저)의 이름을 변경하려면 세 번째 방법을 사용할 수 있습니다.
절차 CoolProcedure; 외부 myfirstdll.dll 이름 "DoSomethingReallyCool";
여기에서 가져온 프로시저 CoolProcedure의 이름은 DoSomethingReallyCool입니다.
동적으로 로드된 라이브러리에서 가져온 프로시저 및 함수 호출
위에서 설명한 방법보다 다소 복잡합니다. 이 경우 선언해야 합니다.
사용하려는 함수 또는 프로시저에 대한 포인터입니다.
HelloWorld 절차를 기억하십니까? 하기 위해 해야 할 일을 보자.
DLL의 동적 로드의 경우 실행을 위해 호출합니다. 너 먼저
이 절차를 설명하는 유형을 선언해야 합니다.
유형
THelloWorld = 절차(AForm: TForm);
이제 동적 라이브러리를 로드해야 합니다. GetProcAddress를 사용하여
프로시저에 대한 포인터, 실행을 위해 이 프로시저를 호출하고 마지막으로 메모리에서 DLL을 언로드합니다.
다음은 이 작업을 수행하는 방법을 보여주는 코드입니다.

DLL인스턴스: THandle ;

HelloWorld:THelloWorld;

시작하다

(DLL 로드)

(포인터 가져오기)

(실행할 프로시저 호출)

헬로월드(셀프) ;

(RAM에서 DLL 언로드)

무료 라이브러리(DLL인스턴스) ;

끝 ;

위에서 언급했듯이 DLL을 정적으로 로드할 때의 단점 중 하나는
하나 이상의 라이브러리가 없는 경우 응용 프로그램을 계속합니다. 다이나믹의 경우
로드할 때 프로그래밍 방식으로 이러한 상황을 처리하고 프로그램이
저절로 떨어졌습니다. LoadLibrary 및 GetProcAddress 함수에서 반환된 값에 따라 다음을 수행할 수 있습니다.
라이브러리 로드가 성공했는지 여부와 응용 프로그램에 필요한 절차가 라이브러리에서 발견되었는지 여부를 확인합니다.
아래 코드는 이를 보여줍니다.

절차 TForm1.DynamicLoadBtnClick (발신자: TObject) ;

유형

THelloWorld = 절차(AForm: TForm) ;

DLL인스턴스: THandle ;

HelloWorld:THelloWorld;

시작하다

DLLInstance:= LoadLibrary("myfirstdll.dll" ) ;

DLLInstance = 0이면 시작

메시지Dlg( "DLL을 로드할 수 없습니다", mtError, [mbOK], 0 ) ;

출구;

끝 ;

@HelloWorld:= GetProcAddress(DLLInstance, "HelloWorld" ) ;

@HelloWorld nil이면

헬로월드(셀프)

또 다른

메시지Dlg( "요청한 절차를 찾을 수 없습니다!", mtError, [mbOK], 0 ) ;

무료 라이브러리(DLL인스턴스) ;

끝 ;

DLL에는 코드뿐만 아니라 양식도 저장할 수 있습니다.
또한 동적 라이브러리에서 양식을 만들고 배치하는 것은 작업과 크게 다르지 않습니다.
일반 프로젝트의 양식과 함께. 먼저 라이브러리를 작성하는 방법을 살펴보겠습니다.
양식이 포함된 다음 DLL에서 MDI 기술을 사용하는 방법에 대해 설명합니다.
예제와 함께 양식을 포함하는 DLL의 개발을 시연하겠습니다.
따라서 먼저 새로운 동적 라이브러리 프로젝트를 생성해 보겠습니다.
이렇게 하려면 파일|새로 만들기 메뉴 항목을 선택한 다음 DLL 아이콘을 두 번 클릭합니다.
그러면 다음 코드와 같은 내용이 표시됩니다.

결과 프로젝트를 저장합니다. DllForms.dpr이라고 합시다.
이제 새 양식을 만들어야 합니다. 이것은 다양한 방법으로 수행할 수 있습니다.
예를 들어 File|New Form 메뉴 항목을 선택합니다. 양식에 일부 구성 요소를 추가합니다.
양식 이름을 DllForm으로 지정하고 결과 단위를 DllFormUnit.pas로 저장하겠습니다.
프로젝트의 기본 모듈로 돌아가서 여기에 ShowForm 함수를 배치해 보겠습니다. 이 작업에는 다음이 포함됩니다.
양식을 만들어 화면에 표시합니다. 이를 위해 아래 코드를 사용하십시오.

형식: TDLLForm;

시작하다

결과:= Form.ShowModal ;

양식.무료 ;

끝 ;

프로젝트가 오류 없이 컴파일되기 위해서는 uses 섹션에 Forms 모듈을 추가해야 한다는 사실에 주목합니다.
export 키워드를 사용하여 함수를 내보냅니다.
수출
쇼폼;
프로젝트를 컴파일하고 dllforms.dll 파일을 얻습니다. 이 간단한 단계가 전부입니다
수집을 위해 해야 할 일 ShowForm 함수는 stdcall 키워드를 사용하여 선언됩니다.
함수를 내보낼 때 규칙을 사용하도록 컴파일러에 신호를 보냅니다.
표준 호출 규칙에 따라. 이 방법으로 함수를 내보내면
델파이에서 만든 어플리케이션 뿐만 아니라 개발된 DLL을 사용할 수 있는 기능.
호출 규칙은 함수가 호출될 때 인수가 전달되는 방식을 정의합니다.
stdcall, cdecl, pascal, register, safecall의 다섯 가지 기본 규칙이 있습니다.
델파이 도움말 파일의 "호출 규칙" 섹션을 보면 이에 대해 자세히 알아볼 수 있습니다.
또한 ShowForm 함수에서 반환된 값은
ShowModal 값에 해당합니다. 이 방법으로 일부 정보를 전달할 수 있습니다.
호출 응용 프로그램에 대한 양식의 상태에 대해.
다음은 두 개의 목록이며, 그 중 첫 번째 목록에는 전체 파일 코드가 포함되어 있습니다.
DLL 프로젝트(형식이 있는 모듈은 여기에 표시되지 않음)이고 두 번째는 호출 응용 프로그램의 모듈입니다.
방금 개발한 라이브러리를 사용합니다.

라이브러리 DllForms;

용도

"DllFormUnit.pas"의 DllFormUnit(DllForm) ;

($R*.RES)

함수 ShowForm: 정수 ; 표준 호출 ;

형식: TDLLForm;

시작하다

양식:= TDLLForm.Create(응용 프로그램) ;

결과:= Form.ShowModal ;

양식.무료 ;

끝 ;

시작하다

끝.


단위 TestAppUnit;

상호 작용

용도

Windows, 메시지, SysUtils, 클래스, 그래픽,

컨트롤, 양식, 대화 상자, StdCtrls;

유형

TForm1 = 클래스(TForm)

버튼1: T버튼;

절차 Button1Click(보낸 사람: TObject) ;

사적인

(비공개 선언)

공공의

(공개 선언)

끝 ;

Form1: TForm1;

함수 ShowForm: 정수 ; 표준 호출 ;

외부 "dllforms.dll" ;

구현

($R *.DFM)

절차 TForm1.Button1Click (발신자: TObject ) ;

시작하다

끝 ;

끝.

함수를 내보낼 때도 stdcall 키워드가 사용되었습니다.
DLL에서 자식 폼 작업에 특히 주의해야 합니다. 예를 들어,
호출 응용 프로그램에서 기본 양식에는 MDIForm으로 설정된 FormStyle 속성이 있습니다.
그런 다음 MDIChild 양식 DLL에서 호출하려고 하면 화면에 오류 메시지가 나타납니다.
활성 MDI 양식이 없다고 표시됩니다.
자식 창을 표시하려고 하는 순간 VCL은 정확성을 확인합니다.
응용 프로그램 기본 양식의 FormStyle 속성입니다. 그러나 우리의 경우 모든 것이 올바른 것 같습니다.
그래서 무슨 거래? 문제는 이러한 검사를 수행할 때 Application 객체가 고려된다는 것입니다.
호출 응용 프로그램이 아니라 동적 라이브러리 자체가 소유합니다.
물론 DLL에 기본 형식이 없기 때문에 검사에서 오류가 발생합니다.
이러한 상황을 피하기 위해서는 동적 라이브러리의 Application 객체에 할당해야 합니다.
호출 응용 프로그램의 Application 개체입니다. 당연히 이것은 다음과 같은 경우에만 작동합니다.
호출 프로그램이 VCL 응용 프로그램인 경우. 또한 메모리에서 라이브러리를 언로드하기 전에
라이브러리의 Application 개체 값을 원래 상태로 되돌려야 합니다.
이렇게 하면 메모리 관리자가 라이브러리가 차지하는 RAM을 정리할 수 있습니다.
따라서 라이브러리의 기본 Application 개체에 대한 포인터를 저장해야 합니다.
값을 복원할 때 사용할 수 있는 전역 변수에 있습니다.
이제 조금 돌아가서 배치된 작업에 필요한 단계를 나열해 보겠습니다.
DLL MDIChild 형식.
동적 라이브러리에서 TApplication 유형의 전역 변수를 생성합니다.
전역 변수에 응용 프로그램 DLL 개체에 대한 포인터를 저장합니다.
동적 라이브러리의 Application 개체에 Application에 대한 포인터를 할당합니다.
호출 응용 프로그램.
MDIChild 양식을 만들고 작업합니다.
동적 라이브러리의 Application 개체 값을 원래 상태로 되돌립니다.
메모리에서 DLL을 언로드합니다.
첫 번째 단계는 간단합니다. DLL 모듈의 맨 위에 다음 코드를 입력하기만 하면 됩니다.
var
DLLApp: TApplication;
그런 다음 Application 개체의 값을 변경하고 자식 폼을 만드는 프로시저를 만듭니다.
절차는 다음과 같을 수 있습니다.

프로시저 ShowMDIChild(MainApp: TApplication) ;

자식: TMDIChild;

시작하다

할당되지 않은 경우(DllApp) 시작

DLLApp:= 응용 프로그램;

응용 프로그램:= MainApp;

끝 ;

자식:= TMDIChild.Create(Application.MainForm) ;

차일드.쇼 ;

끝 ;

이제 Application 객체의 값을 반환하기만 하면 됩니다.
원래 상태로. MyDllProc 프로시저를 사용하여 이 작업을 수행합니다.

프로시저 MyDLLProc(이유: 정수) ;

시작하다

이유 = DLL_PROCESS_DETACH이면

(DLL 언로드 중. 애플리케이션 포인터 값 복원)

할당된 경우(DllApp) 다음

응용 프로그램:= DLLApp;

끝 ;

결론 대신.
동적 링크 라이브러리를 사용하는 것은 언뜻 보기에 그리 어렵지 않습니다.

동적 링크 라이브러리를 사용하는 것은 언뜻 보기에 그리 어렵지 않습니다.
DLL은 응용 프로그램의 성능을 최적화할 수 있는 가장 광범위한 가능성을 제공하며,
뿐만 아니라 프로그래머 자신의 작업. DLL을 사용하면 인생이 더 쉬워질 것입니다!
http://subscribe.ru/
이메일: [이메일 보호됨]검색
Subscribe.Ru에서 APORT로

Delphi에서 DLL 생성 및 사용에 대해 알려주는 요청이 포함된 편지를 한 번 이상 받아야 했습니다. 이 기사에서 우리는 모든 것을 다루고 우리 자신의 라이브러리를 만들 것입니다. 동적으로 연결된 라이브러리(Dinamic Link Library)를 사용하면 서로 다른 응용 프로그램이 작업에서 공통 리소스 집합을 사용할 수 있습니다. 중요한 것은 DLL에 있는 프로시저와 함수가 그것을 사용하는 프로세스 내에서 실행된다는 것입니다. DLL을 호출하는 각 응용 프로그램에 대해 별도의 복사본을 실행하는 루틴과 달리 DLL은 이를 요청하는 모든 응용 프로그램에서 공유하는 단일 리소스 복사본을 모든 응용 프로그램에 제공합니다. 또한 DLL과 서브루틴의 차이점에는 DLL이 프로시저와 함수만 내보낼 수 있고 형식, 상수 등은 내보낼 수 없다는 사실이 포함될 수 있습니다.

메모리에 있는 DLL의 구조에 대한 "Lessons on Delphi"에서 발췌한 내용을 제공하고 싶습니다.

DLL은 응용 프로그램과 달리 라이브러리이며 스택이나 메시지 큐가 없습니다. DLL에 배치된 함수는 스택을 사용하여 호출 응용 프로그램의 컨텍스트에서 실행됩니다. 그러나 이러한 동일한 기능은 응용 프로그램의 복사본이 아니라 라이브러리의 데이터 세그먼트를 사용합니다. DLL의 이러한 구성으로 인해 실행 중인 모든 응용 프로그램이 해당 모듈에 특정 표준 기능을 포함하지 않고 하나의 DLL 모듈을 사용하기 때문에 메모리가 절약됩니다. 종종 DLL의 형태로 별도의 기능 세트가 생성되어 하나 또는 다른 논리적 기능에 따라 결합됩니다. 이는 Pascal에서 모듈이 개념적으로(단위의 의미에서) 계획되는 방식과 유사합니다. 차이점은 Pascal 모듈의 기능은 연결 단계에서 정적으로 연결되고 DLL의 기능은 런타임에 동적으로 연결된다는 것입니다.

DLL 생성

DLL의 구조는 오브젝트 파스칼의 일반적인 모듈 구조와 크게 다르지 않습니다. DLL은 라이브러리라는 단어로 시작하고 그 뒤에 라이브러리 이름이 와야 합니다. DLL이 다른 사용자에게 제공(내보내기)할 기능과 절차는 내보내기 지시문 뒤에 나열됩니다.

각 프로시저 또는 함수에 대해 Index 지시문을 사용하여 해당 번호를 지정할 수 있습니다. 숫자가 없으면 컴파일러가 자동 인덱싱을 수행합니다. 프로시저 번호 대신 name 지시문을 사용하여 지정되는 고유한 이름을 사용할 수 있습니다. 함수의 이름과 번호가 지정되지 않은 경우 Delphi는 이를 함수 이름과 일치하는 이름별 내보내기로 인식합니다.

라이브러리는 로드될 때 실행될 초기화 코드를 포함할 수도 있습니다. 시작과 끝 사이에 배치됩니다. DLL의 일반적인 구조는 다음과 같습니다.

LibraryFirst_Dll; 용도<используемые модули>; <объявления и описания функций>수출<экспортируемые функции> <описание процедур и функций>시작하다<инициализационная часть>끝.

내보내기 섹션에서 내보낸 기능에 대한 설명의 예를 제공합니다.

Function1 인덱스 2를 내보냅니다. Function2 이름 "My_sqr"; 기능3;

짐작하셨겠지만 함수 이름이 내보내기 이름과 일치하지 않을 수 있습니다!!!

DLL 사용

DLL의 프로시저와 함수를 사용해야 하는 모듈은 외부 지시문을 사용해야 합니다. DLL(동적 및 정적)을 사용하는 두 가지 방법이 있습니다. 첫 번째 경우 DLL에서 함수를 호출하는 응용 프로그램은 라이브러리의 이름과 진입점을 알고 있으며 라이브러리가 변경되지 않는다고 가정합니다. 두 번째 경우 DLL을 사용하기 전에 필요한 라이브러리가 존재하고 필요한 서브루틴이 포함되어 있는지 확인해야 합니다.

이름과 번호로 서브루틴을 가져올 수 있습니다. 번호로 서브루틴을 검색하는 것이 더 빠르지만 항상 편리합니다.

다음은 예제에서 다룬 First_DLL에서 함수를 가져오는 예제입니다.

(지정된 이름으로 가져오기) 함수 ImportByName; 외부 "First_DLL" 이름 "My_sqr"; (인덱스로 가져오기) 함수 ImportByOrdinal; 외부 "First_DLL" 인덱스 2; (원래 이름으로 가져오기) 기능 Function3; 외부 "First_DLL";

DLL을 사용하는 정적 방법을 살펴보았습니다. 그러나 어떤 경우에는 어떤 라이브러리가 필요한지 미리 알 수 없으므로 동적 방법을 사용해야 합니다.

WinTypes, WinProcs, ... 사용 ; 유형 TMyProc = 절차 ; var 핸들: THandle; MyImportProc: TMyProc; 핸들 시작:=LoadLibrary("FirstDLL"); 핸들>=32인 경우(인 경우<=32 - ошибка! } begin @MyImportProc:=GetProcAddress(Handle,"My_sqr"); if MyImportProc<>nil then ...... (여기서 결과 함수를 사용합니다) end; FreeLibrary(핸들); 끝;

그러나 제 생각에는 여기에 쓰여진 모든 것이 명확하지 않으며 실제 완성된 예를 원합니다. 기사에 예제가 거의 없고 이론이 하나만 있을 때 항상 좌절감을 느꼈습니다. 그래서 DLL을 사용하는 간단한 예제를 알려드립니다.

메뉴 파일 -> 새로 만들기를 클릭하고 DLL을 선택합니다. Project1.dpr이라는 이름으로 제안된 대로 완성된 템플릿을 저장합니다.

다음은 전체 코드입니다.

라이브러리 프로젝트1; SysUtils, 클래스를 사용합니다. 함수 Function1(x,y:정수):정수; 내보내다; bginresult:=x+y; 끝; 함수 Function2(x,y:실제):실제; 내보내다; 바트:진짜; 시작 t:=exp(y*ln(x)); 결과:=t; 끝; Function1 인덱스 1, Function2 이름 "My_sqr"을 내보냅니다. 시작 끝.

여기에는 두 가지 함수가 있습니다. 첫 번째는 두 숫자의 합을 계산하고 숫자로 내보내고, 두 번째는 x를 y의 거듭제곱으로 계산하고 이름으로 내보냅니다.

이제 새 프로젝트를 만들고 DemoDLL과 같은 다른 이름으로 저장해 보겠습니다. 폼에 두 개의 버튼을 배치해 보겠습니다. 첫 번째 버튼을 클릭하면 첫 번째 프로시저를 호출하고 두 번째 버튼을 클릭하면 두 번째 프로시저를 호출합니다. 이 데모 프로젝트의 전체 코드는 다음과 같습니다.

유닛 데모; 인터페이스는 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls를 사용합니다. 유형 TForm1 = 클래스(TForm) Button1: TButton; 버튼2: T버튼; 절차 Button1Click(보낸 사람: TObject); 절차 Button2Click(보낸 사람: TObject); private ( Private 선언 ) public ( Public 선언 ) end; var Form1: TForm1; 구현($R *.DFM) 함수 ImportSumm(x,y:integer):integer; 외부 "Project1" 인덱스 1; // 숫자로 가져오기 function ImportSqr(x,y:real):real; 외부 "Project1" 이름 "My_sqr"; //이름으로 가져오기 프로시저 TForm1.Button1Click(Sender: TObject); 바트:진짜; begin //2의 3승이 얼마인지 알아냅니다. t:=ImportSqr(2,3); Showmessage(FloatTostr(t)); 끝; 절차 TForm1.Button2Click(발신자: TObject); vart:정수; begin //10+10이 얼마인지 알아내십시오 t:=ImportSumm(10,10); Showmessage(IntTostr(t)); 끝; 끝.

델파이 프로그래머, MySQL. 고등 교육. 특기: 정보 기술 소프트웨어.