2012-06-04 3 views
1

JNA을 사용하여 델파이 DLL에서 함수를 호출하려고합니다. 함수 정의는 다음과 같습니다jna 핸들 및 문자열에서 delphi/pascal dll 함수 매핑

function myFuncGetName (aHandle : THandle; var aBuf : pwideChar): integer; export; 

내 JNA 매핑은 다음과 같습니다

int myFuncGetName(PointerByReference aHandle, WString aBuf); 

반환 값은 실패에 대한 성공 0과 -1이어야하며 항상 -1을 얻고있다.

WinDbg을 시작하고 프로세스에 연결하면 myFuncGetName에서 중단됩니다.

057cb384 eb11   jmp  myDLL!myFuncGetName+0x87 (057cb397) 
057cb386 b8dcb37c05  mov  eax,offset myDLL!myFuncGetName+0xcc (057cb3dc) 
057cb38b 8b55f8   mov  edx,dword ptr [ebp-8] 
057cb38e 8902   mov  dword ptr [edx],eax ds:002b:00000000=???????? <-- ### breaks here ### 
057cb390 c745f4ffffffff mov  dword ptr [ebp-0Ch],0FFFFFFFFh 

저는 조립 문제가 아니므로 어디에서 제가 틀렸는 지 수정하십시오. 주소 (함수 인수)를 ebp-8 위치에서 edx 레지스터로 이동한다고 생각합니다. edx가 0이되도록 ebp-8이 값 0을 가리킴. edx가 가리키는 주소로 eax를 이동합니다. 0을 움직여서 모든 것이 깨지지 않도록해야하나요?

내 인수가 함수에 올바르게 전달되지 않는 이유는 무엇입니까? 이전 호출과 동일한 DLL에서 aHandle을 얻었으므로 aBuf를 으로 설정합니다. WString aBuf = 새 WString ("placeholderstring"); 함수가 반환 된 후 aBuf가 실제 텍스트로 채워질 것으로 예상합니다.

이것은 모두 Java 7 64 비트가 설치된 Windows 7에서 실행됩니다. DLL은 32 비트 DLL입니다.

UPDATE 및 솔루션 :

당신의 의견을 당신에게 다윗과 롭 감사드립니다. Delphi 정의를 stdcall 선언을 사용하도록 변경했습니다. 함수를 호출하면 이제 0을 반환합니다. (내 생각)

int charcount= "placeholder".length(); 
PointerByReference aBuf = new PointerByReference(new Memory(charcount*4)); 
int returnvalue = myFuncGetName(aHandle, aBuf); 
if(returnvalue == 0) { 
    System.out.println(aBuf.getValue().getString(0, true)); 
} 
+0

이것이 실제로 기계 코드 인 경우 첫 번째 행만 관련됩니다. 그것은 057cb397을 처리하기 위해 4 개의 연속 라인을 넘어서 점프. 더 보여주세요. –

+0

당신 말이 맞습니다. 저것을 보지 못했습니다. 진술을 뛰어 넘기 위해 어떤 일이 일어나거나 진입 점이 그 아래에 있어야합니다. 왜냐하면 디버거는 두 번째 행에서 마지막 행으로 분리되기 때문입니다. 방금 디버거가 중단 된 부분을 명확하게하기 위해 다시 편집했습니다. – Alex

답변

4

이것이 DLL 함수의 실제 선언이라면 문제는 호출 규칙이 될 수 있습니다. Delphi의 기본 호출 규칙은 register이며 EAX 및 EDX의 처음 두 인수를 저장하지만 기본 C 호출 규칙은 cdecl이며이를 스택에 저장합니다. 여기에 델파이 선언을 변경합니다

function myFuncGetName(aHandle: THandle; var aBuf: PWideChar): Integer; stdcall; 

(당신이 그것을 제거 할 수 있도록 정말) 델파이 2의, 나는 생각 (더 이상 아무것도하지 않습니다 export 지시어가 exports 절에 의해 포섭되어있어있다. DLL 소스의 다른 곳에서 찾아야합니다.)

Java 측도 잘못되었습니다.Delphi 코드의 두 번째 매개 변수는 부터 PWideChar까지입니다. JNA에 WStringByReference 유형이 표시되지 않지만 필요한 내용입니다. 그래도 직접 구현하는 방법에 대한 조언은 드릴 수 없습니다.

+0

JNA에서 cdecl이 없습니다. 마지막 단락의 결론은 반드시 정확하지는 않습니다. 네, 자바 측은 틀릴 수도 있지만 델파이 측도 그렇습니다. 묻는 사람이 자바를 가장 잘 알고 있기 때문에 후자가 될 것입니다. 어떤 경우에는 서명이 내 대답의 매개 변수 2와 같을 것입니다. –

+1

@David,'Library'와 그 자손'StdCallLibrary'의 존재는 Java가 어느 관례의 함수를 호출 할 수 있음을 나타냅니다. Java 코드는 DLL 함수가 참조로 PWideChar를 사용한다는 질문에 제공된 정보의 컨텍스트에서 잘못되었습니다. DLL이 잘못된 경우 DLL에 대한 정보가없는 DLL 작업에 대한 사양 컨텍스트에있는 것입니다. 내가 DLL을 치료하려고 노력하고있어 주어진이며, 그것은 그것을 소비하는 자바 프로그래머의 일이야. 나쁜 컨벤션은 고정 된 DLL 쪽이어야합니다. 유형은 Java 측에서 고정 될 수 있습니다. –

1

당신은 규칙을 호출 stdcall을 사용해야하며, 문자열 매개 변수가 잘못 선언 다음 PWideChar로의 값을 검색하려면 나는 다음을했다. export 키워드는 더 이상 사용되지 않으며 생략 될 수 있습니다. 라이브러리 코드의 다른 위치에있는 exports 키워드로 내보내기의 이름을 지정하십시오.

귀하의 델파이 함수는 이와 같아야합니다.

function myFuncGetName(aHandle: THandle; aBuf: pwideChar): integer; stdcall; 

PointerByReference에 대해 확실하지 않습니다. 이것이 void **와 같은 경우 THandle에 매핑하는 이유는 무엇입니까?

+0

맞아요, PointerByReference가 잘못되었습니다. int는 잘 작동합니다. 내가 왜 일들이 작동하지 않는지 테스트했기 때문에 델파이에서 추기경 (declinal int) 인 것으로 선언되어 Java에서 문제를 일으킬 것이라고 생각했기 때문에 거기에있었습니다. 내 손잡이가 어느 시점에서 올바르지 않다고 생각했습니다. – Alex

+0

내 대답이 도움이되지 않아서 죄송합니다. –