DLL-퀵 가이드

동적 연결은 런타임에 응용 프로그램을 라이브러리에 연결하는 메커니즘입니다. 라이브러리는 자체 파일에 남아 있으며 응용 프로그램의 실행 파일에 복사되지 않습니다. DLL은 응용 프로그램이 만들어 질 때가 아니라 실행될 때 응용 프로그램에 연결됩니다. DLL은 다른 DLL에 대한 링크를 포함 할 수 있습니다.

많은 경우 DLL은 .EXE, .DRV 또는 .DLL과 같은 다른 확장자를 가진 파일에 배치됩니다.

DLL의 장점

다음은 DLL 파일을 갖는 몇 가지 장점입니다.

더 적은 리소스 사용

DLL 파일은 메인 프로그램과 함께 RAM에로드되지 않습니다. 그들은 필요하지 않는 한 공간을 차지하지 않습니다. DLL 파일이 필요할 때로드되고 실행됩니다. 예를 들어, Microsoft Word 사용자가 문서를 편집하는 한 RAM에 프린터 DLL 파일이 필요하지 않습니다. 사용자가 문서를 인쇄하기로 결정하면 Word 응용 프로그램에서 프린터 DLL 파일을로드하고 실행합니다.

모듈 식 아키텍처 촉진

DLL은 모듈 식 프로그램 개발을 촉진하는 데 도움이됩니다. 여러 언어 버전이 필요한 대형 프로그램이나 모듈 식 아키텍처가 필요한 프로그램을 개발하는 데 도움이됩니다. 모듈 식 프로그램의 예로는 런타임에 동적으로로드 할 수있는 많은 모듈이있는 회계 프로그램이 있습니다.

간편한 배포 및 설치 지원

DLL 내의 함수에 업데이트 또는 수정이 필요한 경우 DLL의 배포 및 설치는 프로그램을 DLL과 다시 연결할 필요가 없습니다. 또한 여러 프로그램이 동일한 DLL을 사용하는 경우 모든 프로그램이 업데이트 또는 수정의 혜택을받습니다. 이 문제는 정기적으로 업데이트되거나 수정되는 타사 DLL을 사용할 때 더 자주 발생할 수 있습니다.

DLL 연결이 컴파일의 일부로 모듈 정의 파일의 IMPORTS 섹션에 지정된 경우 응용 프로그램과 DLL은 다른 DLL에 자동으로 연결할 수 있습니다. 그렇지 않으면 Windows LoadLibrary 함수를 사용하여 명시 적으로로드 할 수 있습니다.

중요한 DLL 파일

  • COMDLG32.DLL -대화 상자를 제어합니다.

  • GDI32.DLL -그래픽 그리기, 텍스트 표시 및 글꼴 관리를위한 다양한 기능이 포함되어 있습니다.

  • KERNEL32.DLL -메모리 및 다양한 프로세스 관리를위한 수백 가지 기능을 포함합니다.

  • USER32.DLL-다양한 사용자 인터페이스 기능이 포함되어 있습니다. 프로그램 창 생성 및 서로 간의 상호 작용에 관여합니다.

먼저 사용자 고유의 DLL을 개발할 때 고려해야하는 문제와 요구 사항에 대해 논의합니다.

DLL 유형

응용 프로그램에서 DLL을로드 할 때 두 가지 연결 방법을 사용하여 내 보낸 DLL 함수를 호출 할 수 있습니다. 두 가지 연결 방법은 다음과 같습니다.

  • 로드 시간 동적 연결 및
  • 런타임 동적 연결.

로드 시간 동적 연결

로드 시간 동적 연결에서 응용 프로그램은 로컬 함수와 같이 내 보낸 DLL 함수를 명시 적으로 호출합니다. 로드 시간 동적 링크를 사용하려면 애플리케이션을 컴파일하고 링크 할 때 헤더 (.h) 파일과 가져 오기 라이브러리 (.lib) 파일을 제공하십시오. 이렇게하면 링커가 DLL을로드하고로드시 내 보낸 DLL 함수 위치를 확인하는 데 필요한 정보를 시스템에 제공합니다.

런타임 동적 연결

런타임 동적 연결에서 응용 프로그램은 LoadLibrary 함수 또는 LoadLibraryEx 함수를 호출하여 런타임에 DLL을로드합니다. DLL이 성공적으로로드되면 GetProcAddress 함수를 사용하여 호출 할 내 보낸 DLL 함수의 주소를 가져옵니다. 런타임 동적 링크를 사용하는 경우 가져 오기 라이브러리 파일이 필요하지 않습니다.

