COM : Interface from c# to c++ problem with IntPtr type

E

Eric

Hi all,

I have a C++ application that load C# applets. A method use an IntPtr
parameter because I want to be 32/64-bit compatible. The problem is in
the .tlh file generated. This parameter is a long and not an INT_PTR
and I don't know why ?

Here is some code that may help you.

In C# project.

public interface IDlgCriteresRecherche
{
IntPtr HandleEditeurParent { get; set;}
}

public class AScDlgCriteresRecherche : System.Windows.Forms.Form,
IDlgCriteresRecherche
{

#region IDlgCriteresRecherche Members

private IntPtr nHandleEditeurParent = (IntPtr)0;

public IntPtr HandleEditeurParent
{
get{ return nHandleEditeurParent; }
set{ nHandleEditeurParent = value; }
}

#endregion
}

In the .tlh generated

struct __declspec(uuid("a070cc19-98cf-4433-8351-e1fc2228260f"))
/* dual interface */ IDlgCriteresRecherche;
struct /* coclass */ AScDlgCriteresRecherche;

_COM_SMARTPTR_TYPEDEF(IDlgCriteresRecherche,
__uuidof(IDlgCriteresRecherche));

struct __declspec(uuid("a070cc19-98cf-4433-8351-e1fc2228260f"))
IDlgCriteresRecherche : IDispatch
{
virtual HRESULT __stdcall get_HandleEditeurParent (
/*[out,retval]*/ long * pRetVal ) = 0;
virtual HRESULT __stdcall put_HandleEditeurParent (
/*[in]*/ long pRetVal ) = 0;
}

in C++

#import "ASCommun.tlb" raw_interfaces_only

pIDlgCriteresRecherche->put_HandleEditeurParent((INT_PTR)poActiveView->m_hWnd);

Regards,

Eric
 
S

ssamuel

Hi, Eric.

You're doing COM interop, and an int in COM is 16 bits. An int in .NET
is 32 bits, which is a long in COM. This is independent of whether your
app is targeted at 32 or 64 bit processors.


Stephan
 
T

Thomas T. Veldhouse

ssamuel said:
Hi, Eric.

You're doing COM interop, and an int in COM is 16 bits. An int in .NET
is 32 bits, which is a long in COM. This is independent of whether your
app is targeted at 32 or 64 bit processors.

An int in COM is 32 bits. A short in COM is 16 bits. A long in C++ is the
word length of your platform (32 bits on x86 and 64 bits on x86_64). I am not
sure off hand how this affects long in COM, but I suspect long follows the
same convention as it does in C/C++.
 
E

Eric

You're doing COM interop, and an int in COM is 16 bits. An int in .NET
is 32 bits, which is a long in COM. This is independent of whether your
app is targeted at 32 or 64 bit processors.
Ok, so to be compatible 32/64-bit I have to use Int64 in .NET for not
having pointer troncation in the case of 64-bit processors?

I thought IntPtr was more convenient

Eric
 
T

Thomas T. Veldhouse

Eric said:
Ok, so to be compatible 32/64-bit I have to use Int64 in .NET for not
having pointer troncation in the case of 64-bit processors?

I thought IntPtr was more convenient

IntPtr should work fine as a pointer, is by definition, defined by the word
length of the CPU. The platform should not matter for IntPtr.
 
E

Eric

An int in COM is 32 bits. A short in COM is 16 bits. A long in C++ is the
word length of your platform (32 bits on x86 and 64 bits on x86_64). I am not
sure off hand how this affects long in COM, but I suspect long follows the
same convention as it does in C/C++.
The problem Microsoft doesn't follow standard. int and long are still
32-bit on 64-bit processors in C++. So, in COM using a long will cause
pointer troncation.

Regards,
Eric
 
E

Eric

IntPtr should work fine as a pointer, is by definition, defined by the word
length of the CPU. The platform should not matter for IntPtr.
Yes, that's what I thought. The problem, the IntPtr is changed for an
long when the COM interface is created from an C# project (Visual
Studio 2005). That's what I don't understand.

