CALLBACK procedure (invalid calling convention '__stdcall ' for function compiled with /clr:pure or

S

SQACPP

Hi,

I try to figure out how to use Callback procedure in a C++ form
project

The following code *work* perfectly on a console project

#include "Windows.h"
BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lparam)
{
// blablabla we dont care for now
return (TRUE);
}
int main()
{
EnumWindows((WNDENUMPROC) MyEnumWindowsProc,0);
}

But in the C++ form project it return the following error :

Error C3641: 'MyEnumWindowsProc' : invalid calling convention
'__stdcall ' for function compiled with /clr:pure or /clr:safe

I already read a lot of post on the subject but still trying to find
an answer...

Thanks!

Mike
 
J

Jochen Kalmbach [MVP]

Hi SQACPP!
Error C3641: 'MyEnumWindowsProc' : invalid calling convention
'__stdcall ' for function compiled with /clr:pure or /clr:safe

Switch the setting in your project to:
"Common language runtime support" to "/clr"


--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
 
S

SQACPP

Hi SQACPP!


Switch the setting in your project to:
"Common language runtime support" to "/clr"

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/

Thanks! it work with /clr

I'm wondering one another thing about CALLBACK functions....

By example if i want to print something in a textBox from my callback
function how can i access to my textBox ? This->textBox1.Text or
Form1->textBox1.Text are not available in the callback

In other word i'm trying the print the handle or the caption of each
window in a TextBox control and i dont know how to access to my
TextBox from the callback (EnumWindowsProc).

In a console application I can just output (cout) each window handle
to the console but I cant figure out how to do this in a C++ form
project. Is anybody know how to access to my TextBox1 from the
callback?

Thanks again!
 
D

David Wilkinson

SQACPP said:
I'm wondering one another thing about CALLBACK functions....

By example if i want to print something in a textBox from my callback
function how can i access to my textBox ? This->textBox1.Text or
Form1->textBox1.Text are not available in the callback

In other word i'm trying the print the handle or the caption of each
window in a TextBox control and i dont know how to access to my
TextBox from the callback (EnumWindowsProc).

In a console application I can just output (cout) each window handle
to the console but I cant figure out how to do this in a C++ form
project. Is anybody know how to access to my TextBox1 from the
callback?

SQACPP:

I'm not so sure about managed/unmanaged issues, but in Win32 you would
pass a pointer to a user-defined struct as the LPARAM parameter of
EnumWindows(). This struct can contain anything you like (strings,
window handles, whatever).
 
S

SQACPP

SQACPP:

I'm not so sure about managed/unmanaged issues, but in Win32 you would
pass a pointer to a user-defined struct as the LPARAM parameter of
EnumWindows(). This struct can contain anything you like (strings,
window handles, whatever).

Sounds like a good ideas but i dont know how to declare the type of
"this" (Form1) to pass it to my callback function :

struct FormReference {
int FormRef; // ** What is the "this" (form1) type?
int blabla;
};

BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lparam)
{
// I want to access to this->textBox1->Text in this callback
function
lparam.FormRef->textBox1->Text+="x\n"; // ?????
return (TRUE);
}
//...
....main()
{
FormReference *MyFormReference;
// *** How to define define MyFormReference.FormRef=this; ?????????
EnumWindows((WNDENUMPROC)MyEnumWindowsProc,0); // ** How to pass
the pointer to the structure as LPARAM for the last parameter?
}
 
B

Ben Voigt [C++ MVP]

SQACPP said:
Thanks! it work with /clr

I'm wondering one another thing about CALLBACK functions....

By example if i want to print something in a textBox from my callback
function how can i access to my textBox ? This->textBox1.Text or
Form1->textBox1.Text are not available in the callback

In other word i'm trying the print the handle or the caption of each
window in a TextBox control and i dont know how to access to my
TextBox from the callback (EnumWindowsProc).

In a console application I can just output (cout) each window handle
to the console but I cant figure out how to do this in a C++ form
project. Is anybody know how to access to my TextBox1 from the
callback?

Make your callback function an instance member of the Form. Take off the
CALLBACK designator. Together, this will make your callback function in
managed code. Define a delegate type matching the EnumWindowsProc (the C#
version on pinvoke.net might be useful for comparison). Use the
Marshal::GetFunctionPointerForDelegate method to have .NET compile the
native shim which contains the hidden "this" handle, and pass the resulting
pointer to EnumWindows (properly cast). Now you can access any of the other
controls and members of your form from inside the callback.

As a side effect, you can again use /clr:pure.
 
S

SQACPP