다음 목록은로드 시간 동적 연결과 런타임 동적 연결 중에서 선택하기위한 응용 프로그램 기준을 설명합니다.

  • Startup performance : 응용 프로그램의 초기 시작 성능이 중요한 경우 런타임 동적 연결을 사용해야합니다.

  • Ease of use:로드 시간 동적 링크에서 내 보낸 DLL 함수는 로컬 함수와 같습니다. 이러한 함수를 쉽게 호출 할 수 있습니다.

  • Application logic: 런타임 동적 링크에서 애플리케이션은 필요에 따라 다른 모듈을로드하도록 분기 할 수 있습니다. 이것은 다국어 버전을 개발할 때 중요합니다.

DLL 진입 점

DLL을 만들 때 선택적으로 진입 점 함수를 지정할 수 있습니다. 진입 점 함수는 프로세스 또는 스레드가 자신을 DLL에 연결하거나 DLL에서 분리 할 때 호출됩니다. 진입 점 함수를 사용하여 DLL에 필요한 데이터 구조를 초기화하거나 삭제할 수 있습니다.

또한 응용 프로그램이 다중 스레드 인 경우 TLS (스레드 로컬 저장소)를 사용하여 진입 점 함수의 각 스레드에 개인용 메모리를 할당 할 수 있습니다. 다음 코드는 DLL 진입 점 함수의 예입니다.

BOOL APIENTRY DllMain(
HANDLE hModule,	// Handle to DLL module DWORD ul_reason_for_call, LPVOID lpReserved )  // Reserved
{
   switch ( ul_reason_for_call )
   {
      case DLL_PROCESS_ATTACHED:
      // A process is loading the DLL.
      break;
      case DLL_THREAD_ATTACHED:
      // A process is creating a new thread.
      break;
      case DLL_THREAD_DETACH:
      // A thread exits normally.
      break;
      case DLL_PROCESS_DETACH:
      // A process unloads the DLL.
      break;
   }
   return TRUE;
}

진입 점 함수가 FALSE 값을 반환하면로드 시간 동적 연결을 사용하는 경우 응용 프로그램이 시작되지 않습니다. 런타임 동적 연결을 사용하는 경우 개별 DLL 만로드되지 않습니다.

진입 점 함수는 간단한 초기화 작업 만 수행해야하며 다른 DLL로드 또는 종료 함수를 호출해서는 안됩니다. 예를 들어 진입 점 함수에서 직접 또는 간접적으로LoadLibrary 기능 또는 LoadLibraryEx함수. 또한FreeLibrary 프로세스가 종료 될 때 기능.

WARNING: 다중 스레드 응용 프로그램에서 DLL 전역 데이터에 대한 액세스가 동기화되어 (스레드 안전) 데이터 손상 가능성을 방지해야합니다. 이렇게하려면 TLS를 사용하여 각 스레드에 고유 한 데이터를 제공하십시오.

DLL 함수 내보내기

DLL 함수를 내보내려면 내 보낸 DLL 함수에 함수 키워드를 추가하거나 내 보낸 DLL 함수를 나열하는 모듈 정의 (.def) 파일을 만들 수 있습니다.

함수 키워드를 사용하려면 내보낼 각 함수를 다음 키워드로 선언해야합니다.

__declspec(dllexport)

응용 프로그램에서 내 보낸 DLL 함수를 사용하려면 다음 키워드를 사용하여 가져올 각 함수를 선언해야합니다.

__declspec(dllimport)

일반적으로 하나의 헤더 파일을 사용합니다. define 진술 및 ifdef 문을 사용하여 export 문과 import 문을 구분합니다.

모듈 정의 파일을 사용하여 내 보낸 DLL 함수를 선언 할 수도 있습니다. 모듈 정의 파일을 사용할 때 내 보낸 DLL 함수에 function 키워드를 추가 할 필요가 없습니다. 모듈 정의 파일에서LIBRARY 진술 및 EXPORTSDLL에 대한 문. 다음 코드는 정의 파일의 예입니다.

// SampleDLL.def
//
LIBRARY "sampleDLL"

EXPORTS
   HelloWorld

샘플 DLL 작성

Microsoft Visual C ++ 6.0에서는 다음 중 하나를 선택하여 DLL을 만들 수 있습니다. Win32 Dynamic-Link Library 프로젝트 유형 또는 MFC AppWizard (dll) 프로젝트 유형.

다음 코드는 Win32 동적 연결 라이브러리 프로젝트 형식을 사용하여 Visual C ++에서 만든 DLL의 예입니다.

// SampleDLL.cpp

#include "stdafx.h"
#define EXPORTING_DLL
#include "sampleDLL.h"

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved )
{
   return TRUE;
}

