다음을 통해 공유


안내서: 고유한 동적 연결 라이브러리 만들기 및 사용하기(C++)

이 단계별 연습에서는 Visual Studio IDE를 사용하여 MSVC(Microsoft C++)로 작성된 고유한 DLL(동적 연결 라이브러리)을 만드는 방법과 다른 C++ 앱에서 DLL을 사용하는 방법을 설명합니다. UNIX 기반 운영 체제에서 공유 라이브러리 라고도 하는 DLL은 가장 유용한 종류의 Windows 구성 요소 중 하나입니다. 이를 사용하여 코드와 리소스를 공유하고 앱 크기를 줄일 수 있습니다. DLL을 사용하면 앱을 더 쉽게 서비스하고 확장할 수 있습니다.

이 연습에서는 일부 수학 함수를 구현하는 DLL을 만듭니다. 그런 다음 DLL의 함수를 사용하는 콘솔 앱을 만듭니다. 또한 Windows DLL에 사용되는 프로그래밍 기술 및 규칙 중 일부를 소개합니다.

이 안내서에서는 다음 단계를 설명합니다.

  • Visual Studio에서 DLL 프로젝트를 만듭니다.
  • 내보낸 함수 및 변수를 DLL에 추가합니다.
  • Visual Studio에서 콘솔 앱 프로젝트를 만듭니다.
  • 콘솔 앱의 DLL에서 가져온 함수 및 변수를 사용합니다.
  • 완료된 앱을 실행합니다.

정적으로 연결된 라이브러리와 마찬가지로 DLL은 변수, 함수 및 리소스를 이름으로 내보 냅니다. 클라이언트 앱은 해당 변수, 함수 및 리소스를 사용하기 위해 이름을 가져옵니다 . 정적으로 연결된 라이브러리와 달리 Windows는 가져오기를 링크 시 연결하는 대신 로드 시 또는 런타임에 앱의 가져오기를 DLL의 내보내기로 연결합니다. Windows에서는 이러한 연결을 위해 표준 C++ 컴파일 모델에 속하지 않는 추가 정보가 필요합니다. MSVC 컴파일러는 이 추가 정보를 제공하기 위해 C++에 대한 일부 Microsoft 관련 확장을 구현합니다. 진행하면서 이러한 확장에 대해 설명합니다.

이 연습에서는 DLL을 빌드하는 솔루션과 클라이언트 앱을 빌드하는 두 가지 Visual Studio 솔루션을 만듭니다. DLL은 C 호출 규칙을 사용합니다. 플랫폼, 호출 규칙 및 연결 규칙이 일치하는 한 다른 프로그래밍 언어로 작성된 앱에서 호출할 수 있습니다. 클라이언트 앱은 암시적 연결을 사용합니다. 여기서 Windows는 로드 시 앱을 DLL에 연결합니다. 이 연결을 통해 앱은 정적으로 연결된 라이브러리의 함수와 마찬가지로 DLL 제공 함수를 호출할 수 있습니다.

이 단계별 설명에서는 몇 가지 일반적인 상황을 다루지 않습니다. 코드는 다른 프로그래밍 언어에서 C++ DLL을 사용하는 것을 표시하지 않습니다. 리소스 전용 DLL을 만드는 방법이나 명시적 연결을 사용하여 로드 시가 아닌 런타임에 DLL을 로드하는 방법은 표시되지 않습니다. MSVC 및 Visual Studio를 사용하여 이러한 모든 작업을 수행할 수 있습니다.

DLL 코드가 C++로 작성되더라도 내보낸 함수에 C 스타일 인터페이스를 사용합니다. 두 가지 주요 이유가 있습니다. 첫째, 다른 많은 언어는 C 스타일 함수 가져오기를 지원합니다. 클라이언트 앱은 C++로 작성할 필요가 없습니다. 둘째, 내보낸 클래스 및 멤버 함수와 관련된 몇 가지 일반적인 문제를 방지합니다. 클래스 선언 내에서 참조되는 모든 항목에는 내보내는 인스턴스화도 있어야 하므로 클래스를 내보낼 때 쉽게 진단하기 어려운 오류를 만들 수 있습니다. 이 제한은 DLL에 적용되지만 정적 라이브러리에는 적용되지 않습니다. 클래스가 일반 오래된 데이터 스타일인 경우 이 문제가 발생해서는 안 됩니다.

DLL에 대한 자세한 내용은 Visual Studio에서 C/C++ DLL 만들기를 참조하세요. 암시적 연결 및 명시적 연결에 대한 자세한 내용은 사용할 연결 방법 결정(Determine)을 참조하세요. C 언어 연결 규칙을 사용하는 프로그래밍 언어에 사용할 C++ DLL을 만드는 방법에 대한 자세한 내용은 C-언어 실행 파일에서 사용할 C++ 함수 내보내기(Exporting C++ Functions)를 참조하세요. .NET 언어와 함께 사용할 DLL을 만드는 방법에 대한 자세한 내용은 Visual Basic 애플리케이션에서 DLL 함수 호출을 참조하세요.

