Q&A

  • Calling Convention에 대해 아시는분 답변을 부탁
VC++에서 만든 dll을 호출시
CALLBACK 선언을 없애고(아래 예제 참고)
델파이에서

function EdrCenterText(hdc:HDC;prc:PRect;pString:PChar):boolean; cdecl; external 'EDRLIB.DLL';

라고 선언해야만 DLL 함수가 호출되거든요

cdecl선언만 호출되고 stdcall 인자를 넣으면 함수가 호출되지않는
이유를 몰라서 질문합니다.



////////////////헤더 선언부분 변경전///////////////////////
#ifdef __cplusplus
#define EXPORT extern "C" __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif

EXPORT BOOL CALLBACK EdrCenterTextA (HDC, PRECT, PCSTR) ;
EXPORT BOOL CALLBACK EdrCenterTextW (HDC, PRECT, PCWSTR) ;

#ifdef UNICODE
#define EdrCenterText EdrCenterTextW
#else
#define EdrCenterText EdrCenterTextA
#endif
///////////////////////////////////////////////////////////
////////////////헤더 선언부분 변경후///////////////////////
#ifdef __cplusplus
#define EXPORT extern "C" __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif

EXPORT BOOL  EdrCenterTextA (HDC, PRECT, PCSTR) ;
EXPORT BOOL  EdrCenterTextW (HDC, PRECT, PCWSTR) ;

#ifdef UNICODE
#define EdrCenterText EdrCenterTextW
#else
#define EdrCenterText EdrCenterTextA
#endif
///////////////////////////////////////////////////////////


When you declare a procedure or function, you can specify a calling convention using one of the directives register, pascal, cdecl, stdcall, and safecall. For example,

function MyFunction(X, Y: Real): Real; cdecl;
...

Calling conventions determine the order in which parameters are passed to the routine. They also affect the removal of parameters from the stack, the use of registers for passing parameters, and error and exception handling. The default calling convention is register.

The register and pascal conventions pass parameters from left to right; that is, the left most parameter is evaluated and passed first and the rightmost parameter is evaluated and passed last. The cdecl, stdcall, and safecall conventions pass parameters from right to left.
        For all conventions except cdecl, the procedure or function removes parameters from the stack upon returning. With the cdecl convention, the caller removes parameters from the stack when the call returns.

The register convention uses up to three CPU registers to pass parameters, while the other conventions pass all parameters on the stack.
        The safecall convention implements exception "firewalls." On Windows, this implements interprocess COM error notification.

The table below summarizes calling conventions.

Calling conventions
Directive        Parameter order        Clean-up        Passes parameters in registers?
register        Left-to-right        Routine        Yes
pascal        Left-to-right        Routine        No
cdecl        Right-to-left        Caller        No
stdcall        Right-to-left        Routine        No
safecall        Right-to-left        Routine        No
The default register convention is the most efficient, since it usually avoids creation of a stack frame. (Access methods for published properties must use register.) The cdecl convention is useful when you call functions from shared libraries written in C or C++, while stdcall and safecall are recommended, in general, for calls to external code. On Windows, the operating system APIs are stdcall and safecall. Other operating systems generally use cdecl. (Note that stdcall is more efficient than cdecl.)