Regards,
Eric
 
T

Thomas T. Veldhouse

Eric said:
The problem Microsoft doesn't follow standard. int and long are still
32-bit on 64-bit processors in C++. So, in COM using a long will cause
pointer troncation.

No they aren't. You will only see the length of a long as 32-bit on a 64-bit
processor if you use 32-bit Windows. If you install Windows XP 64-bit and
compile your application with XP64 as a target you will be able to verify
this.
 
W

Willy Denoyette [MVP]

Thomas T. Veldhouse said:
An int in COM is 32 bits. A short in COM is 16 bits. A long in C++ is
the
word length of your platform (32 bits on x86 and 64 bits on x86_64). I am
not
sure off hand how this affects long in COM, but I suspect long follows the
same convention as it does in C/C++.


A long in C++ (Microsoft specific) is still a 32bit integer type. A long
long or __int64 is 64 bit in VC++ (VS2005).

Willy.
 
T

Thomas T. Veldhouse

Eric said:
Yes, that's what I thought. The problem, the IntPtr is changed for an
long when the COM interface is created from an C# project (Visual
Studio 2005). That's what I don't understand.

long is the the same bit size as a pointer on the OS ... that is why. See my
other post; you have to be running Windows XP 64-bit on a 64-bit processor to
see long as a 64-bit type [as IntPtr will also be].
 
E

Eric

No they aren't. You will only see the length of a long as 32-bit on a 64-bit
processor if you use 32-bit Windows. If you install Windows XP 64-bit and
compile your application with XP64 as a target you will be able to verify
this.

int and long are still 32-bit in the Microsoft Standard.

see this article
Everything You Need To Know To Start Programming 64-Bit Windows Systems
http://msdn.microsoft.com/msdnmag/issues/06/05/x64/default.aspx

Maybe is don't understand the COM part

Regards,
Eric
 
W

Willy Denoyette [MVP]

Eric said:
Hi all,

I have a C++ application that load C# applets. A method use an IntPtr
parameter because I want to be 32/64-bit compatible. The problem is in
the .tlh file generated. This parameter is a long and not an INT_PTR
and I don't know why ?

Here is some code that may help you.

In C# project.

public interface IDlgCriteresRecherche
{
IntPtr HandleEditeurParent { get; set;}
}

public class AScDlgCriteresRecherche : System.Windows.Forms.Form,
IDlgCriteresRecherche
{

#region IDlgCriteresRecherche Members

private IntPtr nHandleEditeurParent = (IntPtr)0;

public IntPtr HandleEditeurParent
{
get{ return nHandleEditeurParent; }
set{ nHandleEditeurParent = value; }
}

#endregion
}

In the .tlh generated

struct __declspec(uuid("a070cc19-98cf-4433-8351-e1fc2228260f"))
/* dual interface */ IDlgCriteresRecherche;
struct /* coclass */ AScDlgCriteresRecherche;

_COM_SMARTPTR_TYPEDEF(IDlgCriteresRecherche,
__uuidof(IDlgCriteresRecherche));

struct __declspec(uuid("a070cc19-98cf-4433-8351-e1fc2228260f"))
IDlgCriteresRecherche : IDispatch
{
virtual HRESULT __stdcall get_HandleEditeurParent (
/*[out,retval]*/ long * pRetVal ) = 0;
virtual HRESULT __stdcall put_HandleEditeurParent (
/*[in]*/ long pRetVal ) = 0;
}

in C++

#import "ASCommun.tlb" raw_interfaces_only

pIDlgCriteresRecherche->put_HandleEditeurParent((INT_PTR)poActiveView->m_hWnd);

Regards,

Eric



Change your INT_PTR into a void*, IntPtr is marshaled as void* type by the
interop marshaler.

Willy.
 
T

Thomas T. Veldhouse

Eric said:
int and long are still 32-bit in the Microsoft Standard.

