[C/C++/C#] dll

1. Predefined macro

_CONSOLE 매크로는 하위시스템이 콘솔일때 정의된다.

_WINDLL 매크로는 dll프로젝트일때 정의된다.

http://stackoverflow.com/questions/7697859/visual-studio-macro-for-checking-configuration-type-exe-dll
이를 이용하면 dll 프로젝트에서 테스트를 위해 main 함수와 함께 사용할 수 있다.

#ifdef _WINDLL	
#include<Windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
	switch (ul_reason_for_call) {
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
#else
#include<iostream>
int main(){
    std::cout << "i'm test function" << std::endl;
}
#endif

2. dll 프로젝트 생성

a. DLL프로젝트를 빈 프로젝트로 생성한다.
b. 만들고자 하는 함수를 아래와 같은 형식으로 정의 한다.
extern "C"{
    __declspec(dllexport) int foo(int a){
        return a;
    }
}

3. dll load in C/C++(암시적)

프로젝트 설정의 추가 라이브러리 디렉터리 에서 lib 파일을 추가해준다.
또는, #pragma comment 키워드로 추가할수 있다.이거 좀 비추

사용하는 곳에서는 함수 정의만 있으면 된다. 헤더파일을 만들어 두는게 더 좋은 방식이다.

dllexe와 같은 경로에 있어야 한다.

또는 32비트 dll의 경우 C:\Windows\SysWOW64 에 있거나, 64비트 dll의 경우 C:\Windows\System32 에 있으면 된다.

4. dll load in C/C++(명시적)

말은 필요없다. 코드로 설명한다.

뭔소린지 모르겠다면, 함수 포인터 부분을 공부하고 오자.

int(*foo)(int a)= NULL;
HMODULE hMod=LoadLibraryA("a.dll");
if(hMod==NULL){
    fprintf(stderr,"Dll load fail(%d)\n",GetLastError());
}
foo=(int(*)())GetProcAddress(hMod,"foo");

//foo();

FreeLibrary(hMod);

이때 dll 로드가 실패한다면 GetLastError 함수를 통해 실패한 이유를 알 수 있다.

193 번 에러는 해당 dll과 client 프로그램의 비트수가 맞지 않아 생기는 에러이다.
(e.g. 64비트 프로세스에서 32비트 dll을 호출)

5. dll load in C#(암시적)

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace cs_program
{
    class Program
    {
        //외부 함수 Import
        [DllImport("a.dll")]
        public static extern int foo(int a);
 
        static void Main(string[] args)
        {
             foo(5);  //그냥 호출 하면 됨.
        }
    }
}

6. dll load in C#(명시적)

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace cs_program
{
    class Program
    {
        //dll을 로드하기 위한 함수 import
        [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
        static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
        static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);
        [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
        static extern bool FreeLibrary(int hModule);
        [DllImport("kernel32.dll", EntryPoint = "GetLastError")]
        static extern int GetLastError();
 
        //함수를 받기위한 원형 선언
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate int FUNC_foo(int);
        FUNC_foo foo;
 
        static void Main(string[] args)
        {
            IntPtr dll = LoadLibrary("a.dll");
            if (dll == IntPtr.Zero)
            {
                MessageBox.Show(GetLastError().ToString());
                Environment.Exit(1);
            }else
            {
                IntPtr func_addr= GetProcAddress(dll, "foo");
                foo = (FUNC_foo)Marshal.GetDelegateForFunctionPointer(func_addr, typeof(FUNC_foo));
            }
            foo(5); 
        }
    }
}

References