Visual Studio Community 2022에서 DLL 만든 후 Excel에서 사용

예전 Visual Studio 2008에서 Simple DLL 만든 후 Excel에서 사용하기 글을 통해 DLL 생성 후 엑셀에서 Declare 문을 통해 잘 사용했었다.

그러나!!!

당시 사용하던 Windows OS는 Windows XP, 그것도 32bit OS 이었고 Office 역시 32bit 버전이 대세였으나 현재는 Windows 10 64bit에 Office 역시 64bit가 대세를 형성하고 있다. 1

이와 같은 상황에서 예전 글을 참고해서, 그것도 10여 년 전 버전의 Visual Studio 2008 버전으로 DLL을 만들어 2022년 현재의 Windows 11 64bit + Office 2016 64bit 조합에 들이대기 영 껄쩍지근하던 차에 아래의 글을 발견하고 차례로 적용하여 성공한 기억을 잊어 먹지 않기 위해 글로 남긴다.

참고로 본인은 본 글 제목에서처럼 Visual Studio Community 2022 버전으로 시도했으니 참고하기를. 아, 또 하나는 상기 글을 작성한 저자가 아래와 같은 주의사항을 강한 늬앙스로 명기하고 있으니 이 역시 참고하기를.

Note: Be sure to change the path after Lib to the location of .dll on your own computer.

Above we define a function get_square_cpp which exposes our .dll file’s get_square function. Notice that we pass the argument by reference, as our C++ code expects a pointer. We then define a wrapper function named get_square which ensures that any data passed to our get_square_cpp is the expected “double” data type. Using get_square_cpp directly without the help of the explicitly typed parameters of the wrapper function can result in data being incorrectly marshalled to our C++ function, causing Excel to crash.

