예전 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.
본인이 시도하여 성공한 순서대로 적고자 한다.
- 프로그램을 시작하여 ‘새 프로젝트 만들기(N)‘ 클릭
- ‘새 프로젝트 만들기‘ 창 상단 검색 바에서 ‘라이브러리‘ 입력 후 나타나는 목록 중 ‘DLL(동적 연결 라이브러리)‘ 선택 후 ‘다음‘ 클릭
- ‘새 프로젝트 구성‘ 창 내 ‘프로젝트 이름(J)‘에 ‘MyUtil‘ 입력 후 ‘만들기(C)‘ 클릭
- 메인 메뉴에서 ‘프로젝트(P)‘ ⇒ ‘새 항목 추가(W)…‘ 클릭
- ‘새 항목 추가‘ 창에서 ‘헤더 파일(.h)‘ 선택하고 하단 ‘이름(N)‘ 입력란에 ‘MyUtil.h‘ 입력 후 ‘추가(A)‘ 클릭
- 메인 창 ‘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);
- 우측 ‘솔루션 탐색기‘ 창에서 마우스 우클릭으로 ‘소스 파일‘ 클릭 후 ‘추가‘ ⇒ ‘새 항목(W)…‘ 클릭
- ‘새 항목 추가‘ 창에서 ‘C++ 파일(.cpp)‘ 선택하고 하단 ‘이름(N)‘ 입력란에 ‘MyUtil.cpp‘ 입력 후 ‘추가(A)‘ 클릭
- 메인 창 ‘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); }
- 메인 메뉴에서 ‘빌드‘ ⇒ ‘솔루션 빌드(B)‘ 클릭
- 상단 도구 모음에서 ‘x64‘ 확인 후 하단 ‘출력‘ 창에서 빌드 성공 메시지 확인
- 엑셀을 시작하여 ‘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
- 실제로 적용하여 아무런 문제가 없는 것을 확인!!!
예전과는 다른 방법으로 엑셀에서 사용하려는 DLL을 생성했으며 또한 과거 종종 DLL 사용하던 엑셀이 Crash로 죽던 경우가 본 방법을 통해 생성한 DLL 사용 시 아직까지는 발생하지 않고 있다.