How to get the main forM handle in .NET

  • Thread starter Thread starter Fred Hebert
  • Start date Start date
F

Fred Hebert

I am trying to use a 3rd party DLL that requires the main window handle as
a parameter.

e.g. MyFunc(WHND MyHandle);

The example looks something like this:

Result = MyFunc(Handle);

Where "Handle" is the Win32 handle.

Trying to use the example as written results in a compiler error:
cannot convert parameter 5 from 'int' to 'HWND'

First isn't the HWND basically an unsigned integer? I have tried type
casting and several other things, but nothing the compiler likes.

Does anyone know how to make this work?
 
Fred Hebert said:
I am trying to use a 3rd party DLL that requires the main window handle as
a parameter.

e.g. MyFunc(WHND MyHandle);

Typo? You mean this?

MyFunc(HWND MyHandle);

The example looks something like this:

Result = MyFunc(Handle);

Where "Handle" is the Win32 handle.

Trying to use the example as written results in a compiler error:
cannot convert parameter 5 from 'int' to 'HWND'

First, it is always a good idea to post code exactly as written; the devil
is in the details.

This is a guess: If you must, cast the 5th parameter:

change ...(... x, ...);

to

...(... (HWND) x, ...);
First isn't the HWND basically an unsigned integer?

Using Von Neumann machines, everything is basically an integer. So, what?
:-)
I have tried type casting and several other things,
but nothing the compiler likes.

As I said, show the bad code, the exact text of the error message and what
you have tried.

Regards,
Will
 
Sorry about the typo, was just trying to simplify.

It's pulled from various places, but here is the actual code:

typedef int (_stdcall *pOmniConnect) (char * IpAddress,
unsigned int Port,
unsigned int Timeout,
unsigned char EncryptionKey[16],
HWND NotifyWindow);
....
pOmniConnect OmniConnect;
....
The dll is loaded and addresses resolved (not relevant to problem)
....
OmniConnect(IpEdit->Text,
PortEdit->Text->ToInt32,
TimeoutEdit->Text->ToInt32,
BinKey,
Handle); // this line is the problem
As Written:
error C2664: 'int(... the func template ...)': cannot convert parameter 5
from 'int' to 'HWND'

Tried type casting e.g. (HWND)Handle);
error C2440" 'type cast' : cannot convert from 'System::IntPtr' to 'HWND'

Tried various this->Handle, and Handle->xxx conversions but similar
problems.
 
Fred Hebert said:
Sorry about the typo, was just trying to simplify.

It's pulled from various places, but here is the actual code:

typedef int (_stdcall *pOmniConnect) (char * IpAddress,
unsigned int Port,
unsigned int Timeout,
unsigned char EncryptionKey[16],
HWND NotifyWindow);
...
pOmniConnect OmniConnect;
...
The dll is loaded and addresses resolved (not relevant to problem)
...
OmniConnect(IpEdit->Text,
PortEdit->Text->ToInt32,
TimeoutEdit->Text->ToInt32,
BinKey,
Handle); // this line is the problem
As Written:
error C2664: 'int(... the func template ...)': cannot convert parameter 5
from 'int' to 'HWND'

Tried type casting e.g. (HWND)Handle);
error C2440" 'type cast' : cannot convert from 'System::IntPtr' to 'HWND'

Tried various this->Handle, and Handle->xxx conversions but similar
problems.

How is Handle declared?

Regards,
Will
 
How is Handle declared?

Regards,
Will

It's not in my code. It should be the handle of the main form.

According to the docs:
[C++]
public: __property virtual IntPtr get_Handle();

Property Value
An IntPtr that contains the window handle (HWND) of the control.

Implements
IWin32Window.Handle

Remarks
The value of the Handle property is a Windows HWND. If the handle has not
yet been created, referencing this property will force the handle to be
created.
 
Fred Hebert said:
According to the docs:
[C++]
public: __property virtual IntPtr get_Handle();

Property Value
An IntPtr that contains the window handle (HWND) of the control.

Implements
IWin32Window.Handle

Remarks
The value of the Handle property is a Windows HWND. If the handle has not
yet been created, referencing this property will force the handle to be
created.

I have no idea why a window handle should be returned as an IntPtr. <Sigh>

Does this IntPtr have a ToInt32() method? If so, can you use it to get
yourself an integer and cast that to a window handle?

Regards,
Will
 
Hi Will,
I have no idea why a window handle should be returned as an IntPtr. <Sigh>

Because IntPtr represents a platform-specific pointer size (meaning, it
holds a 64-bit value on 64-bit platforms with the 64-bit version of the
framework).
Does this IntPtr have a ToInt32() method? If so, can you use it to get
yourself an integer and cast that to a window handle?

