기본 콘텐츠로 건너뛰기

Use VC++ to create a DLL file and use its functions in Visual Basic 6 Programming Tips

VB에서 VC DLL을 호출 할때 호출 규약 오류 때문에 DLL을 찾을수 없다고 메세지를 띄울 때 처리하는 방법입니다.
저희 회사는 아직도 VB 6.0을 사용하고 있거던요.(지금도 UI를 VB로 개발해요 ㅠㅠ)

간단히 말하면 VC에서 __stdcall 호출 규약을 사용하여 DLL 함수를 만들구요,
VB쪽에서 함수를 선언할때 DLL 전체 경로를 주고요, 또한 Alias를 설정해 줍니다.

배포할 때 주의 사항은 DLL 전체 경로를 주면 실행시 해당 경로에 DLL을 찾기 때문에 오류가 발생할수 있습니다.
따라서 DLL 전체 경로를 없애야 합니다.(대부분이 DLL을 실행 파일이랑 같이 두니까요)


원본 : http://b4you.net/blog/tag/%ED%98%B8%EC%B6%9C%EA%B7%9C%EC%95%BD

VC에서 만든 DLL을 VB에서 사용할 때 애먹고 있으신 분들을 위해..
참고로, 굳이 프로젝트 세팅에서 __stdcall 방식으로 바꿀 필요는 없다.
이렇게 하면 c 코드를 작성하는 모든 부분의 데이터를 이상하게 처리해야될지 모르므로 -ㅅ-;;
각 함수마다 __stdcall을 이용하면되는데..

예를 들면
int __stdcall a(){}
와 같이 함수 선언부에 __stdcall를 붙이면 이 함수만 __stdcall 규약을 따르게 될 수 있다.

P.S. 보통 Windows API들이 __stdcall을 따른다.
그 이유는, Windows에서 제공하는 API들은 VC, VB, Delphi 등등의 프로그램에서 사용되어야 하므로 표준 규약인 __stdcall을 지키는것이며,
그래서 VC에서 Windows API들이 선언된 것을 보면 WINAPI 라고 된 것을 볼 수 있다.
이 WINAPI는 PASCAL 형이며, PASCAL은 _pascal 의 별칭이다.
(wtypes.h에 define 되어 있으며, pascal과 stdcall방식은 서로 같다. pascal방식은 caller가 stack을 삭제하는 것이다.)
이렇게 함으로써, 우리는 쥐도새도모르게(?) Windows에서 제공하는 API를 __stdcall이라는 키워드 없이 이용할 수 있는것이다.

아래는 돌아다니다가 주워온 자료이다.


http://www.vb-helper.com/howto_vcc_dll.html

Title Use VC++ to create a DLL file and use its functions in Visual Basic 6
Description
               
This example shows how to use VC++ to create a DLL file and use its functions in Visual Basic 6.
Keywords VC++, VCC, DLL, C++
Categories Software Engineering


I have found 2 methods to do this. The first makes the VC++ easier and the Visual Basic messier. The second makes the VC++ harder and the Visual Basic easier.
Method 1: Easy VC++, Hard VB
VC++: Invoke New\Projects\Win32 Dynamic-Link Library. Enter the directory where you want the VC++ project and the project name (MyFuncsProject in the example).
VC++: Invoke New\Files\C++ Source File. Check the Add To Project box. Enter the file name (MyFuncs.cpp in the example).
VC++: Enter the function's source code. Use __declspec (note the two underscores) to export the function's symbol. Use 'extern "C"' to minimize name mangling by VC++.

// Define DllExport to declare exported symbols.
#define DllExport __declspec( dllexport )

// Prototype the function.
// Use 'extern "C"' to minimize name mangling.
extern "C" DllExport long MyCFunc(long x);

// Define the function.
extern "C" DllExport long MyCFunc(long x)
{
        return x * x;
}
VC++: Set project options using Project\Settings. On the C/C++ tab, select the Code Generation category. Then change Calling Convention to __stdcall. VC++: Select Build\Set Active Configuration. Select the Release configuration. Repeat step 4 to make the options apply to the release configuration in addition to the debug configuration. Use Build\Set Active Configuration to reselect the debug configuration if desired.
VC++: Build the project (press F7 or use the Build menu). This creates the DLL file.
VB: In your Visual Basic program, declare the DLL function using the DLL file's full path name. The function's name in the DLL file has been slightly mangled by VC++. The name is an underscore, followed by the name you gave it, followed by "@", followed by the number of bytes in the function's argument list. In this example the name is _MyCFunc@4 because the function takes one 4 byte argument (a long integer).

Private Declare Function MyCFunc Lib _
"C:\VBHelper\VcDll\Method1\Release\MyFuncsProject.dll" _
Alias "_MyCFunc@4" _
(ByVal x As Long) As Long 

Private Sub Command1_Click()
    Dim x As Long
    Dim y As Long 

    x = CInt(Text1.Text)
    y = MyCFunc(x)
    Label1.Caption = Str$(y)
End Sub
*** HINT: To quickly determine the mangled name of the function, find the DLL file in Windows Explorer. Right click on the file and select the "Quick View" command. This presents an editor showing information about the DLL. Page down 2 or 3 pages and you will find a list of exported symbols available in the DLL. One of these will be the mangled function name.
VB: Run the program.



Method 2, Hard VC++, Easy VB
Steps 1 through 5 are the same as in Method 1.

VC++: New\Text File. Check the Add To Project box. Enter the file name. Give it a .DEF extension (MyFuncs.def in the example).
VC++: Enter definition file information that tells VC++ to export the function with the mangled name using the name you want it to have. The following code makes the exported name MyCFunc equivalent to _MyCFunc@4.

