Function that has a DllImport Custom Attribute cannot return an instance of a class!?!

Hello Experts,

I am trying to call GetLargestConsoleWindowSize from a Managed C++ class. I have created the prototype in my managed code like this:

[DllImport("KERNEL32.DLL", EntryPoint="GetLargestConsoleWindowSize")]
static COORD GetLargestConsoleWindowSize(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 GetLargestConsoleWindowSize 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
LVL 1
MensanaAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Svetlin_PanayotovCommented:
Yes - I had similar problems.I don't know if that's the best way around - but you can probably do something like:

static IntPtr* GetLargestConsoleWindowSize(int hConsoleOutput);

and then
Marshal::PtrToStructure(pResult,COORD);

Svetlin
0
MensanaAuthor Commented:
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 "GetLargestConsoleWindowSize" 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 MyOtherGetLargestConsoleWindowSize( int nWindowHandle )
{
   COORD objWindowSize;

   IntPtr pCoord = GetLargestConsoleWindowSize( GetStdHandle(STD_OUTPUT_HANDLE) );

   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 GetLargestConsoleWindowSize 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 MyGetLargestConsoleWindowSize( 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 = GetLargestConsoleWindowSize( GetStdHandle(STD_OUTPUT_HANDLE) );

      // 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 MyGetLargestConsoleWindowSize 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 GetLargestConsoleWindowSize API function.

0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

AlexFMCommented:
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.
0
MensanaAuthor Commented:
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="SetConsoleScreenBufferSize")]
static int SetConsoleScreenBufferSize(int hConsoleOutput, COORD dwWindowSize );

[DllImport("KERNEL32.DLL", EntryPoint="SetConsoleWindowInfo")]
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="SetConsoleScreenBufferSize")]
static int MySetConsoleScreenBufferSize(int hConsoleOutput, MyCOORD dwWindowSize );

[DllImport("KERNEL32.DLL", EntryPoint="SetConsoleWindowInfo")]
static int MySetConsoleWindowInfo(int hConsoleOutput, int bAbsolute, const MySMALL_RECT *srWindowSize );

In the end I had to modify the code and use API's GetLargestConsoleWindowSize directly:

COORD objScreenBufferSize = GetLargestConsoleWindowSize( GetStdHandle(STD_OUTPUT_HANDLE) );

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
0
AlexFMCommented:
>> NEVER MIX P/INVOKE WITH IJW!
Right, managed C++ programmer doesn't need PInvoke.
0
MensanaAuthor Commented:
Please close this question and return points in my pool. Points were awarded.
0
AlexFMCommented:
You can split points here instead of opening new questions.
If you want to refund your points ask Community Support.
0
MensanaAuthor Commented:
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.
0
AlexFMCommented:
Ask community support to close this question. You need to post request here:
http://www.experts-exchange.com/Community_Support/

I add note to "Points for" question.
0
moduloCommented:
Closed, 200 points refunded.

modulo
Community Support Moderator
Experts Exchange
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual C++.NET

From novice to tech pro — start learning today.