C++로 만든 Iocp Server 및 winapi 클라이언트를 연동한 C++ 프로젝트를 C#으로 하나의 단일 게임엔진으로 통합하는 과정이었습니다.
근데 C++에서는 winapi의 함수 호출은 #pragma comment('user32.lib') 뭐 이런 걸로 user32라이브러리 파일을 통해서 링크한 후 CreateWindowExW 이런 함수들을 쓰면 그만이었는데, 막상 C#으로 통합하려하니까
C#에서는 어떻게 하지 ? ?? ? ? 라는 문제점에 봉착했습니다.
1. 일단 런타임이든 윈도우 생성이든 네트워크든간에 OS 기능을 빌려와야 함.
- OS는 그 기능을 native dll (x64/x86 기계어 dll 파일)형태로만 노출하기 때문에, 해당 native dll에 접근해서 가져오면 되겠습니다. (dll 파일도 여러가지 파일이 존재함. native dll / managed dll)
2. native dll 파일은 export table이 존재해서 호출할 수 있는 메서드 이름 및 정보가 존재함.

이런식으로
3. C#에서는 attribute를 통해서 dllimport로 어떤 dll에 접근할건지 알려줄 수 있음.
[DllImport("user32.dll")]
public static extern bool ShowWindow(nint hWnd, int nCmdShow);
이런식으로
4. 이렇게 함수를 정의해놓으면 C#에서는 ShowWindow 함수를 그냥 C++에서 쓰듯이 쓰면 되는거임.
5. 그럼 이제 ShowWindow함수를 호출한다고 가정해보겠음. 내부에서 어떤일이 일어나길래 가능한건지 알아보겠음.
6. 호출 시 다음과 같은 일이 일어남.
- CoreCLR(java의 JVM같은거) 이 메타데이터에서 dll의 이름과(attribute를 참고해서) 함수 이름을 꺼냄.
- LoadLibrary("user32.dll") 함수를 호출해서 user32.dll의 베이스 주소를 반환함.
- GetProcAddress(user32, "ShowWindow")함수를 호출함. -> 위에서 봤던 user32.dll의 export table을 참고해서 showwindow를 찾음.
- 이 주소를 캐싱 후 IL Stub를 생성
- IL Stub의 내용 구현에는 매개변수 마샬링 + GC 전환 + 호출 + 역마샬링을 IL로 합성한 임시 메서드를 생성함. 그리고 JIT로 IL컴파일
- 다음 CreateWindowEx를 호출 시에 JIT가 컴파일한 stub의 기계어를 호출
7. 많이 복잡하긴 한데, 이 과정을 P/Invoke 라고 부름.
8. 그리고 이 과정에서 사용자의 언어를 컴파일된 바이너리 user32.dll에 맞춰서 메모리 레이아웃, 호출 규약, 데이터 형식을 맞춰주는 것임. 그리고 데이터 형식을 맞춰준 것을 토대로 함수를 호출하는 것임.
9. 그리고 8번에서 진행하는 것이 바로 '마샬링' 이라는 작업임.
- 마샬링이라는게 굉장히 어려운 문장으로 막 한 객체의 메모리에서의 표현방식을 저장 또한 전송에 적합한 다른 데이터 형식으로 변환하는 과정 이런식으로 설명되어 있는데, 결국에는 상대방이 알아먹기 쉽게 내 언어를 다른 형식으로 변환하는 과정을 말하는 거. marShal이라는 단어의 어원도 군대 혹은 외교에서 '행렬을 정돈해서 다른 진영으로 보낸다' 라는 뜻임.
10. 결과적으로 C#에서 winapi 함수를 호출하기 위해서는 이런식으로 한번의 래핑 ? 작업이 필요한 것임.