When is a LONG not a long?


Answer: When PInvoke is involved.


I ran across a common error today on stackoverflow regarding P/Invoke that is worth blogging about.  The question regarded the translation of a native API with a parameter of type LONG.  The user mistakenly used the .Net long type as the parameter.  The error is that a C++ LONG is not the same as a .Net long.


When talking about types and PInvoke it’s easier to discuss byte size and signed-ness than type names.  Otherwise confusion around long and short crop up.  Really there are four integer byte sizes each of which can be signed or unsigned: 1,2,4 and 8


The problem the user encountered is the C++ long is 4 byte signed and .Net long is 8 byte signed.  PInvoke requires the parameters to have the same size.  Below is a quick table of the various types in C++ and .Net.



  • 1 byte


    • C++ – char, __int8, BYTE, BOOLEAN

    • .Net – byte

  • 2 byte


    • C++ – wchar, __int16, short, WORD

    • .Net – char, short

  • 4 byte


    • C++ – int, LONG, long, __int32, DWORD

    • .Net – int

  • 8 byte


    • C++ – __int64, LONGLONG, DWORDLONG, LARGE_INTEGER

    • .Net – long

Based on this table when translating a C++ LONG, you should use a .Net int.


Edit1: Moved C++ short to 2 byte, added several other C++ types. (thanks Raymond)