void HelloWorld()
{
   MessageBox( NULL, TEXT("Hello World"), 
   TEXT("In a DLL"), MB_OK);
}
// File: SampleDLL.h
//
#ifndef INDLL_H
#define INDLL_H

#ifdef EXPORTING_DLL
extern __declspec(dllexport) void HelloWorld() ;
#else
extern __declspec(dllimport) void HelloWorld() ;
#endif

#endif

샘플 DLL 호출

다음 코드는 SampleDLL DLL에서 내 보낸 DLL 함수를 호출하는 Win32 응용 프로그램 프로젝트의 예입니다.

// SampleApp.cpp 

#include "stdafx.h"
#include "sampleDLL.h"

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine,  int       nCmdShow)
{ 	
   HelloWorld();
   return 0;
}

NOTE :로드 시간 동적 연결에서는 SampleDLL 프로젝트를 빌드 할 때 생성되는 SampleDLL.lib 가져 오기 라이브러리를 연결해야합니다.

런타임 동적 연결에서는 다음 코드와 유사한 코드를 사용하여 SampleDLL.dll에서 내 보낸 DLL 함수를 호출합니다.

...
typedef VOID (*DLLPROC) (LPTSTR);
...
HINSTANCE hinstDLL;
DLLPROC HelloWorld;
BOOL fFreeDLL;

hinstDLL = LoadLibrary("sampleDLL.dll");
if (hinstDLL != NULL)
{
   HelloWorld = (DLLPROC) GetProcAddress(hinstDLL, "HelloWorld");
	
   if (HelloWorld != NULL)
   (HelloWorld);

   fFreeDLL = FreeLibrary(hinstDLL);
}
...

SampleDLL 응용 프로그램을 컴파일하고 연결할 때 Windows 운영 체제는 다음 위치에서이 순서대로 SampleDLL DLL을 검색합니다.

  • 응용 프로그램 폴더

  • 현재 폴더

  • Windows 시스템 폴더 ( GetSystemDirectory 함수는 Windows 시스템 폴더의 경로를 반환합니다).

  • Windows 폴더 ( GetWindowsDirectory 함수는 Windows 폴더의 경로를 반환합니다.)

DLL을 사용하려면 레지스트리에 적절한 참조를 입력하여 등록해야합니다. 때때로 레지스트리 참조가 손상되어 DLL의 기능을 더 이상 사용할 수없는 경우가 있습니다. 시작-실행을 열고 다음 명령을 입력하여 DLL을 다시 등록 할 수 있습니다.

regsvr32 somefile.dll

이 명령은 somefile.dll이 PATH에있는 디렉터리 또는 폴더에 있다고 가정합니다. 그렇지 않으면 DLL의 전체 경로를 사용해야합니다. 아래 그림과 같이 "/ u"스위치를 사용하여 DLL 파일을 등록 해제 할 수도 있습니다.

regsvr32 /u somefile.dll

이것은 서비스를 켜고 끄는 데 사용할 수 있습니다.

DLL 문제를 해결하는 데 도움이되는 여러 도구를 사용할 수 있습니다. 그들 중 일부는 아래에서 설명합니다.

종속성 워커

종속성 워커 도구 (depends.exe)는 프로그램에서 사용하는 모든 종속 DLL을 재귀 적으로 검색 할 수 있습니다. Dependency Walker에서 프로그램을 열면 Dependency Walker는 다음 검사를 수행합니다.

  • 누락 된 DLL을 확인합니다.
  • 유효하지 않은 프로그램 파일 또는 DLL을 확인합니다.
  • 가져 오기 기능과 내보내기 기능이 일치하는지 확인합니다.
  • 순환 종속성 오류를 확인합니다.
  • 모듈이 다른 운영 체제 용이므로 유효하지 않은 모듈을 확인합니다.

Dependency Walker를 사용하면 프로그램이 사용하는 모든 DLL을 문서화 할 수 있습니다. 향후 발생할 수있는 DLL 문제를 방지하고 수정하는 데 도움이 될 수 있습니다. Dependency Walker는 Microsoft Visual Studio 6.0을 설치할 때 다음 디렉터리에 있습니다.

drive\Program Files\Microsoft Visual Studio\Common\Tools

DLL 범용 문제 해결사