see this article
Everything You Need To Know To Start Programming 64-Bit Windows Systems
http://msdn.microsoft.com/msdnmag/issues/06/05/x64/default.aspx

Maybe is don't understand the COM part

There is a lot of text there, so perhaps I missed it, but I do not see
anywhere where it indicates that long is a 32-bit length type on a 64-bit
Windows XP system (running on a 64-bit CPU obviously). You need to compile
the application (COM and .NET) for a 64-bit target. In fact, that article, a
little more than 1/3 of the way down, indicates how it differentiates
addresses depending upon the mode the CPU is running in (it is running in
64-bit mode if you are running Windows XP 64-bit).
 
T

Thomas T. Veldhouse

Eric said:
int and long are still 32-bit in the Microsoft Standard.

see this article
Everything You Need To Know To Start Programming 64-Bit Windows Systems
http://msdn.microsoft.com/msdnmag/issues/06/05/x64/default.aspx

Maybe is don't understand the COM part

As a followup to my previous message. Try the following (compiled and run on
Windows XP 64-bit with all 64-bit tools and targets).

#include <iostream>
using namespace std;

int main(int argc, char ** argv)
{
cout << "long size = " << sizeof(long) << endl;

return 0;
}
 
T

Thomas T. Veldhouse

Willy Denoyette said:
A long in C++ (Microsoft specific) is still a 32bit integer type. A long
long or __int64 is 64 bit in VC++ (VS2005).

It is 32-bits on my machine (Intel 32-bit CPU with 32-bit windows)..

// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
cout << "long length is " << sizeof(long) << " bytes" << endl;

return 0;
}

Output:

long length is 4 bytes

4 bytes is 32-bits, which indicates the C-library is working as it should and
defining the long variable as the word size of the CPU.
 
W

Willy Denoyette [MVP]

Thomas T. Veldhouse said:
Willy Denoyette said:
A long in C++ (Microsoft specific) is still a 32bit integer type. A long
long or __int64 is 64 bit in VC++ (VS2005).

It is 32-bits on my machine (Intel 32-bit CPU with 32-bit windows)..

// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
cout << "long length is " << sizeof(long) << " bytes" << endl;

return 0;
}

Output:

long length is 4 bytes

4 bytes is 32-bits, which indicates the C-library is working as it should
and
defining the long variable as the word size of the CPU.


Check this:
http://msdn2.microsoft.com/en-us/library/s3f49ktz.aspx

Willy.
 
W

Willy Denoyette [MVP]

Eric said:
int and long are still 32-bit in the Microsoft Standard.

see this article
Everything You Need To Know To Start Programming 64-Bit Windows Systems
http://msdn.microsoft.com/msdnmag/issues/06/05/x64/default.aspx

Maybe is don't understand the COM part

Regards,
Eric

http://msdn2.microsoft.com/en-us/library/s3f49ktz.aspx

The C++ standard doesn't define the precise length of (most of) the
fundamental integer datatypes, the individual integer lengths are
implementation specific.

Willy.
 
E

Eric

Change your INT_PTR into a void*, IntPtr is marshaled as void* type by the
interop marshaler.

pIDlgCriteresRecherche->put_HandleEditeurParent((void*)poActiveView->m_hWnd);

I can't do this because the parameter is a long in
put_HandleEditeurParent(long pRetVal)

That is the problem that I have.

pIDlgCriteresRecherche->put_HandleEditeurParent((INT_PTR)poActiveView->m_hWnd);
warning C4244: 'argument' : conversion from 'INT_PTR' to 'long',
possible loss of data

In my case, IntPtr was generated as long in my .tlb file. Why not
void* ?

Regards,
Eric
 
B

Ben Voigt

Thomas T. Veldhouse said:
There is a lot of text there, so perhaps I missed it, but I do not see
anywhere where it indicates that long is a 32-bit length type on a 64-bit
Windows XP system (running on a 64-bit CPU obviously). You need to
compile

It does say it, right next to where it says that a HANDLE is still 32-bits.
Look for the red "Editors' Note" noting that the previous sentence is wrong.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top