The safecall convention must be used for declaring dual-interface methods. The pascal convention is maintained for backward compatibility. For more information on calling conventions, see Program control.
The directives near, far, and export refer to calling conventions in 16-bit Windows programming. They have no effect in 32-bit applications and are maintained for backward compatibility only.
7  COMMENTS
  • Profile
    정희섭 2002.10.22 02:03
    tdump edrlib.dll 을 실행한 결과 -stdcall 또는 CALLBACK 인경우



    Exports from EDRLIB.dll
      1 exported name(s), 1 export addresse(s).  Ordinal base is 1.
      Sorted by Name:
        RVA      Ord. Hint Name
        -------- ---- ---- ----
        0000100C    1 0000 _EdrCenterText@12

    tdump edrlib.dll을 실행한 결과 - cdecl 또는 인자없이 실행한 경우

    Exports from EDRLIB.dll
      1 exported name(s), 1 export addresse(s).  Ordinal base is 1.
      Sorted by Name:
        RVA      Ord. Hint Name
        -------- ---- ---- ----
        0000100C    1 0000 EdrCenterText


    결론은  함수 명이 바뀌어지네요 그래서 호출이 안되었던거 같습니다.
    광수님 답변이 맞네요.. 감사합니다. ^^
  • Profile
    이광수 2002.10.21 23:53
    우선 dependeny walker인데요. 좀 잘못알려드렸군요.

    vc++을 다 까셨다면 시작폴더에 등록된 것에 보시면

    Microsoft Visual Studio 6.0


    Microsoft Visual Studio 6.0 Tools
    이 있습니다.

    여기에 Depends 라는 프로그램이 있습니다.
    (이것이 Dependency walker입니다.)

    이걸을 실행해서 만드신 DLL파일을 로드해 보시면
    export된 펑션목록이 나오세 됩니다.

    이때 WINAPI나 CALLBACK을 쓰신 함수의 경우는 VC++의 룰에 의해서
    export될때 함수명에
    _와 끝에 @번호 가 붙게 된다는 말입니다.

    이 것을 바꿀수 있는 옵션이 VC++에 있었던 것으로 기억한다는 이야기
    이고요.

    저도 기억이 잘안나서 있는 지 확신이 안간다는 이야기 입니다.

    ------------------------------------------------------------
    참고로 말씀드리면 cdecl인 경우와 stdcall이 각기 call방식이 틀린데
    함수명이 같게 export되면 문제가 발생할수있으므로 vc++
    에서는 cdecl 을 export하면 기본적으로 같은 이름으로 export되고
    stdcall방식인 경우에는 export시 _와 @번호를 붙여서 문제의 소지를
    없애고 있는 것입니다.

    따라서 stdcall방식일때 _ 와 @0를 붙이고 싶지 않으시면 옵션을 조작하시면
    되는 걸로 알고 있다는 이야기 입니다.

    --------------------------------------------------------------
    MSDN에 나온 이야기에 따르면 다음과 같이 됩니다.
    Pascal형태로 바꿀순 없나봅니다. 이전의 16bit에서는 지원하는 것이
    현재는 없어진걸로 되어있습니다.


    INFO: Exporting PASCAL-Like Symbols in 32-Bit DLLs

    Q140485


    --------------------------------------------------------------------------------
    The information in this article applies to:

    Microsoft Visual C++, 32-bit Editions, versions 2.0, 2.1, 2.2, 4.0, 5.0, 6.0

    --------------------------------------------------------------------------------


    SUMMARY
    There is no _pascal keyword in the 32-bit editions of Visual C++. Instead the Windef.h header file has PASCAL defined as __stdcall. This creates the correct style calling convention for the function (the called function cleans up the stack) but decorates the function name differently. So, when __declspec(dllexport) is used (in a .dll file, for example), the decorated name is exported instead of the desired PASCAL style name, which is undecorated and all uppercase.



    MORE INFORMATION
    PASCAL name decoration is simply the undecorated symbol name in uppercase letters. __stdcall name decoration prefixes the symbol name with an underscore (_) and appends the symbol with an at sign (@) character followed by the number of bytes in the argument list (the required stack space). So, the function when declared as:


       int  __stdcall func (int a, double b) is decorated as:

       _func@12 The C calling convention (__cdecl) decorates the name as _func. Whereas the desired PASCAL style name is FUNC.

    To get the decorated name set the Generate Mapfile option in the Linker General category setting.

    Use of __declspec(dllexport) does the following:
    If the function is exported with C calling convention (_cdecl), it strips the leading underscore (_) when the name is exported.


    If the function being exported does not use the C calling convention (for example, __stdcall ), it exports the decorated name.


    So to simulate PASCAL name decoration and calling conventions, you must have the "Called Function stack clean-up" provided by using __stdcall and the undecorated uppercase name.

    Because there is no way to override who does the stack clean up, you must use __stdcall. To undecorate names with __stdcall, you must specify them by using aliases in the EXPORTS section of the .def file. This is shown below for the following function declaration:

       int  __stdcall MyFunc (int a, double b);
       void __stdcall InitCode (void); In the .def file:

       EXPORTS
          MYFUNC=_MyFunc@12
          INITCODE=_InitCode@0 For .dll files to be called by programs written in the 32-bit versions of Visual Basic (versions 4.0 and above), the alias technique shown in this article is needed in the .def file. If alias is done in the Visual Basic program, use of aliasing in the .def file is not necessary. It can be done on the Visual Basic program by adding an Alias clause to the Declare statement as shown here:

    Declare Function MyFunc Lib "dlllibname" Alias "_MyFunc@12"  (...)
       As Integer The complete syntax for the Visual Basic Declare statement follows:

       [Public | Private ] Declare Function name Lib
       "libname" [Alias "aliasname" ] [([arglist])][As type] References
    For more information, query the MSDN compact disc using these keywords:
    VB alias DLL
    NOTE: A very good discussion (with example code) of calling a C .dll file from Visual Basic can be found in the file Vb4dll.txt in the Visual Basic directory. If you can not locate the Vb4dll.txt file, please see the following article in the Microsoft Knowledge Base:
    Q150705 SAMPLE: Using VB4DLL.txt File to Develop .dlls for Visual Basic

    Additional query words: 9.00 9.10 PASCAL declspec VB DLL _stdcall

    Keywords : kbCompiler kbVC200 kbVC210 kbVC220 kbVC400 kbVC500 kbVC600
    Issue type : kbinfo
    Technology : kbvc


    Last Reviewed: February 4, 2000
    © 2001 Microsoft Corporation. All rights reserved. Terms of Use.


  • Profile
    이광수 2002.10.21 20:23
    VC++에서 Dependency walker로 보시면 이해가 가실겁니다.
    dll을 열어보시면요.

    즉 cdecl로 컴파일하시면 함수명이
    EdrCenterTextA 이 되지만

    WINAPI나 CALLBACK선언으로 만드시면

    _EdrCenterTextA@0 이 됩니다. ^^;

    제가 알기로는 이것은 VC++에 옵션에 고칠수 있는 것으로 아는데요.
    확신이 없네요 ^^

    확인해 보시길 바랍니다.




  • Profile
    정희섭 2002.10.21 21:00
    자꾸 질문해서 미안합니다.
  • Profile
    타락천사 2002.10.21 20:12
    안녕하세여. 타락임다..

    흘흘.. 어려운 질문 이군여..^^
    주로 DLL 을 쓸때(호환 문제에) 필요한 사항 들 입니다. 또한 C++ Builder 와 Delphi 로 함께 개발 할 때 호환성 문제로 신경써야 할때 필요한 사항 입니다.


    *** 호출 규칙(Calling Canvention)

    일반적으로 safecall 로 대부분 처리 됩니다. 먼저 safecall 설명 부터..

    COM이나 예외 처리에 관련된 DLL의 루틴은 safecall 지시자를 사용해야 함다. COM 이나 DLL 함수 호출에서 중요한 건 함수에서 발생한 예외를 델파에서 받아야 하며, 델파이에서 발생한 예외를 COM 이나 DLL 함수로 넘겨 주는 것 입니다.

    Safecall 지시자로 루틴을 선언하면 예외를 호출한 프로세스에 전달할 수 있슴니다. Safecall 지시자는 델파이 예외를 HResult 리턴값으로 변환하며, 묵시적으로 StdCall 호출 규약을 지정함다. 즉 safecall 은 stdcall 에 HResult 처리가 추가된 것이라고 할수 있겠습니다.


    예를 들어, 다음과 같은 함수 선언을 보자.
    fuction Foo(i: Integer): string; Safecall;

    컴파일러는 위의 선언을 다음과 같은 형태로 이해한다.
    fuction Foo(i: Integer): string; HResult; StdCall;

    그리고 컴파일러는 묵시적으로 함수 전체를 try..except 블록으로 감싸서 예외를 잡아낸다. 또한, except 블록 안에 SafecallExceptionHandler()를 호출해서 예외를 HResult값으로 변환하는 코드를 집어넣는다. 16비트 시절, 개발자가 직접 예외를 잡아내고 에러 번호를 돌려주던 것을 컴파일러가 대신 해주는 셈이다.


    다음으로 글 쓰는 김에 호출에 대한 좀더 설명을 하죠.

    C, Pascal, Register 호출 규칙은 각기 스택 클린업, 파라미터 순서, 대소 문자, 전연 명칭의 위치 등이 각기 다릅니다. 파라미터들은 호출 규칙에 따라 CPU Register And/Or Stack 을 통해 프로시저와 함수에 전달되는 방식이 달라짐다.

                       파라미터 호출순서   Clean-up        Register    Name 변경 사항
    register         Left-to-right            함수                  Yes      
    pascal          Left-to-right            함수                  No       대문자
    cdecl            Right-to-left            Caller               No        '_' 가 앞에 붙음
    stdcall          Right-to-left            함수                  No        변경없슴
    safecall        Right-to-left            함수                  No        변경없슴


    C, C++, Pascal, Assembly 는 각기 다른 호출 방식을 가집니다.
    C++ 은 name-mangling 을 취함다. Assembly 는 스텍에 Push 하고 Pop 해서 얻는 단순한 방법을 사용함다. Pascal 은 Top-down 방식으로 인자를 정함다. 반면에 C 는 Pascal 과는 반대로 스택 위에 저장함다.

    볼랜드 개발자 들은 최적화 코드를 생성하려면 스택에 인자를 저장하는 방식보다는 레지스터를 경유하는 방식이 훨씬 빠르다는 것을 발견했담미다. 그래서 나온 것이 pascal 임다. 그러나 C++ 컴파일러에 의한 name-mangling 문제와 부딧쳤습니다. 일반적으로 C 코드의 cdecl 과 함께 꼬여진 name 을 구별하지 못함다. 이때는 stdcall 을 사용해야 함다.

    이런 문제들은 COM 이나 DLL 의 함수를 만들때 어떻게 호출했느냐에 관련이 있습니다.
  • Profile
    정희섭 2002.10.21 21:06
    답변 감사드립니다.

    VC++ DLL에서 CALLBACK 대신에 __stdcall 로 선언하고
    델파이에서 stdcall로 바꾸어서 선언하면
    호출이 안되거든요.

    호출되는 조건은  VC++에서 함수앞에 __cdecl 선언하거나 함수명만 적어은다음 델파이에서 cdcel을 선언해야만 호출이 가능하네염

    에구 어려워랑..
  • Profile
    타락천사 2002.10.21 22:36
    안녕하세여. 타락임다..

    VC++ DLL 써본지가 오래되서, 기억이 잘 안납니다..

    앞의 코드에선 CALLBACK 을 빼면 안되는것 같습니다.

    그리고 CallBack 함수라서 cdecl 로 호출되는 것으로 보입니다..

    기억이 안나지만, 전에 제가 개발할 때는 VC++ 의 DLL 선언에서 export 를 다르게 했던것 같습니다.

    제가 시러하는 분야라.. 별 도움을 못드려 죄송합니다.

    www.borlandforum.com 에 질문하면 해답이 나올지도 모르겠습니다.

    즐푸하세여..

    타락천사..
    • 샤리
    • 2002.10.21 21:50
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 전종표
      2002.10.21 22:09
      델7에 보면 Indy 가 있습니다.  그걸로 대체되었습니다. Indy 의 데모는 델설치프로그램에 ...
    • 김해성
    • 2002.10.21 21:08
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 전종표
      2002.10.21 21:59
      SpeedButton 은 DataSet 과 연결할 수 없습니다. 따라서 OnClick 에 직접 프로그램을 넣으셔야 합니다....
    • 김해성
      2002.10.21 22:38
      Button과 연결할려면 어떻게 해야돼여?
    • 이치영
    • 2002.10.21 20:58
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 전종표
      2002.10.21 21:16
      ---- unit2.pas ...    function PumSearch(cFileNo:string): TClientDataSet; functi...
    • 2002.10.21 20:28
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 전종표
      2002.10.21 20:59
      DB 의 EOF 를 모르는게 아닌가 싶네요.  그냥 DB 만 연결해서 출력한 것 같진 않고,  ...
    • 2002.10.21 23:41
      질문에 대한 답변 감사 드립니다. 데이터를 앞으로 옮기는 작업이 어떤것을 말하는지 잘 몰라서 이렇게 ...
    • 김기성
    • 2002.10.21 20:11
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 타락천사
      2002.10.21 20:16
      DelForEx 란게 있습니다. 자료실을 검색해 보심 나올겁니다. 즐푸하세여.. 타락천사.
    • 정희섭
    • 2002.10.21 19:25
    • 7 COMMENTS
    • /
    • 0 LIKES
    • 정희섭
      2002.10.22 02:03
      tdump edrlib.dll 을 실행한 결과 -stdcall 또는 CALLBACK 인경우 Exports from EDRLIB.dll  ...
    • 이광수
      2002.10.21 23:53
      우선 dependeny walker인데요. 좀 잘못알려드렸군요. vc++을 다 까셨다면 시작폴더에 등록된 것에 보시...
    • 이광수
      2002.10.21 20:23
      VC++에서 Dependency walker로 보시면 이해가 가실겁니다. dll을 열어보시면요. 즉 cdecl로 컴파일하시...
    • 정희섭
      2002.10.21 21:00
      자꾸 질문해서 미안합니다.
    • 타락천사
      2002.10.21 20:12
      안녕하세여. 타락임다.. 흘흘.. 어려운 질문 이군여..^^ 주로 DLL 을 쓸때(호환 문제에) 필요한 사항 ...
    • 정희섭
      2002.10.21 21:06
      답변 감사드립니다. VC++ DLL에서 CALLBACK 대신에 __stdcall 로 선언하고 델파이에서 stdcall로 바꾸...
    • 타락천사
      2002.10.21 22:36
      안녕하세여. 타락임다.. VC++ DLL 써본지가 오래되서, 기억이 잘 안납니다.. 앞의 코드에선 CALLBACK...
    • 김장호
    • 2002.10.21 12:55
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 타락천사
      2002.10.22 03:51
      안녕하세요. 타락임다.. 아마 Canvas 에는 회전된 그림이 있을 겁니다.. TBitmap 을 선언해서.. C...
    • 박상윤
      2002.10.21 19:25
      24비트 RGB (8bit,8bit,8bit) 16-5,5,5    -5,6,5 포맷 2가지입니다.    그럼 여...
    • 나윤호
    • 2002.10.21 05:06
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 타락천사
      2002.10.21 20:46
      안녕하세여. 타락임다.. ActiveForm Paint 이벤트가 점 문제가 있나여? 그럼 ActiveForm 크기에 해당...
    • 나윤호
      2002.10.21 23:50
      activeX콘트롤 말하는거 맞는데요....델파이에서 acitveFrom이라구 되어있잖아요....일반 애플로 했던것을 ...
    • 롯데
    • 2002.10.21 04:00
    • 4 COMMENTS
    • /
    • 0 LIKES
    • 타락천사
      2002.10.21 20:24
      안녕하세여. 타락임다.. 아래는 제가 팁에 올린 Directory&File Delete/Move/Rename 함수 임다. /...
    • 정성훈
      2002.10.21 19:47
      팁에서 가져온 자료입니다. 참조하세요..(하위폴더까지 복사함..) 디렉토리 단위로 복사하는 재귀호출 ...
    • 롯데
      2002.10.21 21:32
      답변 감사합니다. 코드를 아래와 같이 고치면 조금 더 낫군요..  너무 감사합니다.  ...
    • 롯데
      2002.10.21 21:48
      아참.. 그리고 while 문 블럭 다음에 반드시 아래 코드를 써주셔야 할 것 같습니다. 감사합니다. &nbs...
    • 타락천사
      2002.10.21 18:51
      안녕하세요. 타락임다. 보아하니 Win2K 에서 Virtual SMTP Server 를 활용해서 메일을 발송하려는가 보...
    • 김세형
    • 2002.10.21 01:10
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 김세형
      2002.10.22 11:15
      질문이 너무 막연했었습니다. 자답으로 올릴께여~ 쓰래드의 Synchronize 함수로 해결했습니당~ ^^;; ...
    • 타락천사
      2002.10.22 02:01
      안녕하세여.. 타락임다.. Canvas 는 ThreadSafe 합니다.. Canvas.Lock 과 Canvas.UnLock 을 쓰세여.....
    • 이영동
    • 2002.10.20 22:28
    • 1 COMMENTS
    • /
    • 0 LIKES
    • *^^*
      2002.10.21 02:44
          필드 선택하시고, 프로퍼티 보면     "DisplY Format" 에다...
    • 김종균
    • 2002.10.20 21:03
    • 5 COMMENTS
    • /
    • 0 LIKES
    • 정성훈
      2002.10.21 19:40
      strout := inttostr(strtoint(strout) * 500); 이부분이죠? 날짜 * 500억씩 ㅡ.ㅡ 아래 Lookup 설명한...
    • 정경철
      2002.10.20 21:25
      lockup field가 아님니다.. 죄송 합니다. Calculated Field를 만들어서 날자와 연체료를 계산하면 될것...
    • 정경철
      2002.10.20 21:20
      lockup Field 를 만들어서 해보세요..
    • 김종균
      2002.10.20 22:26
      lockup Field가 먼지 모르거든여.. 답변부탁드립니다. 좋은 하루되세요
    • 정성훈
      2002.10.21 19:29
      어떤 한 필드의 값의 정보를 다른테이블에 있는것과 비교해서 필요한 필드를 가져오는 것입니다. 예를 ...
    • 호현수
    • 2002.10.20 09:48
    • 3 COMMENTS
    • /
    • 0 LIKES
    • 김태훈
      2002.11.22 07:23
      공유기 같은 걸로 물린 경우 사설아이피를 할당받아서 쓰게됩니다. 클래스에 따라 할당된 아이피가 다름...
    • 타락천사
      2002.10.21 18:45
      안녕하세여. 타락임다.. 내부 IP 는 임의로 할당할 수 있습니다. 따라서 외부IP 와 같이 부여 할 수도 ...
    • 호현수
      2002.10.22 16:07
    • 타락천사
      2002.10.21 20:39
      안녕하세여. 타락임다.. 우선 다른 여러대의 컴퓨터에서 실행시켜 봅니다. 만약 델파이가 깔려 있는 컴...
    • 이영동
    • 2002.10.20 05:18
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 이영범
      2002.10.21 19:04
      코딩으로 하는 방법은... TQuery의 AfterOpen 이벤트에 아래와 같이 써주시면 됩니다. TNumericField...
    • 정경철
      2002.10.20 21:29
      방법은 여러가지가 있겠지만 제가 주로 사용 하는 방법은 테이블을 더블 클릭 하여 표시될 필드를 선택 하...