سؤال

لدي حالة عمل حيث أحتاج إلى أن أكون قادرا على تحديد اتفاقية الاتصال الخاصة بي عند استخدام P / Invokook. على وجه التحديد، لدي DLL Langacy يستخدم ABI غير قياسي، وأحتاج إلى تحديد اتفاقية الاتصال لكل وظيفة.

على سبيل المثال، تقبل وظيفة واحدة في هذا DLL أول حجتين لها عبر EAX و EBX، مع بقية عبر المكدس. تعمل وظيفة أخرى حجة واحدة عبر ECX، مع البقية على المكدس. لدي بضع مئات من هذه الوظائف، وأود تجنب كتابة DLL جسر الوسيط الخاص بي من أجل الوصول إلى هذه الوظائف.

خياري الآخر سيكون يدويا لفة بلدي مخصص P / استدعاء، وهو أمر غير مرغوب فيه لأسباب واضحة.

نقدر اي مساعدة، شكرا،

هل كانت مفيدة؟

المحلول

أنا لا أفهم ما تقصده مع مخصص 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.getDelegateFrefunderPointer) لتنبعث طريقة جديدة P / Invoke لطريقة الروتين العارية الخاصة. إنه يعمل على إصلاح المعلمات ثم يستدعي الطريقة في الواقع.

هنا هو رمز C. ليس لدي جزء C # مفيد :( كنت أتعلم المجمع أيضا في ذلك الوقت حتى يتمتص الكود :)

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