Make your callback function an instance member of the Form. Take off the
CALLBACK designator. Together, this will make your callback function in
managed code. Define a delegate type matching the EnumWindowsProc (the C#
version on pinvoke.net might be useful for comparison). Use the
Marshal::GetFunctionPointerForDelegate method to have .NET compile the
native shim which contains the hidden "this" handle, and pass the resulting
pointer to EnumWindows (properly cast). Now you can access any of the other
controls and members of your form from inside the callback.

As a side effect, you can again use /clr:pure.






- Show quoted text -- Hide quoted text -

- Show quoted text -

Afters hours of trying to make the callback function as described I
restart from scratch with a working example found at :
http://www.codeproject.com/managedcpp/cbwijw.asp The only problem is
that this example use /oldSyntax and I manage to convert it to the new
syntax. I'm still trying to figure out how to solve 2 errors and 1
warning.

Original /old syntax source : http://www.codeproject.com/managedcpp/cbwijw.asp


Here is the converted example :
======================
<Code>

#include "stdafx.h"
#using <mscorlib.dll>
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#include <tchar.h>
#include <windows.h>

using namespace System;
using namespace System::ComponentModel;
using namespace System::Drawing;
using namespace System::Windows::Forms;


ref class CEnumWindows
{
private:
__nogc class _CEnumWindows // **** Error C4980: '__nogc' : use of
this keyword requires /clr:blush:ldSyntax ***
{
private:
static BOOL EnumWindowsProc(HWND hwnd, LPARAM)
{
CEnumWindows^ pew = CEnumWindows::GetClass();
pew->m_EnumProc->Invoke(hwnd, NULL); //*** Error C2664:
'CEnumWindows::EnumProc::Invoke' : cannot convert parameter 1 from
'HWND' to 'System::IntPtr'
return TRUE;
}
public:
void StartFinding()
{
EnumWindows((WNDENUMPROC)_CEnumWindows::EnumWindowsProc,NULL);
}
};
private:
_CEnumWindows* m_ew;
public:
delegate bool EnumProc(IntPtr hwnd, IntPtr lParam);
static CEnumWindows^ GetClass()
{
return m_pclass;
}
static CEnumWindows^ m_pclass=NULL;
CEnumWindows()
{
m_pclass = this;
m_ew = new _CEnumWindows();
}
~CEnumWindows()
{
delete m_ew;
}
void StartFinding()
{
m_ew->StartFinding();
}
EnumProc^ m_EnumProc;
};

public ref class NForm : public Form
{
public:
bool EWHandler(IntPtr hwnd, IntPtr lParam)
{
char buff[512];
if(GetWindowText((HWND)hwnd.ToInt32(),buff,511))
{
String^ s = String::Format("{0}{1}",
hwnd.ToInt32().ToString("X8"),Convert::ToString(buff)); // ***
Warning warning C4800: 'char *' : forcing value to bool 'true' or
'false' (performance warning) ***
lbox->Items->Add(s);
}
return false;
}
NForm()
{
StartPosition = FormStartPosition::CenterScreen;
Text = "Callbacks with IJW - Nish for CodeProject - Avoid
DllImport";
Size = Drawing::Size(750,550);
FormBorderStyle =
System::Windows::Forms::FormBorderStyle::FixedDialog;
MaximizeBox = false;

lbox = gcnew ListBox();
lbox->Location=Point(5,5);
lbox->Size=Drawing::Size(730,500);
lbox->Sorted = true;

Controls->Add(lbox);

CEnumWindows^ p = gcnew CEnumWindows();
p->m_EnumProc = gcnew
CEnumWindows::EnumProc(this,&NForm::EWHandler);
p->StartFinding();

}
ListBox^ lbox;

};

int WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
Application::Run(gcnew NForm());
return 0;
}

</Code>

