오늘 회사에서 아는 형이 코드에서 "PInvokeStackImbalance" Exception이 발생한다고 도와달라고 했다.

사실 여기서 가장 큰 문제는 "왜 되던 코드가 안되는 것일까?" 였다. 이전 프로젝트에서는 DLL을 잘 로드해서 썼는데, 새로 프로젝트를 만들고 똑같이 DLL을 로드했는데 갑자기 위의 Exception이 발생했다고 한다.

그래서 두 프로젝트를 비교해봤더니 사용하던 .Net Framework 버전이 달랐다. 잘 되던 곳은 3.0을 쓰고 있었고, 안되는 곳은 4.0을 쓰는 문제가 있었다.

그래서 찾아봤다. 역시 문제는 CallingConvention 문제.

[DllImport("TestDll.dll")]
public static extern int Test(string text);

위와 같이 작성되었던 것을

[DllImport("TestDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int Test(string text);

이렇게 뒤에 CallingConvention을 붙여서 호출하면 된다.


보통 C++에서 DLL을 만들면 cdecl 이란 호출규약으로 만든다. 왜냐면 다들 귀찮으니까 별도의 호출규약을 안써준다. 근데, C#에서 DllImportAttributeCallingConvention은 기본값이 stdcall이다. 그래서 에러가 난거다.


호출규약에 대해서 궁금하면 여기! 를 참고하면 좋다.


뭐... 이거야 쉽게 해결했지만 왜 3.0에서는 된걸까?

여러 글을 찾아보다가 결국 해답은 못찾았다. 하지만 StackOverflow에 같은 질문이 올라온 글에 David Hefferman이란 사람이 아래와 같이 적어놓았다.

Don't kid yourself that your code is alright because .net 3.5 doesn't raise this error. The error detection in .net 4 is better which is why you only see the errors there. But your code is broken in all .net versions.

굳이 해석하자면...

"3.5에서 에러가 나지 않았다고 코드에 이상없다고 착각하지 마. 단지 4.0에서 이러한 에러를 잘 찾아내니까 발생한거야. 니 코드는 모든 .net 버전에서 에러야"


음. 명언이다. 에러가 안난건 단지 4.0의 성능이 좋아서다. 내가 봐도 확실히 에러 맞다.



posted by 스펜서.