필수 조건

  • Microsoft Windows 7 이상. 최상의 개발 환경을 위해 최신 버전의 Windows를 사용하는 것이 좋습니다.
  • 비주얼 스튜디오. Visual Studio를 다운로드하고 설치하는 방법을 알아보려면 Visual Studio 설치를 참조하세요. 설치 관리자를 실행할 때 C++ 워크로드를 사용한 데스크톱 개발이 선택되어 있는지 확인합니다. Visual Studio를 설치할 때 이 워크로드를 설치하지 않은 경우 걱정하지 마세요. 설치 관리자를 다시 실행하고 지금 설치할 수 있습니다.

    C++ 워크로드를 사용한 Visual Studio 설치 관리자, 데스크톱 개발의 스크린샷.

  • 비주얼 스튜디오. Visual Studio 2015를 다운로드하고 설치하는 방법에 대한 자세한 내용은 Visual Studio 2015 설치를 참조하세요. 기본적으로 설치되지 않으므로 사용자 지정 설치를 사용하여 C++ 컴파일러 및 도구를 설치합니다.
  • Visual Studio IDE 사용의 기본 사항을 이해합니다. 이전에 Windows 데스크톱 앱을 사용한 적이 있다면 계속 작업할 수 있습니다. 소개는 Visual Studio IDE 기능 둘러보기를 참조하세요.

  • C++ 언어에 대해 잘 알고 있습니다. 걱정하지 마세요, 우리는 너무 복잡한 아무것도하지 않습니다.

비고

이 연습에서는 Visual Studio 2017 버전 15.9 이상을 사용 중이라고 가정합니다. 일부 이전 버전의 Visual Studio 2017에는 코드 템플릿에 결함이 있거나 다른 사용자 인터페이스 대화 상자가 사용되었습니다. 문제를 방지하려면 Visual Studio 설치 관리자를 사용하여 Visual Studio 2017을 버전 15.9 이상으로 업데이트합니다.

DLL 프로젝트 만들기

다음 작업 집합에서는 DLL에 대한 프로젝트를 만들고 코드를 추가하고 빌드합니다. 시작하려면 Visual Studio IDE를 시작하고 필요한 경우 로그인합니다. 지침은 사용 중인 Visual Studio 버전에 따라 약간 다릅니다. 선호하는 버전의 Visual Studio에 대한 단계를 보려면 이 페이지의 목차 맨 위에 있는 버전 선택기를 사용합니다.

Visual Studio에서 DLL 프로젝트를 만들려면

  1. 메뉴 모음에서 파일>새로 만들기>프로젝트를 선택하여 새 프로젝트 만들기 대화 상자를 엽니다.

    동적 링크 라이브러리 템플릿이 강조 표시된 새 프로젝트 만들기 대화 상자의 스크린샷

  2. 대화 상자 맨 위에서 언어C++로 설정하고 , 플랫폼을Windows로 설정하고, 프로젝트 형식라이브러리로 설정합니다.

  3. 필터링된 프로젝트 형식 목록에서 DLL(동적 연결 라이브러리)을 선택한 다음, 다음을 선택합니다.

  4. 새 프로젝트 구성 페이지의 프로젝트 이름 상자에 MathLibrary를 입력하여 프로젝트의 이름을 지정합니다. 기본 위치솔루션 이름 값을 그대로 둡니다. 솔루션을 설정하여 새 솔루션을 만듭니다. 솔루션 및 프로젝트를 동일한 디렉터리에 배치가 선택되어 있다면 선택을 취소하십시오.

  5. 만들기 단추를 선택하여 프로젝트를 만듭니다.

솔루션을 만들면 Visual Studio의 솔루션 탐색기 창에서 생성된 프로젝트 및 원본 파일을 볼 수 있습니다.

MathLibrary 프로젝트가 강조 표시된 솔루션 탐색기 창의 스크린샷.

Visual Studio 2017에서 DLL 프로젝트를 만들려면

  1. 메뉴 모음에서 파일>새로 만들기>프로젝트를 선택하여 새 프로젝트 대화 상자를 엽니다.

  2. 새 프로젝트 대화 상자의 왼쪽 창에서 설치된Visual C++>Windows 데스크톱> 선택합니다. 가운데 창에서 DLL(Dynamic-Link 라이브러리)을 선택합니다. 이름 상자에 MathLibrary를 입력하여 프로젝트의 이름을 지정합니다. 기본 위치솔루션 이름 값을 그대로 둡니다. 솔루션을 설정하여 새 솔루션을 만듭니다. 체크되어 있지 않으면 솔루션에 대한 디렉터리 만들기를 선택하십시오.

    이름 텍스트 상자의 수학 라이브러리를 보여 주는 Visual Studio 2017의 새 프로젝트 대화 상자 스크린샷

  3. 확인 단추를 선택하여 프로젝트를 만듭니다.