Here is the ***errors*** :
==================
Error C4980: '__nogc' : use of this keyword requires /clr:blush:ldSyntax
-> What is the new syntax for _nogc ? cant find much details on
google...
Error C2664: 'CEnumWindows::EnumProc::Invoke' : cannot convert
parameter 1 from 'HWND' to 'System::IntPtr'
-> ???? no idea :(
Warning warning C4800: 'char *' : forcing value to bool 'true' or
'false' (performance warning)
-> ???? no idea :(

If i can find solution these errors I will be ble to integrate this
"example" in my C++ form project.

Thanks again for any clues on this issues...
 
B

Ben Voigt [C++ MVP]

SQACPP said:
Afters hours of trying to make the callback function as described I
restart from scratch with a working example found at :
http://www.codeproject.com/managedcpp/cbwijw.asp The only problem is
that this example use /oldSyntax and I manage to convert it to the new
syntax. I'm still trying to figure out how to solve 2 errors and 1
warning.

Original /old syntax source :
http://www.codeproject.com/managedcpp/cbwijw.asp

I don't know that C++/CLI will even allow you to nest an unmanaged class
inside a ref class, in any case the new syntax for __nogc class is simply
"class", no "ref" or "value" prefix.

You could do what David suggested and pass the handle to your form through
the extra parameter provided for your use. To do that, you will need your
original code and GCHandle::Alloc, GCHandle::Target, and GCHandle::Free.
The problem with passing a pointer through unmanaged code is that the
garbage collector might move your form around while running your callback,
then it will adjust the pointer that you received, but the next time the
callback is invoked, it will get the original pointer location which is no
longer valid. GCHandle solves this problem.
 
S

SQACPP

I don't know that C++/CLI will even allow you to nest an unmanaged class
inside a ref class, in any case the new syntax for __nogc class is simply
"class", no "ref" or "value" prefix.

You could do what David suggested and pass the handle to your form through
the extra parameter provided for your use. To do that, you will need your
original code and GCHandle::Alloc, GCHandle::Target, and GCHandle::Free.
The problem with passing a pointer through unmanaged code is that the
garbage collector might move your form around while running your callback,
then it will adjust the pointer that you received, but the next time the
callback is invoked, it will get the original pointer location which is no
longer valid. GCHandle solves this problem.- Hide quoted text -

- Show quoted text -

Thanks for your help!

I'm still trying to make the enumwindows works and being able to
display the results of enumWindows in my form (this->listBox2->Items-

using namespace System::Runtime::InteropServices;
BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lparam)
{
//GCHandle MyThis = GCHandle::FromIntPtr(lparam); //** not
working since LPARAM is not a IntPtr
//Form MyForm= gcnew System::Windows::Forms::; // ** Dont know
how to define a new "this" instance (my form)

// GCHandle gch = GCHandle.FromIntPtr(param);
// TextWriter tw = (TextWriter)gch.Target;
// tw.WriteLine(handle);
return (TRUE);
}

// ....

GCHandle gch = GCHandle::Alloc(this);
// *** NOT WORKING :
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch)); //** not
working since LPARAM is not a IntPtr
EnumWindows(MyEnumWindowsProc,0);
// ....

I need help to understand how to change the lparam param to a IntPtr
without having compiling errors like :

[error C4439: 'AutomationWinForm::MyEnumWindowsProc' : function
definition with a managed type in the signature must have a __clrcall
calling convention]

when i change my the last param of my callback like this : BOOL
CALLBACK MyEnumWindowsProc(HWND hwnd, IntPtr lparam)

and

[error C2664: 'EnumWindows' : cannot convert parameter 1 from 'BOOL
(__stdcall *)(HWND,System::IntPtr)' to 'WNDENUMPROC' ]

when I change the call to enumWindows like this
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch));

Also it still not clear how to define a new instance of my form
(this) :

Really need help!...thanks!
 
S

SQACPP

I don't know that C++/CLI will even allow you to nest an unmanaged class
inside a ref class, in any case the new syntax for __nogc class is simply
"class", no "ref" or "value" prefix.
You could do what David suggested and pass the handle to your form through
the extra parameter provided for your use. To do that, you will need your
original code and GCHandle::Alloc, GCHandle::Target, and GCHandle::Free.
The problem with passing a pointer through unmanaged code is that the
garbage collector might move your form around while running your callback,
then it will adjust the pointer that you received, but the next time the
callback is invoked, it will get the original pointer location which is no
longer valid. GCHandle solves this problem.- Hide quoted text -
- Show quoted text -

Thanks for your help!

I'm still trying to make the enumwindows works and being able to
display the results of enumWindows in my form (this->listBox2->Items-

using namespace System::Runtime::InteropServices;
BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lparam)
{
//GCHandle MyThis = GCHandle::FromIntPtr(lparam); //** not
working since LPARAM is not a IntPtr
//Form MyForm= gcnew System::Windows::Forms::; // ** Dont know
how to define a new "this" instance (my form)

// GCHandle gch = GCHandle.FromIntPtr(param);
// TextWriter tw = (TextWriter)gch.Target;
// tw.WriteLine(handle);
return (TRUE);

}

// ....

GCHandle gch = GCHandle::Alloc(this);
// *** NOT WORKING :
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch)); //** not
working since LPARAM is not a IntPtr
EnumWindows(MyEnumWindowsProc,0);
// ....

I need help to understand how to change the lparam param to a IntPtr
without having compiling errors like :

[error C4439: 'AutomationWinForm::MyEnumWindowsProc' : function
definition with a managed type in the signature must have a __clrcall
calling convention]

when i change my the last param of my callback like this : BOOL
CALLBACK MyEnumWindowsProc(HWND hwnd, IntPtr lparam)

and

[error C2664: 'EnumWindows' : cannot convert parameter 1 from 'BOOL
(__stdcall *)(HWND,System::IntPtr)' to 'WNDENUMPROC' ]

when I change the call to enumWindows like this
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch));