본인이 시도하여 성공한 순서대로 적고자 한다.

  1. 프로그램을 시작하여 ‘새 프로젝트 만들기(N)‘ 클릭
    Visual Studio 2022 시작 화면 — '새 프로젝트 만들기' 선택
  2. 새 프로젝트 만들기‘ 창 상단 검색 바에서 ‘라이브러리‘ 입력 후 나타나는 목록 중 ‘DLL(동적 연결 라이브러리)‘ 선택 후 ‘다음‘ 클릭
    새 프로젝트 만들기 — '라이브러리' 검색 후 'DLL(동적 연결 라이브러리)' 템플릿 선택, 다음 클릭
  3. 새 프로젝트 구성‘ 창 내 ‘프로젝트 이름(J)‘에 ‘MyUtil‘ 입력 후 ‘만들기(C)‘ 클릭
    새 프로젝트 구성 — 프로젝트 이름 MyUtil, 위치 C:\Users\Kiin\source\repos, 만들기 클릭
  4. 메인 메뉴에서 ‘프로젝트(P)‘ ⇒ ‘새 항목 추가(W)…‘ 클릭
    Visual Studio 프로젝트 메뉴 — '새 항목 추가...(Ctrl+Shift+A)' 선택
  5. 새 항목 추가‘ 창에서 ‘헤더 파일(.h)‘ 선택하고 하단 ‘이름(N)‘ 입력란에 ‘MyUtil.h‘ 입력 후 ‘추가(A)‘ 클릭
    새 항목 추가 — Visual C++ 헤더 파일(.h) 선택, 이름 MyUtil.h, 추가 클릭
  6. 메인 창 ‘MyUtil.h‘ 탭 안에 아래 내용 입력
    // MyUtil.h - 함수들에 대한 선언 포함
    #pragma once
    
    #ifdef MYUTIL_EXPORTS
    #define MYUTIL_API __declspec(dllexport)
    #else
    #define MYUTIL_API __declspec(dllimport)
    #endif
    
    extern "C" MYUTIL_API double GetSquare(double* x);
    extern "C" MYUTIL_API double MyX(double* a, double* b);

    MyUtil.h 편집 화면 — MYUTIL_EXPORTS 조건부 dllexport/dllimport 매크로와 extern "C" MYUTIL_API double get_square(double* x); 선언

  7. 우측 ‘솔루션 탐색기‘ 창에서 마우스 우클릭으로 ‘소스 파일‘ 클릭 후 ‘추가‘ ⇒ ‘새 항목(W)…‘ 클릭
    솔루션 탐색기 소스 파일 우클릭 — 추가 > 새 항목 메뉴 선택
  8. 새 항목 추가‘ 창에서 ‘C++ 파일(.cpp)‘ 선택하고 하단 ‘이름(N)‘ 입력란에 ‘MyUtil.cpp‘ 입력 후 ‘추가(A)‘ 클릭
    새 항목 추가 — C++ 파일(.cpp) 선택, 이름 MyUtil.cpp, 추가 클릭
  9. 메인 창 ‘MyUtil.cpp‘ 탭 안에 아래 내용 입력
    // MyUtil.cpp : DLL로 내보낸 (exported) 함수 정의.
    #include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
    #include "MyUtil.h"
    #include <cmath>
    
    double WINAPI GetSquare(double* x)
    {
        return *x * *x;
    }
    
    double WINAPI MyX(double* a, double* b)
    {
        if (*a > *b)
            return pow(*a, *b);
        else
            return pow(*b, *a);
    }

    MyUtil.cpp 편집 화면 — GetSquare(제곱 반환)와 MyX(큰 값의 거듭제곱 반환) 함수 정의

  10. 메인 메뉴에서 ‘빌드‘ ⇒ ‘솔루션 빌드(B)‘ 클릭
    빌드 메뉴 — '솔루션 빌드(Ctrl+Shift+B)' 선택 (우측 하단에 Windows 보안 알림 표시)
  11. 상단 도구 모음에서 ‘x64‘ 확인 후 하단 ‘출력‘ 창에서 빌드 성공 메시지 확인
    x64 Debug 빌드 결과 — 출력 창에 MyUtil.lib·MyUtil.exp 생성과 MyUtil.dll 빌드 성공(1 성공, 0 실패) 메시지
  12. 엑셀을 시작하여 ‘MyUtil.xlsb’란 새 이름으로 저장하고 ‘ALT + F11’ 이용하여 나타난 Microsoft Visual Basic for Application 창에 아래 내용을 입력 2
    Option Explicit
    	
    ' Win64는 64비트 오피스인지 판별하는 상수
    ' VBA7은 오피스 2010 이상인지 판별하는 상수
    #If Win64 Then
        Private Declare PtrSafe Function GetSquareCpp Lib "C:\Users\Kiin\source\repos\MyUtil\x64\Debug\MyUtil.dll" _
            Alias "GetSquare" (ByRef Arg As Double) As Double
    
        Private Declare PtrSafe Function MyXCpp Lib "C:\Users\Kiin\source\repos\MyUtil\x64\Debug\MyUtil.dll" _
            Alias "MyX" (ByRef Arg1 As Double, ByRef Arg2 As Double) As Double
    #Else ' x86으로 Build한 DLL 선언
        Private Declare Function GetSquareCpp Lib "C:\Users\Kiin\source\repos\MyUtil\x86\Debug\MyUtil.dll" _
            Alias "GetSquare" (ByRef Arg As Double) As Double
    
        Private Declare Function MyXCpp Lib "C:\Users\Kiin\source\repos\MyUtil\x86\Debug\MyUtil.dll" _
            Alias "MyX" (ByRef Arg1 As Double, ByRef Arg2 As Double) As Double
    #End If
    
    ' ByRef가 기본이나 하나의 셀에 있는 값을 인수로 받기 때문에 명확하게 하기 위해 ByVal 사용
    Public Function GetSquare(ByVal x As Double) As Double
        GetSquare = GetSquareCpp(x)
    End Function
    
    ' ByRef가 기본이나 하나의 셀에 있는 값을 각각 인수로 받기 때문에 명확하게 하기 위해 ByVal 사용
    Public Function MyX(ByVal Arg1 As Double, ByVal Arg2 As Double) As Double
        MyX = MyXCpp(Arg1, Arg2)
    End Function
    
    Sub tmp()
        MsgBox GetSquare(0.2)
        MsgBox MyX(0.8, 0.2)
    End Sub

    VBA 편집기 Module1 — #If Win64 분기로 MyUtil.dll의 GetSquareCpp·MyXCpp를 Declare PtrSafe 선언하고 GetSquare·MyX 공용 함수로 감싼 코드

  13. 실제로 적용하여 아무런 문제가 없는 것을 확인!!!
    Excel 시트에서 DLL 함수 테스트 — GetSquare(D5)=0.04(POWER와 동일), MyX(D5,D6)=0.956352(POWER와 동일), FORMULATEXT()로 수식 확인

예전과는 다른 방법으로 엑셀에서 사용하려는 DLL을 생성했으며 또한 과거 종종 DLL 사용하던 엑셀이 Crash로 죽던 경우가 본 방법을 통해 생성한 DLL 사용 시 아직까지는 발생하지 않고 있다.

조회수: 38

Footnotes

  1. 본인 주변을 돌아봤을 때를 전제로 한 판단이다. 아니면 말고.
  2. 캡처 이미지 상으로 붉은 부분이 있어서 오류라고 착각할 수도 있으나 실제 사용하는 데에는 전혀 지장을 주지 않는다.

댓글 남기기