솔루션을 만들면 Visual Studio의 솔루션 탐색기 창에서 생성된 프로젝트 및 원본 파일을 볼 수 있습니다.

수학 라이브러리가 강조 표시된 Visual Studio 2017의 솔루션 탐색기 창 스크린샷

Visual Studio 2015 및 이전 버전에서 DLL 프로젝트를 만들려면

  1. 메뉴 모음에서 파일>새로 만들기>프로젝트를 선택합니다.

  2. 새 프로젝트 대화 상자의 왼쪽 창에서 설치된템플릿> 확장하고 Visual C++를 선택한 다음 가운데 창에서 Win32 콘솔 애플리케이션을 선택합니다. 이름 편집 상자에 MathLibrary를 입력하여 프로젝트의 이름을 지정합니다. 기본 위치솔루션 이름 값을 그대로 둡니다. 솔루션을 설정하여 새 솔루션을 만듭니다. 체크되어 있지 않으면 솔루션에 대한 디렉터리 만들기를 선택하십시오.

    이름 텍스트 상자에서 MathLibrary를 보여 주는 Visual Studio 2015의 새 프로젝트 대화 상자 스크린샷

  3. 확인 단추를 선택하여 새 프로젝트 대화 상자를 해제하고 Win32 애플리케이션 마법사를 시작합니다.

    Win32 애플리케이션 마법사 개요 페이지의 스크린샷.

  4. 다음 단추를 선택합니다. 애플리케이션 설정 페이지의 애플리케이션 유형에서 DLL을 선택합니다.

    Win32 애플리케이션 마법사 애플리케이션 설정 페이지의 스크린샷.

  5. 마침 단추를 선택하여 프로젝트를 만듭니다.

마법사가 솔루션을 완료하면 Visual Studio의 솔루션 탐색기 창에서 생성된 프로젝트 및 원본 파일을 볼 수 있습니다.

MathLibrary가 강조 표시된 Visual Studio 2015의 솔루션 탐색기 창 스크린샷

현재 이 DLL은 별로 작동하지 않습니다. 다음으로, DLL에서 내보내는 함수를 선언하는 헤더 파일을 만든 다음 DLL에 함수 정의를 추가하여 더 유용하게 만듭니다.

DLL에 헤더 파일을 추가하려면

  1. 함수에 대한 헤더 파일을 만들려면 메뉴 모음에서 프로젝트>새 항목 추가를 선택합니다.

  2. 새 항목 추가 대화 상자의 왼쪽 창에서 Visual C++를 선택합니다. 가운데 창에서 헤더 파일(.h)을 선택합니다. 헤더 파일의 이름으로 지정 MathLibrary.h 합니다.

    C+ 더하기 헤더 파일 템플릿이 선택되고 이름 텍스트 상자에 MathLibrary.h가 입력된 새 항목 추가 대화 상자의 스크린샷

  3. 추가 단추를 선택하여 새 편집기 창에 표시되는 빈 헤더 파일을 생성합니다.

    편집기의 빈 MathLibrary.h 파일 스크린샷

  4. 헤더 파일의 내용을 다음 코드로 바꿉니다.

    // MathLibrary.h - Contains declarations of math functions
    #pragma once
    
    #ifdef MATHLIBRARY_EXPORTS
    #define MATHLIBRARY_API __declspec(dllexport)
    #else
    #define MATHLIBRARY_API __declspec(dllimport)
    #endif
    
    // The Fibonacci recurrence relation describes a sequence F
    // where F(n) is { n = 0, a
    //               { n = 1, b
    //               { n > 1, F(n-2) + F(n-1)
    // for some initial integral values a and b.
    // If the sequence is initialized F(0) = 1, F(1) = 1,
    // then this relation produces the well-known Fibonacci
    // sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    extern "C" MATHLIBRARY_API void fibonacci_init(
        const unsigned long long a, const unsigned long long b);
    
    // Produce the next value in the sequence.
    // Returns true on success and updates current value and index;
    // false on overflow, leaves current value and index unchanged.
    extern "C" MATHLIBRARY_API bool fibonacci_next();
    
    // Get the current value in the sequence.
    extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();
    
    // Get the position of the current value in the sequence.
    extern "C" MATHLIBRARY_API unsigned fibonacci_index();
    

이 헤더 파일은 두 개의 초기 값이 지정된 경우 일반화된 피보나치 시퀀스를 생성하는 일부 함수를 선언합니다. 친숙한 피보나치 숫자 시퀀스를 생성하는 호출 fibonacci_init(1, 1) 입니다.

파일 맨 위에 있는 전처리기 문을 확인합니다. DLL 프로젝트의 새 프로젝트 템플릿은 정의된 전처리기 매크로에 <PROJECTNAME>_EXPORTS를 추가합니다. 이 예제에서 Visual Studio는 MATHLIBRARY_EXPORTS MathLibrary DLL 프로젝트가 빌드되는 시기를 정의합니다.