DLL Universal Problem Solver (DUPS) 도구는 DLL 정보를 감사, 비교, 문서화 및 표시하는 데 사용됩니다. 다음 목록은 DUPS 도구를 구성하는 유틸리티를 설명합니다.

  • Dlister.exe -이 유틸리티는 컴퓨터의 모든 DLL을 열거하고 정보를 텍스트 파일이나 데이터베이스 파일에 기록합니다.

  • Dcomp.exe -이 유틸리티는 두 개의 텍스트 파일에 나열된 DLL을 비교하고 차이점이 포함 된 세 번째 텍스트 파일을 생성합니다.

  • Dtxt2DB.exe -이 유틸리티는 Dlister.exe 유틸리티와 Dcomp.exe 유틸리티를 사용하여 만든 텍스트 파일을 dllHell 데이터베이스에로드합니다.

  • DlgDtxt2DB.exe -이 유틸리티는 Dtxt2DB.exe 유틸리티의 그래픽 사용자 인터페이스 (GUI) 버전을 제공합니다.

DLL을 작성하는 동안 다음 팁을 염두에 두십시오.

  • 적절한 호출 규칙 (C 또는 stdcall)을 사용하십시오.

  • 함수에 전달 된 인수의 올바른 순서를 알고 있어야합니다.

  • 함수에 직접 전달 된 인수를 사용하여 배열의 크기를 조정하거나 문자열을 연결하지 마십시오. 전달하는 매개 변수는 LabVIEW 데이터라는 것을 기억하십시오. 배열 또는 문자열 크기를 변경하면 LabVIEW 메모리에 저장된 다른 데이터를 덮어 쓰면 충돌이 발생할 수 있습니다. LabVIEW Array Handle 또는 LabVIEW String Handle을 전달하고 Visual C ++ 컴파일러 또는 Symantec 컴파일러를 사용하여 DLL을 컴파일하는 경우 배열의 크기를 조정하거나 문자열을 연결할 수 있습니다.

  • 문자열을 함수에 전달하는 동안 전달할 올바른 유형의 문자열을 선택하십시오. C 또는 Pascal 또는 LabVIEW 문자열 핸들.

  • 파스칼 문자열의 길이는 255 자로 제한됩니다.

  • C 문자열은 NULL로 종료됩니다. DLL 함수가 이진 문자열 형식으로 숫자 데이터를 반환하는 경우 (예 : GPIB 또는 직렬 포트를 통해) 데이터 문자열의 일부로 NULL 값을 반환 할 수 있습니다. 이러한 경우 짧은 (8 비트) 정수 배열을 전달하는 것이 가장 안정적입니다.

  • 데이터의 배열 또는 문자열로 작업하는 경우, LabVIEW 핸들로 전달하지 않는 한 항상 함수가 버퍼에 배치 한 모든 결과를 보유 할 수있을만큼 큰 버퍼 또는 배열을 전달합니다.이 경우 CIN을 사용하여 크기를 조정할 수 있습니다. Visual C ++ 또는 Symantec 컴파일러의 기능.

  • _stdcall을 사용하는 경우 모듈 정의 파일의 EXPORTS 섹션에 DLL 함수를 나열하십시오.

  • 다른 응용 프로그램이 모듈 정의 파일 EXPORTS 섹션에서 호출하는 DLL 함수를 나열하거나 함수 선언에 _declspec (dllexport) 키워드를 포함합니다.

  • C ++ 컴파일러를 사용하는 경우 헤더 파일에 extern .C. {} 문을 사용하여 함수를 내 보내어 이름 변경을 방지합니다.

  • 고유 한 DLL을 작성하는 경우 다른 응용 프로그램에서 DLL을 메모리로로드하는 동안 DLL을 다시 컴파일해서는 안됩니다. DLL을 다시 컴파일하기 전에 특정 DLL을 사용하는 모든 응용 프로그램이 메모리에서 언로드되었는지 확인하십시오. DLL 자체가 메모리에로드되지 않도록합니다. 이것을 잊어 버리고 컴파일러가 경고하지 않으면 올바르게 다시 빌드하지 못할 수 있습니다.

  • 다른 프로그램으로 DLL을 테스트하여 함수 (및 DLL)가 올바르게 작동하는지 확인합니다. 컴파일러의 디버거 또는 DLL에서 함수를 호출 할 수있는 간단한 C 프로그램으로 테스트하면 가능한 문제가 DLL에 내재되어 있는지 또는 관련 LabVIEW와 관련된 것인지 식별하는 데 도움이됩니다.

DLL을 작성하는 방법과 "Hello World"프로그램을 만드는 방법을 살펴 보았습니다. 이 예제는 DLL을 만드는 기본 개념에 대한 아이디어를 제공했을 것입니다.

여기에서는 Delphi, Borland C ++ 및 다시 VC ++를 사용하여 DLL을 만드는 방법에 대해 설명합니다.

이러한 예를 하나씩 살펴 보겠습니다.

  • Delphi 내에서 DLL을 작성하고 호출하는 방법

  • Borland C ++ Builder IDE에서 DLL 만들기

  • Microsoft Visual C ++ 6.0에서 DLL 만들기