WinAPI/COMインタフェースの使用時の呼び出し規則

39789 ワード

背景:ネットで調べたところ、C#の呼び出し約束はstdcallだった.
前提:ここでのテストは主にC#プロジェクトの「ターゲットプラットフォーム」が「x 86」の場合、その他は具体的なテストがありません...
テスト環境:Win 7 64ビット、vs 2013はexe(C#、現在使用している.netバージョンは3.5)、VC 6はdllを作成します.
 
ZC:指定したC#一般関数呼び出し規則を表示する方法は調べられませんでした.しかし、私がデバッグしたとき、stdcallではありませんでした.
ZC:具体的には、ecxはthisポインタを格納し、edxは最初のパラメータを格納し、残りのパラメータは左から右に順にpushします.この呼び出しルールの名前は調べられませんでした...
ZC:C#でWinAPI/COMインタフェース関数を呼び出す場合、一見上の呼び出しルールでもありますが、さらに下位のcallについていくとパラメータを再編成してstdcallでWinAPI/COMインタフェース関数を呼び出すことがわかります.
 
1、exe(C#.netバージョンは3.5)
1.1、ComIntf.cs(インタフェース定義コードファイル)
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Runtime.InteropServices;
 5 using System.Text;
 6 
 7 namespace WindowsFormsApplication
 8 {
 9     [Guid("FCE9DCF3-9E38-441C-B10F-2BA31B57DCDC")]
10     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
11     public interface IntfTest
12     {
13         unsafe Int32 TestZ01(int _i, int _j, int _k, int* _piOut);
14         unsafe Int32 TestZ02(int _i, int _j, int _k, int _m, int* _piOut);
15         unsafe Int32 TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut);
16     }
17 }

1.2、インタフェースのテストコード:
 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.ComponentModel;
 5 using System.Data;
 6 using System.Drawing;
 7 using System.Runtime.InteropServices;
 8 //using System.Linq;
 9 using System.Text;
10 //using System.Threading.Tasks;
11 using System.Windows.Forms;
12 
13 namespace WindowsFormsApplication
14 {
15     public partial class Form1 : Form
16     {
17         public Form1()
18         {
19             InitializeComponent();
20         }
21 
22         private void button1_Click(object sender, EventArgs e)
23         {
24             //*
25             TdrSvgDll svgdll = new TdrSvgDll();
26             AAA(1, 2, 3); //    C# 
27             int kk = TestZZ(1, 2, 3, 4 ,5); //  DLL 
28 
29             TestCB(callback);
30             MessageBox.Show(Fhh.ToString());
31 
32             TRect rect = new TRect();
33             MessageBox.Show(Marshal.SizeOf(rect).ToString());
34 
35             ArrayList list = new ArrayList();
36             //list.[i];
37             //*/
38         }
39 
40         int AAA(int i, int j, int k)
41         {
42             return (i + j + k);
43         }
44 
45         //[DllImport("DLL_Z.dll", EntryPoint="TestZZ", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
46         [DllImport("DLL_Z.dll", EntryPoint = "TestZZ", CharSet = CharSet.Auto)]
47         public static extern int TestZZ(Int32 i, Int32 j, Int32 k, Int32 m, Int32 n);
48 
49         [DllImport("DLL_Z.dll", EntryPoint = "TestCB", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
50         public static extern void TestCB([MarshalAs(UnmanagedType.FunctionPtr)] Callback_Test01 _callback);
51 
52         //  
53         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
54         public delegate int Callback_Test01(int _i, int _j, int _k, int _m, int _n);
55 
56         public static int Fhh = 0;
57         //  
58         Callback_Test01 callback =
59             (i, j, k, m, n) =>
60             {
61                 Fhh = (i + j + k + m + n); //    
62                 //return (i + j + k + m + n);
63                 return Fhh;
64             };
65 
66         private void button2_Click(object sender, EventArgs e)
67         {
68             //  /  DLL 
69             IntfTest intfTest = null;
70             int iRtn = IntfTest_Get(ref intfTest);
71 
72             unsafe
73             {
74                 int iOut = 0;
75                 intfTest.TestZ01(1, 2, 3, &iOut);
76             }
77         }
78 
79         [DllImport("DLL_Z.dll", EntryPoint = "IntfTest_Get", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
80         public static extern int IntfTest_Get(ref IntfTest _intfTest);
81     }
82 }

 
 
2、VC6 -- DLL
2.1、DLL_Z.cpp
 1 // DLL_Z.cpp : Defines the entry point for the DLL application.
 2 //
 3 
 4 #include "stdafx.h"
 5 #include "zz.h"
 6 
 7 BOOL APIENTRY DllMain( HANDLE hModule, 
 8                        DWORD  ul_reason_for_call, 
 9                        LPVOID lpReserved)
10 {
11     return TRUE;
12 }
13 
14 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
15 //  
16 
17 extern "C" __declspec(dllexport) int __stdcall TestZZ(int i, int j, int k, int m, int n)
18 {
19     return (i+j+k+m+n);
20 }
21 
22 extern "C" __declspec(dllexport) void TestCC(int i, int j)
23 {
24 }
25 
26 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
27 // exe , 
28 
29 typedef int (__stdcall * Callback_Test01)(int, int, int, int, int);
30 
31 extern "C" __declspec(dllexport) void __stdcall TestCB(Callback_Test01 _callback)
32 {
33     if (_callback)
34     {
35         int i = _callback(1,2,3,4,5);
36     }
37 }
38 
39 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
40 //   interface,  exe 
41 
42 IntfTest *g_pIntfTest;
43 
44 extern "C" __declspec(dllexport) int IntfTest_Get(IntfTest **_ppIntfTest)
45 {
46     (*_ppIntfTest) = NULL;
47 
48     if ( NULL != g_pIntfTest )
49     {
50         //  "IntfTest*" ,C# , -1,∴ +1
51         //    "IntfTest*" , ,∴ +1
52         g_pIntfTest->AddRef();
53         (*_ppIntfTest) = g_pIntfTest;
54         return 0;
55     }
56 
57 // ***
58     IntfTest *pObj = new TintfTest();
59 
60     IUnknown *pIUnknown = NULL;
61     HRESULT hr = pObj->QueryInterface(IID_IUnknown, (void**)&pIUnknown);
62     pObj->Release();
63     pObj = NULL;
64 
65     if (FAILED(hr))
66     {
67         return -1;
68     }
69     else
70     {
71         hr = pIUnknown->QueryInterface(IID_IntfTest, (void**)&g_pIntfTest);
72         pIUnknown->Release();
73         pIUnknown = NULL;
74 
75         if (SUCCEEDED(hr))
76         {
77             (*_ppIntfTest) = g_pIntfTest;
78         }
79         else
80         {
81             return -2;
82         }
83     }
84     return 0;
85 }

2.2、
  1 #ifndef __zzz_2016__
  2 #define __zzz_2016__
  3 
  4 #include 
  5 
  6 // // {FCE9DCF3-9E38-441C-B10F-2BA31B57DCDC}
  7 static const IID IID_IntfTest =
  8 { 0xfce9dcf3, 0x9e38, 0x441c, { 0xb1, 0xf, 0x2b, 0xa3, 0x1b, 0x57, 0xdc, 0xdc } };
  9 
 10 
 11 interface IntfTest : public IUnknown
 12 {
 13     virtual HRESULT __stdcall TestZ01(int _i, int _j, int _k, int* _piOut) = 0;
 14     virtual HRESULT __stdcall TestZ02(int _i, int _j, int _k, int _m, int* _piOut) = 0;
 15     virtual HRESULT __stdcall TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut) = 0;
 16 };
 17 
 18 class TintfTest :public IntfTest
 19 {
 20 public:
 21     TintfTest();
 22 
 23 public:
 24     virtual HRESULT __stdcall TestZ01(int _i, int _j, int _k, int* _piOut);
 25     virtual HRESULT __stdcall TestZ02(int _i, int _j, int _k, int _m, int* _piOut);
 26     virtual HRESULT __stdcall TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut);
 27 
 28 private:
 29     long FlCount;
 30 public:
 31     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppv)
 32     {
 33         if (iid == IID_IUnknown)
 34         {
 35             *ppv = static_cast(this);
 36         }
 37         else if (iid == IID_IntfTest)
 38         {
 39             *ppv = static_cast(this);
 40         }
 41         else
 42         {
 43             *ppv = NULL;
 44             return E_NOINTERFACE;
 45         }
 46 
 47         AddRef();
 48 
 49         return S_OK;
 50     }
 51 
 52     virtual ULONG STDMETHODCALLTYPE AddRef()
 53     {
 54         return ++FlCount;
 55 
 56         //return InterlockedIncrement(&FlCount);
 57     }
 58 
 59     virtual ULONG STDMETHODCALLTYPE Release()
 60     {
 61         if (--FlCount == 0)
 62         {
 63             delete this;
 64             return 0;
 65         }
 66         return FlCount;
 67 
 68         //if (InterlockedDecrement(&FlCount) == 0)
 69         //{
 70         //    delete this;
 71         //    return 0;
 72         //}
 73         //return FlCount;
 74     }
 75 };
 76 
 77 TintfTest::TintfTest():
 78     FlCount(0)
 79 {
 80     this->AddRef();
 81 }
 82 
 83 HRESULT __stdcall TintfTest::TestZ01(int _i, int _j, int _k, int* _piOut)
 84 {
 85     *_piOut = (_i + _j + _k);
 86     return S_OK;
 87 }
 88 
 89 HRESULT __stdcall TintfTest::TestZ02(int _i, int _j, int _k, int _m, int* _piOut)
 90 {
 91     return S_OK;
 92 }
 93 
 94 HRESULT __stdcall TintfTest::TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut)
 95 {
 96     return S_OK;
 97 }
 98 
 99 
100 #endif // __zzz_2016__

2.3、Z.def
1 LIBRARY DLL_Z
2 EXPORTS
3 TestZZ
4 TestCC
5 TestCB
6 IntfTest_Get

 
3、
3.1、C#exe呼び出し普通のDLL導出関数
(1)、DLL導出関数TestZZ()に対して、指定呼び出し規則がstdcallであることを表示する、(2)、指定呼び出し規則を表示しない、
DLLのデバッグ追跡により、C#独自の呼び出し規則の下でstdcallを構築してTestZZを呼び出すことがわかります(...)
ZC:なぜDLLでアセンブリをデバッグするのですか.►C#でアセンブリを見てみると、C#の関数callしか見えず、DLLの関数callには入れません.F 11(文ごと)を押して更なる関数callに入ることができなくて、現れる効果はF 10(過程ごと)のようです
3.2、C#exe呼び出しDLLエクスポートのCOM型interface
C#独自の呼び出し規則の下でも、インタフェース関数を呼び出すためにstdcallを構築しているようです(C#のinterface宣言にはどの呼び出し規則を使用するか指定されていませんが)
 
4、
また疑問があれば、デバッグしてみましょう.VS 2013デバッグアセンブリ、VC 6 DLLデバッグアセンブリ、全部見てみましょう.
 
5、
 
転載先:https://www.cnblogs.com/csskill/p/5390818.html