매크로가 MATHLIBRARY_EXPORTS 정의되면 매크로는 MATHLIBRARY_API 함수 선언에서 __declspec(dllexport) 한정자를 설정합니다. 이 한정자는 다른 애플리케이션에서 사용하기 위해 DLL에서 함수 또는 변수를 내보내도록 컴파일러와 링커에 지시합니다. 정의되지 않은 경우 MATHLIBRARY_EXPORTS (예: 헤더 파일이 클라이언트 애플리케이션에 포함되는 경우) MATHLIBRARY_API 선언에 __declspec(dllimport) 한정자를 적용합니다. 이 한정자는 애플리케이션에서 함수 또는 변수의 가져오기를 최적화합니다. 자세한 내용은 dllexport, dllimport를 참조하세요.

DLL에 구현을 추가하려면

  1. 솔루션 탐색기에서 원본 파일 노드를 마우스 오른쪽 단추로 클릭하고새 항목>를 선택합니다. 이전 단계에서 새 헤더 파일을 추가한 것과 동일한 방식으로 MathLibrary.cpp라는 새 .cpp 파일을 만드세요.

  2. 편집기 창에서 MathLibrary.cpp 탭이 이미 열려 있는 경우 선택합니다. 그렇지 않은 경우 솔루션 탐색기에서 MathLibrary.cpp 프로젝트의 원본 파일 폴더를 두 번 클릭하여 엽니다.

  3. 편집기에서 파일의 MathLibrary.cpp 내용을 다음 코드로 바꿉니다.

    // MathLibrary.cpp : Defines the exported functions for the DLL.
    #include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
    #include <utility>
    #include <limits.h>
    #include "MathLibrary.h"
    
    // DLL internal state variables:
    static unsigned long long previous_;  // Previous value, if any
    static unsigned long long current_;   // Current sequence value
    static unsigned index_;               // Current seq. position
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    void fibonacci_init(
        const unsigned long long a,
        const unsigned long long b)
    {
        index_ = 0;
        current_ = a;
        previous_ = b; // see special case when initialized
    }
    
    // Produce the next value in the sequence.
    // Returns true on success, false on overflow.
    bool fibonacci_next()
    {
        // check to see if we'd overflow result or position
        if ((ULLONG_MAX - previous_ < current_) ||
            (UINT_MAX == index_))
        {
            return false;
        }
    
        // Special case when index == 0, just return b value
        if (index_ > 0)
        {
            // otherwise, calculate next sequence value
            previous_ += current_;
        }
        std::swap(current_, previous_);
        ++index_;
        return true;
    }
    
    // Get the current value in the sequence.
    unsigned long long fibonacci_current()
    {
        return current_;
    }
    
    // Get the current index position in the sequence.
    unsigned fibonacci_index()
    {
        return index_;
    }
    
  1. 편집기 창에서 이미 열려 있는 경우 MathLibrary.cpp 탭을 선택합니다. 그렇지 않은 경우 솔루션 탐색기에서 MathLibrary 프로젝트의 소스 파일 폴더에서 MathLibrary.cpp 두 번 클릭하여 엽니다.

  2. 편집기에서 파일의 MathLibrary.cpp 내용을 다음 코드로 바꿉니다.

    // MathLibrary.cpp : Defines the exported functions for the DLL.
    #include "stdafx.h" // use pch.h in Visual Studio 2019 and later
    #include <utility>
    #include <limits.h>
    #include "MathLibrary.h"
    
    // DLL internal state variables:
    static unsigned long long previous_;  // Previous value, if any
    static unsigned long long current_;   // Current sequence value
    static unsigned index_;               // Current seq. position
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    void fibonacci_init(
        const unsigned long long a,
        const unsigned long long b)
    {
        index_ = 0;
        current_ = a;
        previous_ = b; // see special case when initialized
    }
    
    // Produce the next value in the sequence.
    // Returns true on success, false on overflow.
    bool fibonacci_next()
    {
        // check to see if we'd overflow result or position
        if ((ULLONG_MAX - previous_ < current_) ||
            (UINT_MAX == index_))
        {
            return false;
        }
    
        // Special case when index == 0, just return b value
        if (index_ > 0)
        {
            // otherwise, calculate next sequence value
            previous_ += current_;
        }
        std::swap(current_, previous_);
        ++index_;
        return true;
    }
    
    // Get the current value in the sequence.
    unsigned long long fibonacci_current()
    {
        return current_;
    }
    
    // Get the current index position in the sequence.
    unsigned fibonacci_index()
    {
        return index_;
    }
    

지금까지 모든 것이 작동하는지 확인하려면 DLL을 컴파일합니다. 컴파일하려면 메뉴 모음에서빌드 솔루션 빌드> 를 선택합니다. DLL 및 관련 컴파일러 출력은 솔루션 폴더 바로 아래에 있는 폴더 Debug 에 배치됩니다. 릴리스 빌드를 만들면 출력이 라는 Release폴더에 배치됩니다. 출력은 다음과 같습니다.