It does, but a better option is to use IntPtr::ToPointer() which returns a
void* :)

So you can just do (HWND)Handle.ToPointer();
 
Hi Tomas,
Because IntPtr represents a platform-specific pointer size (meaning, it
holds a 64-bit value on 64-bit platforms with the 64-bit version of the
framework).

Oh. :-)

Geez, just what I need, something else new to get up to speed on.

Regards,
Will
 
Hi Will,
Oh. :-)

Geez, just what I need, something else new to get up to speed on.

Jajajajaa. Well, in that sense, it's not all that different (source code
wise) from using ULONG_PTR and friends instead of ULONG :)
 
So you can just do (HWND)Handle.ToPointer();

Sounds good, but neither ToInt32 or ToPointer works, and in fact they both
return EXACTLY the same error.

error C3374: managed function 'System::IConvertible::ToInt32' requires
argument list

Any more ideas? This is really frustrating because I am sure it is
something simple.
 
Hi Frank,
Sounds good, but neither ToInt32 or ToPointer works, and in fact they both
return EXACTLY the same error.

error C3374: managed function 'System::IConvertible::ToInt32' requires
argument list

ToInt32, huh? OK, so lets review the code because in no case should
ToInt32() be getting called here.

Consider this code:

void Func(HWND hwnd)
{
MessageBox::Show(String::Format("Handle: {0}", (ULONG_PTR)hwnd));
}

......

void OnButtonClick(Object^ sender, EventArgs^ e)
{
IntPtr handle = this->Handle;
Func((HWND)handle.ToPointer());
}


That compiles and runs cleanly for me.
 
That compiles and runs cleanly for me.

I can't get it to work so I created the simplest project I could to
demonstrate the problem:

1. Create a new VC.NET Windows Forms Application.

2. Drop 4 TextBox controls on the form and a Button.

3. Edit the properties of the text controls like this:
[textBox1]
Name: IpEdit
Text: 10.1.1.1
[textBox2]
Name: PortEdit
Text: 1234
[textBox3]
Name: TimeoutEdit
Text: 10
[textBox4]
Name: KeyEdit
Text: fffffffffffffffffffffffffffffff << should be 32 f's

4. Double Click on the button, and enter the following code:
---------------------------------------
unsigned char BinKey[16]; // key is entered in HEX but
must be converted to binary value for use
for(int i=0; i < KeyEdit->Text->Length; i=i+2)
{
BinKey[i>>1] = (unsigned int)(hextobin(KeyEdit->
Text->get_Chars(i)) << 4) +
hextobin(KeyEdit->Text->get_Chars(i+1));
}
OmniConnect(IpEdit->Text,
PortEdit->Text->ToInt32,
TimeoutEdit->Text->ToInt32,
BinKey,
Handle);
---------------------------------------

5. The the beginning of the Form1.h, just after the "#pragma once" line
add the following lines:
---------------------------------------
#include <windows.h>

#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)
<='F' ? (c)-'A'+10 : (c)-'0')

typedef int (_stdcall *pOmniConnect) (char * IpAddress,
unsigned int Port,
unsigned int Timeout,
unsigned char EncryptionKey[16],
HWND NotifyWindow);

pOmniConnect OmniConnect;
---------------------------------------

Now I know I left out the OnCreate of the form where the DLL is loaded
and all of the other DLL exports, but I think I have everything you need
to compile, that is once the "Handle" issue is resolved.

Of course it won't run but right now I am just trying to get past this
one problem. In the real program, if I comment out the code in the
button click the rest of the program runs fine. I didn't have problems
with any of the functions, but most of them just pass strings and
integers.
 
Fred,
1. Create a new VC.NET Windows Forms Application.

2. Drop 4 TextBox controls on the form and a Button.

3. Edit the properties of the text controls like this:
[textBox1]
Name: IpEdit
Text: 10.1.1.1
[textBox2]
Name: PortEdit
Text: 1234
[textBox3]
Name: TimeoutEdit
Text: 10
[textBox4]
Name: KeyEdit
Text: fffffffffffffffffffffffffffffff << should be 32 f's

4. Double Click on the button, and enter the following code:
---------------------------------------
unsigned char BinKey[16]; // key is entered in HEX but
must be converted to binary value for use
for(int i=0; i < KeyEdit->Text->Length; i=i+2)
{
BinKey[i>>1] = (unsigned int)(hextobin(KeyEdit->
Text->get_Chars(i)) << 4) +
hextobin(KeyEdit->Text->get_Chars(i+1));
}
OmniConnect(IpEdit->Text,
PortEdit->Text->ToInt32,
TimeoutEdit->Text->ToInt32,
BinKey,
Handle);

