문제

P/Invoke를 사용할 때 내 자신의 통화 규칙을 지정할 수 있어야하는 비즈니스 사례가 있습니다. 구체적으로, 비표준 ABI를 사용하는 레거시 DLL이 있으며 각 기능에 대한 호출 규칙을 지정할 수 있어야합니다.

예를 들어,이 DLL의 한 기능은 EAX와 EBX를 통해 처음 두 인수를 허용하며 나머지는 스택을 통해 수용합니다. 다른 함수는 ECX를 통해 하나의 인수를 수락하고 나머지는 스택에 있습니다. 이 기능이 수백 개의 기능을 가지고 있으며 이러한 기능에 액세스하기 위해 내 자신의 중간 브리지 DLL을 쓰지 않기를 원합니다.

내 다른 옵션은 내 자신의 Custom P/Invoke를 수작업하는 것입니다. 이는 명백한 이유로 바람직하지 않습니다.

도움을 주셔서 감사합니다. 감사합니다.

도움이 되었습니까?

해결책

Custom P/Invoke의 의미를 이해하지 못하지만 인라인 어셈블리로 관리되지 않는 C ++없이 어떻게 도망 칠 수 있는지 알 수 없습니다. 그러나 거의 모든 것이 32 비트 값으로 전달되므로 함수 당 하나에 적용되는 각 기능 서명에 대해 하나의 프록시 만 작성하는 것이 멀어 질 수 있습니다. 또는 XML에서 프록시를 생성하는 코드 생성기를 작성할 수 있습니다. 모든 프록시 기능이 정말 간단하기 때문에이 버전이 너무 바람직하지 않다는 것을 알 수 없습니다.

int RealFunction(int param1, const char * param2, char param 3);

int MyFunction(int param1, int param2, int param3) { // argument types do not matter as long as they are not doubles or structures
   __asm {
      mov eax, param1
      mov ebx, param2
      push param3
      call RealFunction
      ; depending on calling convention, you might need to do add esp, 12 here
      ; if RealFunction does not return its result in eax, you will need to do mov eax, <wherever the return value is> here
   }
}

다른 팁

별도의 DLL없이 원하는 것을 성취하는 방법이 내장되어 있다고 확신합니다. 런타임 시스템이 지원하는 것 이외의 통화 규칙을 지정하는 방법을 보지 못했습니다.

나는 컨벤션에 전화를 걸어 전화에 대해 배우고 전화를 걸기위한 몇 가지 코드를 썼습니다. 이 코드는 특수 C# 래퍼에서 호출되며, 래퍼 라이브러리는 반사 방출을 사용하여 (Marshal.getDelegateForfunctionPointer 작동 할 수 없음) 특수 알몸 스텁 방법에 대한 새로운 P/호출 방법을 방출합니다. 매개 변수를 수정 한 다음 실제로 메소드를 호출합니다.

다음은 C 코드입니다. 나는 c# part handy가 없다 :( 나는 그 당시 어셈블러를 배우고 있었기 때문에 코드가 빨라질 수있다 :)

typedef struct
{
    USHORT ParameterOneOffset;  // The offset of the first parameter in dwords starting at one
    USHORT ParameterTwoOffset;  // The offset of the second parmaeter in dwords starting at one
} FastCallParameterInfo;



    __declspec( naked,dllexport ) void __stdcall InvokeFast()
{
    FastCallParameterInfo paramInfo;
    int functionAddress;
    int retAddress;
    int paramOne, paramTwo;
    __asm
    {
        // Pop the return address and parameter info.  Store in memory.
        pop retAddress;
        pop paramInfo;
        pop functionAddress;

        // Check if any parameters should be stored in edx                          
        movzx ecx, paramInfo.ParameterOneOffset;     
        cmp ecx,0;
        je NoRegister;  

        // Calculate the offset for parameter one.
        movzx ecx, paramInfo.ParameterOneOffset;    // Move the parameter one offset to ecx
        dec ecx;                                    // Decrement by 1
        mov eax, 4;                                 // Put 4 in eax
        mul ecx;                                    // Multiple offset by 4

        // Copy the value from the stack on to the register.
        mov ecx, esp;                               // Move the stack pointer to ecx
        add ecx, eax;                               // Subtract the offset.
        mov eax, ecx;                               // Store in eax for later.
        mov ecx, [ecx];                             // Derefernce the value
        mov paramOne, ecx;                          // Store the value in memory.

        // Fix up stack
        add esp,4;                                  // Decrement the stack pointer
        movzx edx, paramInfo.ParameterOneOffset;    // Move the parameter one offset to edx
        dec edx;                                    // Decrement by 1
        cmp edx,0;                                  // Compare offset with zero
        je ParamOneNoShift;                         // If first parameter then no shift.

    ParamOneShiftLoop:
        mov ecx, eax;
        sub ecx, 4;
        mov ecx, [ecx]
        mov [eax], ecx;                             // Copy value over
        sub eax, 4;                                 // Go to next 
        dec edx;                                    // decrement edx
        jnz ParamOneShiftLoop;                      // Loop
    ParamOneNoShift:
        // Check if any parameters should be stored in edx                          
        movzx ecx, paramInfo.ParameterTwoOffset;     
        cmp ecx,0;
        je NoRegister;  

        movzx ecx, paramInfo.ParameterTwoOffset;    // Move the parameter two offset to ecx
        sub ecx, 2;                                 // Increment the offset by two.  One extra for since we already shifted for ecx
        mov eax, 4;                                 // Put 4 in eax
        mul ecx;                                    // Multiple by 4

        // Copy the value from the stack on to the register.
        mov ecx, esp;                               // Move the stack pointer to ecx
        add ecx, eax;                               // Subtract the offset.
        mov eax, ecx;                               // Store in eax for later.
        mov ecx, [ecx];                             // Derefernce the value
        mov paramTwo, ecx;                          // Store the value in memory.           

        // Fix up stack
        add esp,4;                                  // Decrement the stack pointer
        movzx edx, paramInfo.ParameterTwoOffset;    // Move the parameter two offset to ecx
        dec edx;                                    // Decrement by 1
        cmp edx,0;                                  // Compare offset with zero
        je NoRegister;                              // If first parameter then no shift.
    ParamTwoShiftLoop:
        mov ecx, eax;
        sub ecx, 4;
        mov ecx, [ecx]
        mov [eax], ecx;                             // Copy value over
        sub eax, 4;                                 // Go to next 
        dec edx;                                    // decrement edx
        jnz ParamTwoShiftLoop;                      // Loop


    NoRegister:
        mov ecx, paramOne;                          // Copy value from memory to ecx register
        mov edx, paramTwo;                          // 
        push retAddress;
        jmp functionAddress;
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top