1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>stdafx.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>MathLibrary.cpp
1>dllmain.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.pdb (Partial PDB)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

축하합니다. Visual Studio를 사용하여 DLL을 만들었습니다. 다음으로, DLL에서 내보낸 함수를 사용하는 클라이언트 앱을 만듭니다.

DLL을 사용하는 클라이언트 앱 만들기

DLL을 만들 때 클라이언트 앱에서 DLL을 사용하는 방법을 생각해 보세요. 함수를 호출하거나 DLL에서 내보낸 데이터에 액세스하려면 클라이언트 소스 코드에 컴파일 시간에 사용할 수 있는 선언이 있어야 합니다. 링크 타임에 링커는 함수 호출 또는 데이터 액세스를 해결하기 위한 정보가 필요합니다. DLL은 실제 코드 대신 함수 및 데이터를 찾는 방법에 대한 정보가 포함된 파일인 가져오기 라이브러리에 이 정보를 제공합니다. 그리고 런타임에 운영 체제에서 찾을 수 있는 위치에서 클라이언트에서 DLL을 사용할 수 있어야 합니다.

사용자 고유 또는 타사에서 온 클라이언트 앱 프로젝트에는 DLL을 사용하려면 몇 가지 정보가 필요합니다. DLL 내보내기를 선언하는 헤더, 링커의 가져오기 라이브러리 및 DLL 자체를 찾아야 합니다. 한 가지 해결 방법은 이러한 모든 파일을 클라이언트 프로젝트에 복사하는 것입니다. 클라이언트가 개발 중인 동안 변경되지 않는 타사 DLL의 경우 이 방법을 사용하는 가장 좋은 방법이 될 수 있습니다. 그러나 DLL을 빌드할 때 중복을 방지하는 것이 좋습니다. 개발 중인 DLL 파일의 로컬 복사본을 만드는 경우 실수로 한 복사본에서 헤더 파일을 변경하지만 다른 복사본은 변경하지 않거나 오래된 라이브러리를 사용할 수 있습니다.

동기화가 중단되는 코드를 방지하려면 DLL 프로젝트에서 직접 DLL 헤더 파일을 포함하도록 클라이언트 프로젝트의 포함 경로를 설정하는 것이 좋습니다. 또한 DLL 프로젝트의 DLL 가져오기 라이브러리를 포함하도록 클라이언트 프로젝트의 라이브러리 경로를 설정합니다. 마지막으로, DLL 프로젝트에서 빌드된 DLL을 클라이언트 빌드 출력 디렉터리로 복사합니다. 이 단계를 통해 클라이언트 앱은 빌드한 것과 동일한 DLL 코드를 사용할 수 있습니다.

Visual Studio에서 클라이언트 앱을 만들려면

  1. 메뉴 모음에서>프로젝트> 선택하여 새 프로젝트 만들기 대화 상자를 엽니다.

  2. 대화 상자 맨 위에서 언어C++로 설정하고, 플랫폼Windows로 설정하고, 프로젝트 형식콘솔로 설정합니다.

  3. 필터링된 프로젝트 형식 목록에서 콘솔 앱을 선택한 후 다음을 선택합니다.

  4. 새 프로젝트 구성 페이지의 프로젝트 이름 상자에 MathClient를 입력하여 프로젝트의 이름을 지정합니다. 기본 위치솔루션 이름 값을 그대로 둡니다. 솔루션을 설정하여 새 솔루션을 만듭니다. 솔루션 및 프로젝트를 동일한 디렉터리에 배치가 선택되어 있다면 선택을 취소하십시오.

    콘솔 앱 옵션이 강조 표시된 새 프로젝트 만들기 대화 상자의 스크린샷

  5. 만들기 단추를 선택하여 클라이언트 프로젝트를 만듭니다.

최소한의 콘솔 애플리케이션 프로젝트가 생성되었습니다. 주 원본 파일의 이름은 이전에 입력한 프로젝트 이름과 동일합니다. 이 예제에서는 이름이 . MathClient.cpp입니다. 빌드할 수 있지만 아직 DLL을 사용하지 않습니다.

Visual Studio 2017에서 클라이언트 앱을 만들려면

  1. 만든 DLL을 사용하는 C++ 앱을 만들려면 메뉴 모음에서>프로젝트 파일을> 선택합니다.

  2. 새 프로젝트 대화 상자의 왼쪽 창에서 설치된Visual C++에서 Windows 데스크톱> 선택합니다. 가운데 창에서 Windows 콘솔 애플리케이션을 선택합니다. 이름 편집 상자에 프로젝트의 이름(MathClient)을 지정합니다. 기본 위치솔루션 이름 값을 그대로 둡니다. 솔루션을 설정하여 새 솔루션을 만듭니다. 선택 취소된 경우 솔루션에 대한 디렉터리 만들기 를 확인합니다.

    Windows 콘솔 애플리케이션이 강조 표시되고 이름 텍스트 상자에 수학 클라이언트가 입력된 새 프로젝트 대화 상자의 스크린샷

  3. 확인을 선택하여 클라이언트 앱 프로젝트를 만듭니다.