EXPORTS MyCFunc=_MyCFunc@4

VC++: Build the project (press F7 or use the Build menu). This creates the DLL file.
*** HINT: Use Quick View to verify the exported names. Find the DLL file in Windows Explorer. Right click on the file and select the "Quick View" command. Page down 2 or 3 pages and you will find a list of exported symbols available in the DLL. This includes both the mangled name and the name you specified in the .DEF file.
VB: In your Visual Basic program, declare the DLL function using the DLL file's full path name. Use the name you placed in the .DEF file not the mangled name.
Private Declare Function MyCFunc Lib _
"C:\VBHelper\VcDll\Method2\Release\MyFuncsProject.dll" _
(ByVal x As Long) As Long

Private Sub Command1_Click()
    Dim x As LongDim y As
    Long  x = CInt(Text1.Text)

    y = MyCFunc(x)
    Label1.Caption = Str$(y)
End Sub

댓글

이 블로그의 인기 게시물

80040154 오류로 인해 CLSID가 {xxxx-...}인 구성 요소의 COM 클래스 팩터리를 검색하지 못했습니다.

원문보기 .NET 으로 만든 응용프로그램에서 com 객체를 호출한 경우 Windows7 64bit 에서 제목과 같은 에러가 발생했다. Win32 COM 과 .NET 프로그램간의 호환성 때문에 생긴 문제였다. 원인은 .NET 실행시 JIT 컴파일러에 의해 최적화된 기계어로 변환되기 때문.. Win32 COM은 컴파일시.. Win32 COM에 맞춰 빌드 속성에서 하위버전으로 맞춰 컴파일을 다시하는 방법도 있지만 메인 프로젝트가 .NET이라면 참조되는 모든 프로젝트를 다 바꿔야할 노릇.. 또 다른 방법은 COM+를 이용하여 독립적으로 만드는 것이다. 분리시키는 방법은 아래 주소해서 확인할 수 있다. http://support.microsoft.com/kb/281335 나의 경우는 Win32 COM DLL을 64비트 .NET 프로그램에서 참조하니 COM 객체를 제대로 호출하지 못하였습니다. 그래서 .NET 프로그램의 Target Machine을 x86으로 설정하니 제대로 COM 객체를 호출하였습니다.

[Pyinstaller] 실행 파일 관리자 권한 획득하기

고객사에서 일부 사용자에게서 프로그램 오류가 발생한다며 아래와 같이 에러 캡처를 보내왔습니다. 프로그램에서 로그를 남기기 위해 로그 파일을 생성하는데 권한의 문제로 로그 파일을 생성하지 못해 프로그램 오류가 발생한 것 같습니다. 처음에는 Python 코드에서 관리자 권한을 요청하는 코드를 넣으려고 했는데, 실제로 Stackoverflow를 찾아보면 이런 내용이 나옵니다. 프로그램이 관리자 권한으로 실행되지 않았다면 관리자 권한으로 다시 프로그램을 실행시키는 코드입니다. import os import sys import win32com.shell.shell as shell ASADMIN = 'asadmin' if sys.argv[-1] != ASADMIN: script = os.path.abspath(sys.argv[0]) params = ' '.join([script] + sys.argv[1:] + [ASADMIN]) shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params) sys.exit(0) 하지만 개인적으로 이런 방식은 마음에 들지 않았고 조금 더 찾아보니 Pyinstaller로 exe 파일을 만들 때 옵션을 설정하여 관리자 권한을 요청하도록 할 수 있다고 합니다. --uac-admin을 옵션에 추가하면 프로그램 실행 시 관리자 권한을 요청할 수 있습니다. pyinstaller.exe --uac-admin sample.py 하지만 안타깝게도 이 방식은 원하는 대로 동작하지 않았습니다. 마지막으로 manifest 파일을 이용하여 시도해보았습니다. spec 파일을 이용하여 pyinstaller로 빌드하면 <실행 파일 이름>.manifest 라는 파일이 생성됩니다. 파일에서 아랫부분을 찾아볼 수 있습니다. <security> <re

초간단 프로그램 락 걸기

프로그램에 락을 걸 일이 생겨났다. 하드웨어 락을 걸면 쉬울텐데 그 정도는 아니고 프로그램의 실행 날짜를 제한 해 달라고 한다. 그래서 파일(license.lic)을 가지고 락을 걸리고 결정을 했다. 요구 사항은 아래와 같다. 1. license.lic 파일이 없으면 프로그램을 실행 할수 없게 한다. 2. 지정한 날짜를 넘어서는 프로그램을 실행 할수 없게 한다. 3. 사용자가 시스템 날짜를 되돌렸을때 인식하여 프로그램을 실행 할수 없게 한다. 음.... 1.번 문제는 사용자가 프로그램을 실행하기 위해서 license.lic 파일을 받아야만 한다. license.lic 파일에는 최근 실행 날짜/종료날짜 이런식으로 적도록 한다.(물론 내용은 암호화 한다.) 최근 실행날짜는 프로그램이 실행때마다 업데이트 하도록 하고 시스템 날짜와 비교하여 시스템 날짜가 최근 실행 날짜보다 이전의 날짜면 시스템 날짜를 되돌렸다고 인식하도록 한다.(3.번 문제 해결) 시스템 날짜와 종료 날짜를 비교하여 시스템 날짜가 종료 날짜를 넘으면 프로그램을 실행 할수 없도록 한다.(2.번 문제 해결)