Also it still not clear how to define a new instance of my form
(this) :

Really need help!...thanks!- Hide quoted text -

- Show quoted text -

Any idea?
 
B

Ben Voigt [C++ MVP]

I'm still trying to make the enumwindows works and being able to
display the results of enumWindows in my form (this->listBox2->Items-

using namespace System::Runtime::InteropServices;
BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lparam)
{
//GCHandle MyThis = GCHandle::FromIntPtr(lparam); //** not
working since LPARAM is not a IntPtr

There's a converting constructor, try GCHandle::FromIntPtr(IntPtr(lparam))
or else GCHandle::FromIntPtr(IntPtr((void*)lparam))
//Form MyForm= gcnew System::Windows::Forms::; // ** Dont know
how to define a new "this" instance (my form)

// GCHandle gch = GCHandle.FromIntPtr(param);
// TextWriter tw = (TextWriter)gch.Target;
// tw.WriteLine(handle);
return (TRUE);
}

// ....

GCHandle gch = GCHandle::Alloc(this);
// *** NOT WORKING :
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch)); //** not
working since LPARAM is not a IntPtr

use GCHandle::ToIntPtr(gch).ToPointer()
EnumWindows(MyEnumWindowsProc,0);
// ....

I need help to understand how to change the lparam param to a IntPtr
without having compiling errors like :

[error C4439: 'AutomationWinForm::MyEnumWindowsProc' : function
definition with a managed type in the signature must have a __clrcall
calling convention]

when i change my the last param of my callback like this : BOOL
CALLBACK MyEnumWindowsProc(HWND hwnd, IntPtr lparam)

and

[error C2664: 'EnumWindows' : cannot convert parameter 1 from 'BOOL
(__stdcall *)(HWND,System::IntPtr)' to 'WNDENUMPROC' ]

when I change the call to enumWindows like this
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch));

Also it still not clear how to define a new instance of my form
(this) :

Really need help!...thanks!
 
S

SQACPP

I'm still trying to make the enumwindows works and being able to
display the results of enumWindows in my form (this->listBox2->Items-
using namespace System::Runtime::InteropServices;
BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lparam)
{
//GCHandle MyThis = GCHandle::FromIntPtr(lparam); //** not
working since LPARAM is not a IntPtr

There's a converting constructor, try GCHandle::FromIntPtr(IntPtr(lparam))
or else GCHandle::FromIntPtr(IntPtr((void*)lparam))
//Form MyForm= gcnew System::Windows::Forms::; // ** Dont know
how to define a new "this" instance (my form)
// GCHandle gch = GCHandle.FromIntPtr(param);
// TextWriter tw = (TextWriter)gch.Target;
// tw.WriteLine(handle);
return (TRUE);
}
GCHandle gch = GCHandle::Alloc(this);
// *** NOT WORKING :
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch)); //** not
working since LPARAM is not a IntPtr

use GCHandle::ToIntPtr(gch).ToPointer()


EnumWindows(MyEnumWindowsProc,0);
// ....
I need help to understand how to change the lparam param to a IntPtr
without having compiling errors like :
[error C4439: 'AutomationWinForm::MyEnumWindowsProc' : function
definition with a managed type in the signature must have a __clrcall
calling convention]
when i change my the last param of my callback like this : BOOL
CALLBACK MyEnumWindowsProc(HWND hwnd, IntPtr lparam)

[error C2664: 'EnumWindows' : cannot convert parameter 1 from 'BOOL
(__stdcall *)(HWND,System::IntPtr)' to 'WNDENUMPROC' ]
when I change the call to enumWindows like this
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch));
Also it still not clear how to define a new instance of my form
(this) :
Really need help!...thanks!- Hide quoted text -

- Show quoted text -

Thanks for still trying to help me!....


BOOL CALLBACK MyEnumWindowsProc(HWND hwnd, LPARAM lparam)
{
GCHandle MyThis = GCHandle::FromIntPtr(IntPtr(lparam)) ;
// ** missing code here to be able to access to my form **//
MyThis->Label1->Text="blabla";
return (TRUE);
}


// ....

GCHandle gch = GCHandle::Alloc(this);
EnumWindows(MyEnumWindowsProc,GCHandle::ToIntPtr(gch).ToPointer()); //
** Error **//

This code return the error Error C2664: 'EnumWindows' : cannot convert
parameter 2 from 'void *' to 'LPARAM'

instead of printing "blabla" in the label1 of my form each time the
callback proc is called for each windows.

I have no clues about how to recreate a usable form "instance" in my
callback procedure... The following code in the proc is to output to
the console but how to work with a form instead ???
GCHandle gch = GCHandle.FromIntPtr(lparam);
TextWriter tw = (TextWriter)gch.Target;
tw.WriteLine(handle);

Thanks...
 

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