최소 콘솔 애플리케이션 프로젝트가 생성됩니다. 주 원본 파일의 이름은 이전에 입력한 프로젝트 이름과 동일합니다. 이 예제에서는 이름이 . MathClient.cpp입니다. 빌드할 수 있지만 아직 DLL을 사용하지 않습니다.

Visual Studio 2015에서 클라이언트 앱을 만들려면

  1. 만든 DLL을 사용하는 C++ 앱을 만들려면 메뉴 모음에서>프로젝트 파일을> 선택합니다.

  2. 새 프로젝트 대화 상자의 왼쪽 창에서 설치된템플릿>에서 Win32> 선택합니다. 가운데 창에서 Win32 콘솔 애플리케이션을 선택합니다. 이름 편집 상자에 프로젝트의 이름(MathClient)을 지정합니다. 기본 위치솔루션 이름 값을 그대로 둡니다. 솔루션을 설정하여 새 솔루션을 만듭니다. 체크되어 있지 않으면 솔루션에 대한 디렉터리 만들기를 선택하십시오.

    Win32 콘솔 애플리케이션 Visual C++가 강조 표시된 새 프로젝트 대화 상자의 스크린샷이며, 이름 텍스트 상자에 Math Client가 입력되어 있습니다.

  3. 확인 단추를 선택하여 새 프로젝트 대화 상자를 해제하고 Win32 애플리케이션 마법사를 시작합니다. Win32 애플리케이션 마법사 대화 상자의 개요 페이지에서 다음 단추를 선택합니다.

  4. 애플리케이션 설정 페이지의 애플리케이션 유형에서 아직 선택되지 않은 경우 콘솔 애플리케이션을 선택합니다.

  5. 마침 단추를 선택하여 프로젝트를 만듭니다.

마법사가 완료되면 최소한의 콘솔 애플리케이션 프로젝트가 생성됩니다. 주 원본 파일의 이름은 이전에 입력한 프로젝트 이름과 동일합니다. 이 예제에서는 이름이 . MathClient.cpp입니다. 빌드할 수 있지만 아직 DLL을 사용하지 않습니다.

다음으로 소스 코드에서 MathLibrary 함수를 호출하려면 프로젝트에 파일이 포함되어 MathLibrary.h 야 합니다. 이 헤더 파일을 클라이언트 앱 프로젝트에 복사한 다음 프로젝트에 기존 항목으로 추가할 수 있습니다. 이 메서드는 타사 라이브러리에 적합할 수 있습니다. 그러나 DLL 및 클라이언트에 대한 코드를 동시에 작업하는 경우 헤더 파일이 동기화에서 벗어날 수 있습니다. 이 문제를 방지하려면 프로젝트의 추가 포함 디렉터리 경로를 설정하여 원래 헤더의 경로를 포함합니다.

포함 경로에 DLL 헤더를 추가하려면

  1. 솔루션 탐색기에서 MathClient 노드를 마우스 오른쪽 단추로 클릭하여 속성 페이지 대화 상자를 엽니다.

  2. 구성 드롭다운 상자에서 아직 선택되지 않은 경우 모든 구성을 선택합니다.

  3. 왼쪽 창에서 구성 속성>C/C++>일반을 선택합니다.

  4. 속성 창에서 추가 포함 디렉터리 편집 상자 옆에 있는 드롭다운 컨트롤을 선택한 다음 편집을 선택합니다.

    추가 포함 디렉터리 속성 드롭다운의 편집 명령을 보여 주는 속성 페이지 대화 상자의 스크린샷.

  5. 추가 포함 디렉터리 대화 상자의 위쪽 창을 두 번 클릭하여 편집 컨트롤을 사용하도록 설정합니다. 또는 폴더 아이콘을 선택하여 새 항목을 만듭니다.

  6. 편집 컨트롤에서 헤더 파일의 위치에 대한 경로를 지정합니다 MathLibrary.h . 줄임표(...) 컨트롤을 선택하여 올바른 폴더로 이동할 수 있습니다.

    클라이언트 원본 파일에서 DLL 헤더 파일이 포함된 폴더로의 상대 경로를 입력할 수도 있습니다. 지침에 따라 클라이언트 프로젝트를 DLL과 별도의 솔루션에 배치한 경우 상대 경로는 다음과 같습니다.

    ..\..\MathLibrary\MathLibrary

    DLL 및 클라이언트 프로젝트가 동일한 솔루션에 있는 경우 상대 경로는 다음과 같을 수 있습니다.

    ..\MathLibrary

    DLL 및 클라이언트 프로젝트가 다른 폴더에 있는 경우 상대 경로를 일치하도록 조정합니다. 또는 줄임표 컨트롤을 사용하여 폴더를 찾습니다.

    MathLibrary 디렉터리에 대한 상대 경로를 보여 주는 추가 포함 디렉터리 대화 상자의 스크린샷

  7. 추가 포함 디렉터리 대화 상자에서 헤더 파일의 경로를 입력한 후 확인 단추를 선택합니다. 속성 페이지 대화 상자에서 확인 단추를 선택하여 변경 내용을 저장합니다.

