문제
나의 창조 작업 ActiveX EXE 를 사용하여 VB6,그만의 예 나는 모든이며 델파이로 작성.
독서 예제 코드가 있는 어떤 기능을 누구의 서명은 다음 safecall 키워드입니다.예를 들어 다음과 같습니다.
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
의 목적은 무엇인가 이 키워드는?
해결책
Safecall 패스를 매개 변수는 오른쪽에서 왼쪽으로는 대신,파스칼 또는 등록부(기본값)왼쪽에서 오른쪽으로
와 safecall,절차 또는 기능을 제거에서 매개 변수는 stack 으로 돌아에(같은 파스칼은,하지만 다음과 같 cdecl 그것은 어디까지 발신자)
Safecall 를 구현하는 예외'방화벽';esp on Win32,이를 구현하는 프로세스 간 COM 오류를 알림.그것은 그렇지 않으면과 동일한 stdcall(다른 호출하는 데 사용되는 규칙으로 승리 api)
다른 팁
또한,방화벽 예외를 호출하여 작업 SetErrorInfo()함께하는 객체 지원 IErrorInfo,그래서는 발신자를 얻을 수 있는 확장된 정보에 대한 예외는 아니다.에 의해 이루어집 TObject.SafeCallException 재정 모두에서 TComObject 및 TAutoIntfObject.이러한 두 종류도를 구현하 ISupportErrorInfo 마이 사실이다.
의 경우에는 예외 safecall 메소드의 호출자를 쿼리할 수 있습 ISupportErrorInfo,다음는 쿼리를 위한 인터페이스에 그의 방법에서 결과 실패 는(높은 비트 세트),그리고 경우에는 반환합니다., GetErrorInfo() 를 얻을 수 있는 예외의 정보(대한 설명,도움,etc., 의 형태로 IErrorInfo 구현에 전달 SetErrorInfo() 에 의해 델파이 RTL 에 SafeCallException 재정의).
무엇을 말했다 Francois 고 그렇지 않았다면 safecall COM 메소드 호출은 것 같은 아래와 당신은 당신의 자신의 오류를 검사를 대신 받고 예외가 있습니다.
function AddSymbol(ASymbol: OleVariant; out Result: WordBool): HResult; stdcall;
COM 에서 모든 메소드가 반환하는 함수는 HRESULT
:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;
이것은 절대적으로 규칙에서 COM:
- 예외가 없 COM
- 모든 것을 반환하 는
- 부정적이외의 실패를 나타내
- 높은 수준에서 언어 장애에 매핑된 예외
그것은 기도의 COM 디자이너는 더 높은 수준 언어로 번역 실패 방법으로는 예외는 아니다.
그래서 자신의 언어,COM 호출로 표시되지 않외.E.g.:
- 델파이 같은:
function AddSymbol(ASymbol: OleVariant): WordBool;
- C#같은:
WordBool AddSymbol(OleVariant ASymbol);
델파이 당신을 사용하도록 선택할 수 있습니다.원수 서명:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;
처리하고 올리는 예외의 자신
bAdded: WordBool;
thingy: IThingy;
hr: HRESULT;
hr := thingy.AddSymbol('Seven', {out}bAdded);
if Failed(hr) then
OleError(hr);
또는 짧은 해당:
bAdded: WordBool;
thingy: IThingy;
hr: HRESULT;
hr := thingy.AddSymbol('Seven', {out}bAdded);
OleCheck(hr);
또는 짧은 해당:
bAdded: WordBool;
thingy: IThingy;
OleCheck(thingy.AddSymbol('Seven'), {out}bAdded);
COM 의도하지 않았를 처리하기 위해 Hresult
요청할 수 있습니다 하지만 델파이를 숨기는 배관에서 당신은,그래서 당신은에서 얻을 수 있습 프로그래밍:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant): WordBool); safecall;
end;
뒤에서는 컴파일러는 여전히 확인 는,및 던져 EOleSysError
예외는 경우에 는 표시량(i.e부정적이었).컴파일러에서 생성 safecall 버전이 기능적으로 동등하다:
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
var
hr: HRESULT;
begin
hr := AddSymbol(ASymbol, {out}Result);
OleCheck(hr);
end;
그러나 그것은 당신을 자유롭게 단순히 전화:
bAdded: WordBool;
thingy: IThingy;
bAdded := thingy.AddSymbol('Seven');
tl;박사:중 하나를 사용할 수 있습니다:
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
하지만 이전에 당신을 필요로 처리 Hresult 니다.
보너스 Chatter
당신은 거의 절대로 처리하려면 Hresult 자신;그것은 클러 프로그램으로는 아무것도 추가.그러나 때로는 너를 확인하려 는 자신(예:을 처리할에 실패하지 않는 아주 특별하).결코 버전의 델파이 시작되는 번역 Windows 헤더 인터페이스 선언을 모두 방법:
IThingy = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;
IThingySC = interface
['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
function AddSymbol(ASymbol: OleVariant): WordBool); safecall;
end;
나에서 RTL 소스:
ITransaction = interface(IUnknown)
['{0FB15084-AF41-11CE-BD2B-204C4F4F5020}']
function Commit(fRetaining: BOOL; grfTC: UINT; grfRM: UINT): HResult; stdcall;
function Abort(pboidReason: PBOID; fRetaining: BOOL; fAsync: BOOL): HResult; stdcall;
function GetTransactionInfo(out pinfo: XACTTRANSINFO): HResult; stdcall;
end;
{ Safecall Version }
ITransactionSC = interface(IUnknown)
['{0FB15084-AF41-11CE-BD2B-204C4F4F5020}']
procedure Commit(fRetaining: BOOL; grfTC: UINT; grfRM: UINT); safecall;
procedure Abort(pboidReason: PBOID; fRetaining: BOOL; fAsync: BOOL); safecall;
procedure GetTransactionInfo(out pinfo: XACTTRANSINFO); safecall;
end;
이 SC 접미사 스탠드 safecall.두 인터페이스가 동등하고,당신이 선택할 수 있는 선언하 COM 변수에 따라 당신의 욕망:
//thingy: IThingy;
thingy: IThingySC;
당신도 그들 사이:
thingy: IThingSC;
bAdded: WordBool;
thingy := CreateOleObject('Supercool.Thingy') as TThingySC;
if Failed(IThingy(thingy).AddSymbol('Seven', {out}bAdded) then
begin
//Couldn't seven? No sixty-nine for you
thingy.SubtractSymbol('Sixty-nine');
end;
추가 보너스 Chatter-C#
C#기본적으로는 해당 Delphi safecall, 를 제외하고,C#:
- 당신은 탈퇴의 safecall mapping
- 오히려 이상 선택에서
C#당신이 선언하 COM 인터페이스:
[ComImport]
[Guid("{357D8D61-0504-446F-BE13-4A3BBE699B05}")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IThingy
{
WordBool AddSymbol(OleVariant ASymbol);
WordBool SubtractSymbol(OleVariant ASymbol);
}
는 것을 알 수 있 COM HRESULT
가 숨겨져 있습니다.C#컴파일러,다음과 같은 델파이 컴파일러,자동으로 확인 반 는 던지는 예외에 대한 당신.
과에서는 C#에서와 같이,델파이,당신이 선택할 수 있습을 처리하 Hresult yourself:
[ComImport]
[Guid("{357D8D61-0504-446F-BE13-4A3BBE699B05}")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IThingy
{
[PreserveSig]
HRESULT AddSymbol(OleVariant ASymbol, out WordBool RetValue);
WordBool SubtractSymbol(OleVariant ASymbol);
}
이 [PreserveSig] 컴파일러를 보존하는 방법을 서명을 정확히 같다:
지 여부를 나타내는 관리되지 않는 방법이 있는 외 나 retval 반환 값은 직접 번역하거나 여부 외 나 retval 반환 값은 자동으로 변환하여 예외가 있습니다.