[C#] P/Invoke van een C++ functie geeft een NullRefException

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Lang geleden, maar ik ga hier toch nog eens een topic openen, ik zit nl. reeds een tijd te 'sjieken' op een probleem dat ik maar niet opgelost krijg.


We hebben hier een C++ DLL waar er een aantal methods gedefinieerd zijn die we via P/Invoke aanroepen vanuit .NET.
Deze C++ dll bestaat al enkele jaren, en werkte tot nu toe naar tevredenheid. Eén van de methods die we vanuit C# aanroepen, ziet er als volgt uit in die C++ dll.

C++:
1
2
3
4
extern "C" long WINAPI BtrTableOpenEx(long *Handle , char *TableName , char *DDLocation , char *DataLocation , char *Owner)
{
   ...
}


Deze method roepen we aan vanuit een C# dll. Hiertoe gebruiken we het DllImport attribute:

code:
1
2
3
4
5
6
[SuppressUnmanagedCodeSecurity]
        private static class NativeMethods
        {                    
            [DllImport ("BtrTable.dll")]
            internal static extern int BtrTableOpenEx( ref int handle, string tableName, string ddLocation, string dataLocation, string owner );
       }


Dit werkt perfect; we kunnen vanuit C# de BtrTableOpenEx method zonder probleem aanroepen.

Onlangs heb ik er echter een method moeten aan toevoegen aan die C++ dll. Het is eigenlijk dezelfde method, maar met een extra parameter. Ik heb geen overload van die method gemaakt, maar een method met een andere naam gedefinieerd (gewoon dezelfde naam gepostfixt met 2):

C++:
1
2
3
4
extern "C" long WINAPI BtrTableOpenEx2(long *Handle , char *TableName , char *DDLocation , char *DataLocation, char *Owner, BTI_WORD threadId)
{
    ...
}

Zoals je kan zien: de naam is gepostfixt met 2, er is een extra parameter toegevoegd van het type BTI_WORD. BTI_WORD is gedefinieerd als
C++:
1
typedef unsigned short     BTI_WORD;


De C++ dll compiled en build perfect.

Ik heb het .NET project aangepast zodanig dat deze nieuwe method ook vanuit .NET kan aangeroepen worden:
C#:
1
2
3
4
5
6
7
8
9
10
11
  [SuppressUnmanagedCodeSecurity]
        private static class NativeMethods
        {
            #region Table manipulation

            [DllImport ("BtrTable.dll")]
            internal static extern int BtrTableOpenEx2( ref int handle, string tableName, string ddLocation, string dataLocation, string owner, ushort threadId );

            [DllImport ("BtrTable.dll")]
            internal static extern int BtrTableOpenEx( ref int handle, string tableName, string ddLocation, string dataLocation, string owner );
}


Als ik nu echter vanuit .NET deze BtrTableOpenEx2 method ga aanroepen, dan krijg ik een runtime-error "object reference not set to an instance".
Het lijkt erop alsof die nieuwe method niet gevonden wordt, want ik ben zeker dat de BtrTableOpenEx2 functie uit de C++ niet aangeroepen wordt.

Waarschijnlijk zie ik iets over het hoofd, maar ik weet niet wat. Hopelijk kan iemand mij helpen. :P

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Extra info:

Ik heb even het command dumpbin /exports btrtable.dll uitgevoerd.

Daar zie ik effectief dat mijn nieuwe method (BtrTableOpenEx2) niet 'aanwezig' is.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
OK.
Er zit in het VC++ 6 (!) project blijkbaar nog een .def file die alle exports oplijst. Daar moest die nieuwe method dus ook nog toegevoegd worden. (Een find in files in VC++ nam die .def file blijkbaar niet mee)...

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Dat los je al sinds VC++6 op met een __declspec (dllexport), je gebruikt hier een methode uit VC++5 (1996)

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
MSalters schreef op donderdag 15 januari 2015 @ 12:07:
Dat los je al sinds VC++6 op met een __declspec (dllexport), je gebruikt hier een methode uit VC++5 (1996)
Dat zou goed kunnen hoor; het is een oud C++ project dat hier jaren geleden ontwikkeld werd ...

Je bedoelt dat het beter is om nu mbhv __declspec aan te geven dat die method 'exportable' is, ipv op de manier waarop het nu gedaan is ?
(Alle exportable methods staan in een aparte file opgelljst ala

code:
1
2
3
4
5
LIBRARY "...."

EXPORTS
    BtrTableOpenEx
    ...

[ Voor 30% gewijzigd door whoami op 15-01-2015 13:42 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Dat is inderdaad vaak handiger, bijvoorbeeld omdat je dan meteen in de source ziet wat exported is.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Dat ga ik helemaal niet ontkennen, gezien het feit dat ik er wel eventjes op gezocht heb. :P
Om het nu nog allemaal te gaan ombouwen echter, gaat me ook wel wat te ver, dus ik ga het nu gewoon zo laten. :)

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Mijzelf
  • Registratie: September 2004
  • Niet online
Met een __declspec( dllexport ) word het volgens mij geexporteerd als _BtrTableOpenEx@24, dus die .def file is zo gek nog niet.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Neuh, stdcall functies (en WINAPI is effectief een macro voor __stdcall) worden altijd op die manier gedecorate (omdat de callee de callstack moet opruimen). Het verschil tussen een .def file en __declspec(dllexport) wordt vooral duidelijk als je een functie met C++ linkage gaat exporteren (dus zonder extern "C"), omdat je dan de C++ name mangling er ook bij krijgt.

[ Voor 7% gewijzigd door .oisyn op 16-01-2015 17:55 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1