이제 MathLibrary.h 파일을 포함하고, 클라이언트 애플리케이션에서 이 파일이 선언하는 함수를 사용할 수 있습니다. 다음 코드를 사용하여 내용을 바꿉니다.MathClient.cpp

// MathClient.cpp : Client app for MathLibrary DLL.
// #include "pch.h" Uncomment for Visual Studio 2017 and earlier
#include <iostream>
#include "MathLibrary.h"

int main()
{
    // Initialize a Fibonacci relation sequence.
    fibonacci_init(1, 1);
    // Write out the sequence values until overflow.
    do {
        std::cout << fibonacci_index() << ": "
            << fibonacci_current() << std::endl;
    } while (fibonacci_next());
    // Report count of values written before overflow.
    std::cout << fibonacci_index() + 1 <<
        " Fibonacci sequence values fit in an " <<
        "unsigned 64-bit integer." << std::endl;
}

이 코드는 컴파일할 수 있지만 연결되지는 않습니다. 지금 클라이언트 앱을 빌드하는 경우 오류 목록에 몇 가지 LNK2019 오류가 표시됩니다. 프로젝트에 일부 정보가 누락되었기 때문입니다. 프로젝트에 라이브러리에 대한 MathLibrary.lib 종속성을 아직 지정하지 않았습니다. 그리고 링커에게 파일을 찾는 MathLibrary.lib 방법을 말하지 않았습니다.

이 문제를 해결하려면 라이브러리 파일을 클라이언트 앱 프로젝트에 직접 복사할 수 있습니다. 링커는 자동으로 찾아서 사용한다. 그러나 라이브러리와 클라이언트 앱이 모두 개발 중인 경우, 한쪽에서의 변경 사항이 다른 쪽에 반영되지 않을 수 있습니다. 이 문제를 방지하려면 추가 종속성 속성을 설정하여 빌드 시스템에 프로젝트가 종속됨을 알릴 수 있습니다 MathLibrary.lib. 또한 연결할 때 원래 라이브러리의 경로를 포함하도록 프로젝트에서 추가 라이브러리 디렉터 리 경로를 설정할 수 있습니다.

프로젝트에 DLL 가져오기 라이브러리를 추가하려면

  1. 솔루션 탐색기에서 MathClient 노드를 마우스 오른쪽 단추로 클릭하고 속성을 선택하여 속성 페이지 대화 상자를 엽니다.

  2. 구성 드롭다운 상자에서 아직 선택되지 않은 경우 모든 구성을 선택합니다. 그러면 속성 변경 내용이 디버그 및 릴리스 빌드 모두에 적용됩니다.

  3. 왼쪽 창에서 구성 속성>링커 입력을> 선택합니다. 속성 창에서 추가 종속성 편집 상자 옆에 있는 드롭다운 컨트롤을 선택한 다음 편집을 선택합니다.

    입력 아래에 있는 속성 페이지 대화 상자에서 '추가 종속성' 속성 드롭다운의 편집 명령을 보여 주는 스크린샷

  4. 추가 종속성 대화 상자에서 맨 위 편집 컨트롤의 목록에 추가 MathLibrary.lib 합니다.

    MathLibrary.lib 파일을 보여 주는 추가 종속성 대화 상자의 스크린샷

  5. [확인]을 선택하여 [속성 페이지] 대화 상자로 돌아갑니다.

  6. 왼쪽 창에서 구성 속성>링커 일반을> 선택합니다. 속성 창에서 추가 라이브러리 디렉터리 편집 상자 옆에 있는 드롭다운 컨트롤을 선택한 다음 편집을 선택합니다.

    일반 탭 아래의 속성 페이지 대화 상자에서 추가 라이브러리 디렉터리 속성 드롭다운에 있는 편집 명령을 보여주는 스크린샷

  7. 추가 라이브러리 디렉터리 대화 상자의 위쪽 창을 두 번 클릭하여 편집 컨트롤을 사용하도록 설정합니다. 편집 컨트롤에서 파일 위치의 경로를 지정합니다 MathLibrary.lib . 기본적으로 DLL 솔루션 폴더 바로 아래에 디버그 라는 폴더에 있습니다. 릴리스 빌드를 만들면 파일이 Release라는 폴더에 배치됩니다. 어떤 종류의 빌드를 $(IntDir) 만들든 링커가 DLL을 찾을 수 있도록 매크로를 사용할 수 있습니다. DLL 프로젝트와 별도의 솔루션에 클라이언트 프로젝트를 배치하는 지침을 따른 경우 상대 경로는 다음과 같습니다.

    ..\..\MathLibrary\$(IntDir)

    DLL 및 클라이언트 프로젝트가 다른 위치에 있는 경우 일치하도록 상대 경로를 조정합니다.

    추가 라이브러리 디렉터리 대화 상자의 스크린샷.

  8. 추가 라이브러리 디렉터리 대화 상자에서 라이브러리 파일의 경로를 입력한 후 확인 단추를 선택하여 속성 페이지 대화 상자로 돌아갑니다. 확인을 선택하여 속성 변경 내용을 저장합니다.