Humm... try changing that one last to:
OmniConnect(IpEdit->Text,
Convert::ToInt32(PortEdit->Text),
Convert::ToInt32(TimeoutEdit->Text),
BinKey,
(HWND)Handle.ToPointer());

Does that work?
 
OmniConnect(IpEdit->Text,
Convert::ToInt32(PortEdit->Text),
Convert::ToInt32(TimeoutEdit->Text),
BinKey,
(HWND)Handle.ToPointer());

Unfortunately no, but I think we are getting closer.

I'm not entirely sure about the difference between PortEdit->Text->ToInt32
and Convert::ToInt32(PortEdit->Text), but now the compiler is complaining
about not being able to convert parameter 1 from 'System::String __gc*' to
'char *'.

I am going to do more reading, but it looks like it is processing the
parameters in reverse order.
 
Hi Fred,
Unfortunately no, but I think we are getting closer.

I'm not entirely sure about the difference between PortEdit->Text->ToInt32
and Convert::ToInt32(PortEdit->Text), but now the compiler is complaining
about not being able to convert parameter 1 from 'System::String __gc*' to
'char *'.

I am going to do more reading, but it looks like it is processing the
parameters in reverse order.

Ahhh, no. The problem is the first argument, where you pass in IpEdit->Text.
That's a String*, and it seems you need a char*. You're gonna have to
marshal that first, using
System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(). See
http://www.winterdom.com/mcppfaq/archives/000111.html
 
OK this is what I came up with:

using namespace System::Runtime::InteropServices;
...
char* ip = (char*)(void*)Marshal::StringToHGlobalAnsi(IpEdit->Text);
OmniConnect(ip,
Convert::ToInt32(PortEdit->Text),
Convert::ToInt32(TimeoutEdit->Text),
BinKey,
(HWND)Handle.ToPointer());
Marshal::FreeHGlobal(ip);

It seems to work, but what a pain. I feel like I am going back to
programming 101 to transition to this .net stuff. In another thread I saw
a comment something about "what's so difficult it's just C++", yea right,
now tell me the one about the Easter bunny...

I guess I better pick up a beginning .net book. I have been programming
for 28 years and thought jumping into .net was going to be easy, but...

Without offending anyone, it think the included documentation leaves a lot
to be desired.
 
OK this is what I came up with:

using namespace System::Runtime::InteropServices;
...
char* ip = (char*)(void*)Marshal::StringToHGlobalAnsi(IpEdit->Text);
OmniConnect(ip,
Convert::ToInt32(PortEdit->Text),
Convert::ToInt32(TimeoutEdit->Text),
BinKey,
(HWND)Handle.ToPointer());
Marshal::FreeHGlobal(ip);

It seems to work, but what a pain. I feel like I am going back to
programming 101 to transition to this .net stuff. In another thread I saw
a comment something about "what's so difficult it's just C++", yea right,
now tell me the one about the Easter bunny...

I guess I better pick up a beginning .net book. I have been programming
for 28 years and thought jumping into .net was going to be easy, but...

Without offending anyone, it think the included documentation leaves a lot
to be desired.

What a nightmare.

Now I be pining for the C/Win32 API simplicity of:

if (OmniConnect(GetDlgItemText(hdlg, IDC_IP),
GetDlgItemInt(hdlg, IDC_PORT, NULL, FALSE),
GetDlgItemInt(hdlg, IDC_TIMEOUT, NULL, TRUE),
BinKey, hwnd) != SUCCESS)...
 
Hi Fred,
It seems to work, but what a pain. I feel like I am going back to
programming 101 to transition to this .net stuff. In another thread I saw
a comment something about "what's so difficult it's just C++", yea right,
now tell me the one about the Easter bunny...

Well, to be honest, there are many new things, and then, some are
reappearences of things that are common in Win32 programming with a
different twist. In your question, for example, there's nothing really new.
String to Int conversions? always have been there in C/C++, and there are
tens of variants on how to do it; this is just a new one of those (and more
comfortable, imho). String to char*? not new, either, especially for someone
used to dealing with unicode-to- ascii conversions and the like.
Without offending anyone, it think the included documentation leaves a lot
to be desired.

That, I won't argue. The .NET framework documentation itself is good, but,
alas, the MC++ language documentation is rather terse and short, and there
is always room for improvement. I believe for C++/CLI this is improving
enormously with a proper language specification and several documents on the
design and implementation, and literally hundreds of new samples of using
C++/CLI with the .NET framework classes.
 
Back
Top