Mensana
asked on
Function that has a DllImport Custom Attribute cannot return an instance of a class!?!
Hello Experts,
I am trying to call GetLargestConsoleWindowSiz e from a Managed C++ class. I have created the prototype in my managed code like this:
[DllImport("KERNEL32.DLL", EntryPoint="GetLargestCons oleWindowS ize")]
static COORD GetLargestConsoleWindowSiz e(int hConsoleOutput);
COORD is a structure declared like this
[StructLayout(LayoutKind:: Sequential )]
private __value struct COORD
{
short x;
short y;
};
which mimics the API structure used by the API's GetLargestConsoleWindowSiz e function.
The problem is that when I try to compile I get an error C3385 that tells me that "a function that has a DllImport Custom Attribute cannot return an instance of a class". I know for sure that the C# compiler doesn't have this limitation. I tried to find any references to this error on the net, but couldn't find any.
Did anyone else bumped into it?
Regards,
Eddie
I am trying to call GetLargestConsoleWindowSiz
[DllImport("KERNEL32.DLL",
static COORD GetLargestConsoleWindowSiz
COORD is a structure declared like this
[StructLayout(LayoutKind::
private __value struct COORD
{
short x;
short y;
};
which mimics the API structure used by the API's GetLargestConsoleWindowSiz
The problem is that when I try to compile I get an error C3385 that tells me that "a function that has a DllImport Custom Attribute cannot return an instance of a class". I know for sure that the C# compiler doesn't have this limitation. I tried to find any references to this error on the net, but couldn't find any.
Did anyone else bumped into it?
Regards,
Eddie
ASKER
Hello Svetlin, AlexFM,
Both your postings point to the same way of doing interop: IJW. It's an untersting approach and I will split the points between you. However, before I do that I need you to help me make this work.
The "GetLargestConsoleWindowSi ze" API function happens to return a COORD object by value (COORD has two shorts, so it's really 4 bytes, just like its address).
Therefore I wrote my wrapper like this:
static COORD MyOtherGetLargestConsoleWi ndowSize( int nWindowHandle )
{
COORD objWindowSize;
IntPtr pCoord = GetLargestConsoleWindowSiz e( GetStdHandle(STD_OUTPUT_HA NDLE) );
Marshal::PtrToStructure( pCoord, __box(objWindowSize) );
return objWindowSize;
};
This compiles fine except I cannot include the "windows.h" header. My project is a Visual C++.NET class library (generates a managed C++ .dll) and when I include the header, ahead of all my "using namespace..." directives (as AlexFM's suggested article tells you to do) I get a bunch of errors that are somewhere else. I comment out the “#include” directive and the call to GetLargestConsoleWindowSiz e and everything compiles.
I can't help but feel that I am doing something wrong. IJW it is suppose to be simple, right?
The example in Nish’s article is not very good because it deals with a passed in parameter (string) and not a returned value. With returned values things are different because they are allocated in the called function and not by the caller. Especially when a structure is returned by value and not by reference.
Just for the sake of this discussion, here is my workaround:
I wrote my own unmanaged .dll and I wrapped the call like this:
#include "windows.h"
extern "C" UNMANAGEDDLL_API BOOL MyGetLargestConsoleWindowS ize( HANDLE hConsoleOutput, COORD *pobjCoordinates );
{
// return value
BOOL bReturn = TRUE;
// check pointer to be initialized
if( pobjCoordinates != NULL )
{
// pointer is initialized => get the largest console window size
// by calling the real API function
*pobjCoordinates = GetLargestConsoleWindowSiz e( GetStdHandle(STD_OUTPUT_HA NDLE) );
// check if structure was initialized
if( (pobjCoordinates->X == 0) || (pobjCoordinates->Y == 0) )
// structure not initialized => signal error
bReturn = FALSE;
}
else
{
// the pointer is not initialized => signal error
bReturn = FALSE;
}
// return
return bReturn;
};
Now I can use P/Invoke because MyGetLargestConsoleWindowS ize doesn’t return a class or structure anymore. The downside is that when calling it two .dlls must be loaded: my unmanaged dll followed by kernel32.dll that hosts the real GetLargestConsoleWindowSiz e API function.
Both your postings point to the same way of doing interop: IJW. It's an untersting approach and I will split the points between you. However, before I do that I need you to help me make this work.
The "GetLargestConsoleWindowSi
Therefore I wrote my wrapper like this:
static COORD MyOtherGetLargestConsoleWi
{
COORD objWindowSize;
IntPtr pCoord = GetLargestConsoleWindowSiz
Marshal::PtrToStructure( pCoord, __box(objWindowSize) );
return objWindowSize;
};
This compiles fine except I cannot include the "windows.h" header. My project is a Visual C++.NET class library (generates a managed C++ .dll) and when I include the header, ahead of all my "using namespace..." directives (as AlexFM's suggested article tells you to do) I get a bunch of errors that are somewhere else. I comment out the “#include” directive and the call to GetLargestConsoleWindowSiz
I can't help but feel that I am doing something wrong. IJW it is suppose to be simple, right?
The example in Nish’s article is not very good because it deals with a passed in parameter (string) and not a returned value. With returned values things are different because they are allocated in the called function and not by the caller. Especially when a structure is returned by value and not by reference.
Just for the sake of this discussion, here is my workaround:
I wrote my own unmanaged .dll and I wrapped the call like this:
#include "windows.h"
extern "C" UNMANAGEDDLL_API BOOL MyGetLargestConsoleWindowS
{
// return value
BOOL bReturn = TRUE;
// check pointer to be initialized
if( pobjCoordinates != NULL )
{
// pointer is initialized => get the largest console window size
// by calling the real API function
*pobjCoordinates = GetLargestConsoleWindowSiz
// check if structure was initialized
if( (pobjCoordinates->X == 0) || (pobjCoordinates->Y == 0) )
// structure not initialized => signal error
bReturn = FALSE;
}
else
{
// the pointer is not initialized => signal error
bReturn = FALSE;
}
// return
return bReturn;
};
Now I can use P/Invoke because MyGetLargestConsoleWindowS
What compilation errors do you have using IJW? I created new managed C++ Clicc Library project and added windows.h to it:
// test1.h
#pragma once
#include <windows.h>
using namespace System;
namespace test1
{
public __gc class Class1
{
// TODO: Add your methods for this class here.
};
}
It compiles successfully.
IJW is not so simple because of possible name conflicts. We need to see your code and error messages.
// test1.h
#pragma once
#include <windows.h>
using namespace System;
namespace test1
{
public __gc class Class1
{
// TODO: Add your methods for this class here.
};
}
It compiles successfully.
IJW is not so simple because of possible name conflicts. We need to see your code and error messages.
ASKER
I figured it out. I had lots of name collisions not reported by the compiler. Since the initial path was P/Invoke I had lots of declarations such as:
[DllImport("KERNEL32.DLL", EntryPoint="SetConsoleScre enBufferSi ze")]
static int SetConsoleScreenBufferSize (int hConsoleOutput, COORD dwWindowSize );
[DllImport("KERNEL32.DLL", EntryPoint="SetConsoleWind owInfo")]
static int SetConsoleWindowInfo(int hConsoleOutput, int bAbsolute, const SMALL_RECT *srWindowSize );
Linking the "windows.h" header, functions with similar names were imported, hence the collision. Note to self: NEVER MIX P/INVOKE WITH IJW!
I just had to rename all my imports and everything compiled just fine.
[DllImport("KERNEL32.DLL", EntryPoint="SetConsoleScre enBufferSi ze")]
static int MySetConsoleScreenBufferSi ze(int hConsoleOutput, MyCOORD dwWindowSize );
[DllImport("KERNEL32.DLL", EntryPoint="SetConsoleWind owInfo")]
static int MySetConsoleWindowInfo(int hConsoleOutput, int bAbsolute, const MySMALL_RECT *srWindowSize );
In the end I had to modify the code and use API's GetLargestConsoleWindowSiz e directly:
COORD objScreenBufferSize = GetLargestConsoleWindowSiz e( GetStdHandle(STD_OUTPUT_HA NDLE) );
I guess that the Marshal class really comes in handy when you deal with dynamically allocated objects. With this feature I can say that Managed C++ is better than C# for those who are trying to port legacy code under .NET.
Thanks,
Eddie
[DllImport("KERNEL32.DLL",
static int SetConsoleScreenBufferSize
[DllImport("KERNEL32.DLL",
static int SetConsoleWindowInfo(int hConsoleOutput, int bAbsolute, const SMALL_RECT *srWindowSize );
Linking the "windows.h" header, functions with similar names were imported, hence the collision. Note to self: NEVER MIX P/INVOKE WITH IJW!
I just had to rename all my imports and everything compiled just fine.
[DllImport("KERNEL32.DLL",
static int MySetConsoleScreenBufferSi
[DllImport("KERNEL32.DLL",
static int MySetConsoleWindowInfo(int
In the end I had to modify the code and use API's GetLargestConsoleWindowSiz
COORD objScreenBufferSize = GetLargestConsoleWindowSiz
I guess that the Marshal class really comes in handy when you deal with dynamically allocated objects. With this feature I can say that Managed C++ is better than C# for those who are trying to port legacy code under .NET.
Thanks,
Eddie
>> NEVER MIX P/INVOKE WITH IJW!
Right, managed C++ programmer doesn't need PInvoke.
Right, managed C++ programmer doesn't need PInvoke.
ASKER
Points for AlexFM:
https://www.experts-exchange.com/questions/21217785/Points-for-AlexFM.html
Points for Svetlin_Panayotov:
https://www.experts-exchange.com/questions/21217789/Points-for-Svetlin-Panayotov.html
https://www.experts-exchange.com/questions/21217785/Points-for-AlexFM.html
Points for Svetlin_Panayotov:
https://www.experts-exchange.com/questions/21217789/Points-for-Svetlin-Panayotov.html
ASKER
Please close this question and return points in my pool. Points were awarded.
You can split points here instead of opening new questions.
If you want to refund your points ask Community Support.
If you want to refund your points ask Community Support.
ASKER
Oh, I didn't know this - probabely a new feature I wasn't aware of. Well, next time I will try it. Since Svetlin "cashed" his points, you are welcome to get yours and I hope this question will be closed by the guys from Support.
Ask community support to close this question. You need to post request here:
https://www.experts-exchange.com/Community_Support/
I add note to "Points for" question.
https://www.experts-exchange.com/Community_Support/
I add note to "Points for" question.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
static IntPtr* GetLargestConsoleWindowSiz
and then
Marshal::PtrToStructure(pR
Svetlin