이제 클라이언트 앱이 컴파일하고 성공적으로 연결할 수 있지만 실행해야 하는 모든 항목이 아직 없습니다. 운영 체제에서 앱을 로드하면 MathLibrary DLL을 찾습니다. 특정 시스템 디렉터리, 환경 경로 또는 로컬 앱 디렉터리에서 DLL을 찾을 수 없는 경우 로드가 실패합니다. 운영 체제에 따라 다음과 같은 오류 메시지가 표시됩니다.

MathLibrary DLL을 찾을 수 없는 오류 대화 상자의 스크린샷

이 문제를 방지하는 한 가지 방법은 빌드 프로세스의 일부로 클라이언트 실행 파일이 포함된 디렉터리에 DLL을 복사하는 것입니다. 빌드 후 이벤트를 프로젝트에 추가하여 DLL을 빌드 출력 디렉터리에 복사하는 명령을 추가할 수 있습니다. 여기에 지정된 명령은 DLL이 누락되었거나 변경된 경우에만 복사합니다. 빌드 구성에 따라 매크로를 사용하여 디버그 또는 릴리스 위치로 데이터를 복사하거나 복사해 옵니다.

빌드 후 이벤트에서 DLL을 복사하려면

  1. 솔루션 탐색기에서 MathClient 노드를 마우스 오른쪽 단추로 클릭하고 속성을 선택하여 속성 페이지 대화 상자를 엽니다.

  2. 구성 드롭다운 상자에서 아직 선택되지 않은 경우 모든 구성을 선택합니다.

  3. 왼쪽 창에서 구성 속성>빌드 이벤트>빌드 후 이벤트를 선택합니다.

  4. 속성 창의 명령줄 필드에서 편집 컨트롤을 선택합니다. 지침에 따라 DLL 프로젝트와 별도의 솔루션에 클라이언트 프로젝트를 배치한 경우 다음 명령을 입력합니다.

    xcopy /y /d "..\..\MathLibrary\$(IntDir)MathLibrary.dll" "$(OutDir)"

    DLL 및 클라이언트 프로젝트가 다른 디렉터리에 있는 경우 일치하도록 DLL의 상대 경로를 변경합니다.

    빌드 후 이벤트 명령줄 속성을 보여 주는 속성 페이지 대화 상자의 스크린샷

  5. 확인 단추를 선택하여 변경 내용을 프로젝트 속성에 저장합니다.

이제 클라이언트 앱에 빌드하고 실행하는 데 필요한 모든 것이 있습니다. 메뉴 모음에서빌드 솔루션 빌드를 선택하여 애플리케이션을 >합니다. Visual Studio의 출력 창에는 Visual Studio 버전에 따라 다음 예제와 같은 내용이 있어야 합니다.

1>------ Build started: Project: MathClient, Configuration: Debug Win32 ------
1>MathClient.cpp
1>MathClient.vcxproj -> C:\Users\username\Source\Repos\MathClient\Debug\MathClient.exe
1>1 File(s) copied
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

축하합니다. DLL에서 함수를 호출하는 애플리케이션을 만들었습니다. 이제 애플리케이션을 실행하여 애플리케이션이 수행하는 작업을 확인합니다. 메뉴 모음에서디버깅하지 않고> 시작을 선택합니다. Visual Studio에서 프로그램을 실행할 명령 창을 엽니다. 출력의 마지막 부분은 다음과 같습니다.

디버깅하지 않고 클라이언트 앱을 시작할 때의 명령 창 출력 스크린샷

아무 키나 눌러 명령 창을 해제합니다.

이제 DLL 및 클라이언트 애플리케이션을 만들었으므로 실험할 수 있습니다. 클라이언트 앱의 코드에서 중단점을 설정하고 디버거에서 앱을 실행합니다. 라이브러리 호출을 한 단계씩 실행하면 어떻게 되는지 확인합니다. 라이브러리에 다른 함수를 추가하거나 DLL을 사용하는 다른 클라이언트 앱을 작성합니다.

앱을 배포할 때 사용하는 DLL도 배포해야 합니다. 빌드하거나 타사에서 포함하는 DLL을 사용할 수 있도록 하는 가장 간단한 방법은 앱과 동일한 디렉터리에 배치하는 것입니다. 앱-로컬 배포라고 합니다. 배포에 대한 자세한 내용은 Microsoft C++의 배포를 참조하세요.

참고하십시오