Bonjour,

Mon problème est le suivant :
- J'ai une DLL en C++ qui est appelée par une application en C#, un pointeur de fonction sur une callback est passé lors de cet appel (ceci afin de pouvoir gérer une fonction de progress dans l'application en C#).
- Il semble que tout soit OK, seulement lors de l'appel de la fonction de callback par la DLL, une erreur est générée.

Il semblerait que le prototype de la fonction de callback soit faux, dans l'appli en C#, voici la partie de source code incriminée :

Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
{
// callback prototype
public unsafe delegate int PROGRESSCALLBACK( int reader, void* pUserData, int progress, int status );
// C++ DLL function called
[DllImport( "ePerso.dll" )] public static extern unsafe int ePersoRead( int iReader, int iBlock, [MarshalAs( UnmanagedType.FunctionPtr )] PROGRESSCALLBACK pFnCallBack, void* pUserData, ref int piSize, char* pDG );
 
//callback function
private int ReadProgress( int reader, void * pUserData, int progress, int status )
{
try
{
if ( reader == READER1 ) SetStatusRead( reader, ref toolStripStatusLabelReader1, progress, status );
if ( reader == READER2 ) SetStatusRead( reader, ref toolStripStatusLabelReader2, progress, status );
if ( reader == READER3 ) SetStatusRead( reader, ref toolStripStatusLabelReader3, progress, status );
if ( reader == READER4 ) SetStatusRead( reader, ref toolStripStatusLabelReader4, progress, status );
}
catch ( Exception ex )
{
MessageBox.Show( ex.Message.ToString() );
}
 
return 0;
}
 
// function which is calling the C++ DLL
unsafe private void Read( int reader, string MRZ, ref PassportReader PPReader, ref ToolStripStatusLabel ctl)
{
try
{
ctl.Text = "";
if ( mb_Connected == true )
{
int status;
if ( ( status = ePersoReset( reader ) ) == 0 )
{
if ( ( status = ePersoSetBACKeys( reader, MRZ.ToCharArray() ) ) != 0 )
ctl.Text = "Failed to set BAC keys : " + status.ToString();
 
if ( status == 0 )
{
PPReader.State = READ_START;
if ( reader == READER1 ) ProcessRead(reader, ref PPReader, ref toolStripStatusLabelReader1, ref mi_SizeReader1 );
if ( reader == READER2 ) ProcessRead(reader, ref PPReader, ref toolStripStatusLabelReader2, ref mi_SizeReader2 );
if ( reader == READER3 ) ProcessRead(reader, ref PPReader, ref toolStripStatusLabelReader3, ref mi_SizeReader3 );
if ( reader == READER4 ) ProcessRead(reader, ref PPReader, ref toolStripStatusLabelReader4, ref mi_SizeReader4 );
}
}
}
else
{
ctl.Text = "Not Connected !";
}
}
catch ( Exception ex )
{
MessageBox.Show( ex.Message.ToString() );
}
}
 
private unsafe void ProcessRead(int reader, ref PassportReader PPReader, ref ToolStripStatusLabel ctl, ref int size )
        {
            int status;
 
            switch ( PPReader.State )
            {
                case READ_START:
                    // Get the EF.COM size
                    PPReader.State = READ_EFCOM_SIZE;
 
                    // Get the current CPU time
                    PPReader.Start = DateTime.Now;
 
                    // Read EF com size
                    if ( ( status = ePersoRead( reader, 0, new PROGRESSCALLBACK( this.ReadProgress ), null, ref size, null ) ) != 0 )
                        ctl.Text = "Read EF.COM size failed : " + status.ToString();
 
                    break;
 
                case READ_EFCOM_SIZE:
 
                    // Get the EF.COM data
                    PPReader.State = READ_EFCOM;
 
                    // Allocate space for data
                    PPReader.DG0 = new char[size];
                    fixed ( char* sTmp = PPReader.DG0 )
                    { 
                        // Read EF com
                        if ( ( status = ePersoRead( reader, 0, new PROGRESSCALLBACK(this.ReadProgress), null, ref size, sTmp ) ) != 0 )
                            ctl.Text = "Read EF.COM data failed : " + status.ToString();
                    }
                    break;
 
                case READ_EFCOM:
 
 
                    break;
            }
 
        }

J'ai essayé de définir le type "void *" en type "[MarshalAs( UnmanagedType.AsAny )] Object", mais on ne peut pas définir le type "void *" de cette manière dans le prototype de la fonction de callback.

J'ai essayé de conserver la référence de l'instance de mon délégué, mais cela n'a rien changé, j'ai toujours la même erreur :

"The value of ESP was not properly saved accross a function call. This usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."


Voici le prototype de ma fonction de callback en C++:

Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
typedef long (*PROGRESSCALLBACK)(long reader, void * pUserData, long progress, long status);

Peut-être que mon prototype de fonction de callback en C# est faus, mais je ne vois pas où, le voici à titre d'information:

Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
public unsafe delegate int PROGRESSCALLBACK( int reader, void* pUserData, int progress, int status );

Quelqu'un a-t-il la solution a mon problème (qui soit dit en passant commence à me rendre chèvre).

Merci d'avance à celles ou ceux qui pourront trouver une solution à ce problème (je ferai une publication sur le site MSDN et elles seront bien sur citées).

@+