Link to home
Start Free TrialLog in
Avatar of ewmontgo
ewmontgo

asked on

COM object - Invalid Pointer Error

I am trying to create an instance of a mainframe emulator. I was previously successful, but managed to get something fouled up so that it stopped working. I downloaded code from the creators of the product, mimicked some of their code, and was ready to go. I continued to mess around with the code, until now both my code and the downloaded code do not work.

Here's a snipit of my code:

...

HRESULT hr;

hr = CoInitialize(NULL);
char SessionName[133];
strcpy(SessionName, "NAME"); // ("NAME" was working before. The details aren't important.

try
{
     hr = system.CreateInstance("Extra.System", NULL);
     sessions = system->Sessions;
     session = sessions->Open(SessionName);
     screen = session->Screen; // ERROR THROWN HERE
     ...
} catch {
     ...
}

That alone throws a _com_error of Invalid Pointer.

Again, I mention that this code was working about 3 hours ago, and just suddenly quit. Is this a problem with some sort of CoInitialize thing? After hr=system.Create, hr is "0." I was expecting it to be "1."

I have a feeling that the problem is not with the code, but with my system.

I appreciate any assistance.

Avatar of Dexstar
Dexstar

ewmontgo:

> Again, I mention that this code was working about 3 hours ago, and just suddenly
> quit.

Are you saying that even the original, unmodified code has stopped working?  Otherwise, I would re-download the sample and see what got changed.  :)

> Is this a problem with some sort of CoInitialize thing? After
> hr=system.Create, hr is "0." I was expecting it to be "1."

No, 0 indicates success.

>      sessions = system->Sessions;
>      session = sessions->Open(SessionName);

> That alone throws a _com_error of Invalid Pointer.

What are the datatypes for those variables?

>      screen = session->Screen; // ERROR THROWN HERE

That line bothers me.  It seems like it should be session->Screen(); or session->get_Screen(); or something like that.

Hope that helps,
Dex*
Avatar of ewmontgo

ASKER

Yes, the original code I downloaded stopped working, exactly the same as my code stopped working.

I'm glad that a 0 indicates success.

The datatypes are specific to namespace Extra, but here are the declarations:
#import "C:\\Extra\\extra.tlb" named_guids
EXTRA::_SystemPtr system;
EXTRA::SessionsPtr sessions;
EXTRA::_SessionPtr session;
EXTRA::ScreenPtr screen;
char SessionName[100];
strcpy(SessionName, "MAINFRAME.EDP");

The screen = session->Screen line has been bothering me, too. It doesn't appear on intellisense, and I can't find it in the header file. But it worked (before it up and quit).

I've since re-downloaded the code and tried it again. It still fails. And I double-checked that the original code remained unchanged, and it had.

I think I may have located a potential source of the problem (knowing about HRESULT and 1 or 0): hr = CoInitialize(NULL) is coming up 0.
I mean, hr = CoInitialize(NULL) is coming up 1.
Okay, I've added if(FAILED(hr)) and if(SUCCEEDED(hr)) to both the CoInitialize and CreateInstance portions of the code. Both are succeeding.

The error is occurring at
session = sessions->Open(SessionName);
This is returning a NULL pointer. I don't know why.

Could this be a registry problem?
Actually, the most significant bit of an HRESULT is used to determine success or failure.  So, 1 still means success, but it means S_FALSE.  That usually means CoInitialize has already been called, but it is okay to call it again.

You need to check the prototype of those functions.  Something about these 2 are not right:

     sessions = system->Sessions;
...
     screen = session->Screen; // ERROR THROWN HERE

The reason you couldn't find them in the header files is because of the #import directive.  When you use that, you need to look for the files .tli and .tlh that are created  (.tlh is the header).  Open up those files, and you'll see the function prototypes.  Maybe that will point you in the right direction.

If you can't figure it out, then post the prototypes here and I'll take a shot.

Dex*
I've stepped through and into the code on those lines. It does indeed step into a .tli file, as advertised. I've also changed those two lines to the following:

sessions = system->GetSessions();
screen = session->GetScreen();

This did not lead to success. The problem is still that the line
session = sessions->Open(SessionName);
is returning a null pointer, which then causes the next line
screen = session->Screen; (or screen = session->GetScreen();)
to crash.

I've also stepped through the Open function, but I don't understand all of the functions that it's passing through (and it passes through a lot). They're inline functions (which I understand doesn't really matter). I'd be happy to post those, but I'm not sure if that would help?
Try this:

Change this line:
     session = sessions->Open(SessionName);

To this:
     HRESULT hr = sessions->raw_Open( SessionName, &session );

(I don't have the prototype for that function, so that call may not be 100% ... But search the .tlh for that function to get the exact prototype)

Then you can check the HRESULT value to see if that function succeeds or fails, and if fails, then you can find out why.

Then change this:
     screen = session->GetScreen();

To This:
    hr = session->get_Screen( &screen );

or it may be:
    hr = session->raw_GetScreen( &screen );

(Depending on how the Interface was defined).

Try that and let me know what compiler errors or HRESULTs you get.

Dex*

     
Here's the raw_Open function:
virtual HRESULT __stdcall raw_Open (
        VARIANT Name,
        IDispatch * * retval ) = 0;

[I don't know what a VARIANT is, but I tried to create one:
tagVARIANT v;
v.??? = SessName;]

And there is not a get_Screen, get_screen, Get_Screen, Get_screen, raw_GetScreen, etc function available.

Try this:

     HRESULT hr = sessions->raw_Open( CComVariant(SessionName), &screen );

What hr value do you get for that?
(I changed it from &screen to &session).

I get a compiler error:
cannot convert parameter 2 from 'struct EXTRA::_Session ** ' to 'struct IDispatch ** '

If I cast as:
 (struct IDispatch **)&session
It compiles, and I get hr returned as 0, which passes the following if(FAILED(hr)), but session is still 0x00000000.
Yeah, I meant &session.  Okay, try this then:

struct EXTRA::_Session* pSession = NULL;
HRESULT hr = sessions->raw_Open( CComVariant(SessionName), &pSession );
if ( SUCCEEDED(hr) )
{
     session = EXTRA::_SessionPtr(pSession, false);
     // false will attach the Interface to the smart pointer, so there is no need to clean up
}

Try that.
Dex*
I get the same compiler error:
cannot convert parameter 2 from 'struct EXTRA::_Session ** ' to 'struct IDispatch ** ',
and I can still cast it (the same way). If I cast it and run it, I end up with the same result. session->GetScreen(); returns NULL.
Well, I'm not sure if casting it that way is safe, but we can worry about that once we get the next step working.  The important thing is that the SessionPtr value is being set now.

We need to figure out what the "raw" function for "GetScreen" is.  Search the .tlh file for "Screen".  There has to be something in there.

Have you wrapped the whole thing is a try, catch block for _com_error& e ?  If one of the methods fails, it should throw such an exception (unless you're using the raw methods).  Does it ever get to the catch block?  If so, what is the value of the e.Error() ?
I found what I think is the raw get screen function (I don't know how I missed it before):
virtual HRESULT __stdcall get_Screen (IDispatch * * retval ) = 0;

One thing, I'm .not. getting a value for sessionPtr. Here's the code for that (just to make sure I didn't make a typo):

struct EXTRA::_Session* pSession = NULL;
hr = sessions->raw_Open(CComVariant(SessionName), (struct IDispatch **)&pSession);
if(SUCCEEDED(hr))
{
     session= EXTRA::_SessionPtr(pSession, FALSE);
}

By debugging, I know that it runs the line session=EXTRA ..., which means hr is succeeding on the previous line. Why would it succeed if pSession is still NULL? If I leave out the casting, it won't compile.

When the get_Screen line fails:
hr = session->get_Screen((struct IDispatch **)&screen);
hr is -2147467261, but I think this line is failing because pSession is NULL. Something must be wrong with the raw_Open function, or one of its subsequent calls. I've searched both the tli and tlh files for raw_Open, but I didn't find anything new.

TLH has:
virtual HRESULT __stdcall raw_Open (
        VARIANT Name,
        IDispatch * * retval ) = 0;

TLI has:
inline IDispatchPtr Sessions::Open ( const _variant_t & Name ) {
    IDispatch * _result;
    HRESULT _hr = raw_Open(Name, &_result);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return IDispatchPtr(_result, false);
}

By the way, I really appreciate your assistance on this. Thank you.
ewmontgo:

> hr = session->get_Screen((struct IDispatch **)&screen);
> hr is -2147467261, but I think this line is failing because pSession is NULL.

Yes, that is exactly what is happening.  But why is it NULL?

Try this:
     IDispatchPtr spDispatch = sessions->Open(SessionName);
     if ( spDispatch == NULL )
     {
        // If it gets here, then something really bizarre is happening
        // because it didn't throw an exception, yet Open returned a NULL value
     }

If it gets inside of the block, then the issue is with your COM object.  For some reason, it is NOT returning a value, yet it is also not returning an error.  You'll have to read the documentation (if there is any) on the "Open" method to see how it is supposed to behave.  One would THINK that if it wasn't going to return a session, that it would return an error, but that is actually defined by the implementation of the COM object.

If you run the above code, and you keep getting (spDispatch == NULL), then try different values for your parameter to Open().  A VARIANT can be anything.  Here are some that I would try:

     spDispatch = sessions->Open(_bstr_t("MAINFRAME.EDP"));
     spDispatch = sessions->Open((long)0);
     spDispatch = sessions->Open((long)1);

Just to see if any of those give you a value for spDispatch.
Once you get a value of spDispatch, then it is just a matter of converting it to an EXTRA::_SessionPtr, but that should be trivial.


> By the way, I really appreciate your assistance on this. Thank you.

Enough to up the points when we get it working?  :P
(Just kidding...)

Dex*
I guess it's an issue with the COM object, then. I tried all four of the spDispatch lines above. The fourth (->Open((long)1);) threw a _com_error with value -2147220992, which has text "Unknown Error" (real helpful). I'll have to check on the documentation for Open.

I've gotten this to work using JavaScript and a command line, and that still works (it uses the same principles as the C++ version). The problem is that I lose a lot of functionality using JavaScript instead of C++. It's just really puzzling, especially that the code I didn't touch suddenly quit, the JavaScript code still works, and there's no apparent reason.

This makes me think that something must be wrong in a Visual Studio related file? I know quite a bit about coding, but not much about COM objects. Would that be possible?
ASKER CERTIFIED SOLUTION
Avatar of Dexstar
Dexstar

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Okay, this is interesting -

I've had the original Extra client reinstalled on my computer. No problem, but my code still doesn't work. I ran the code (actually, the original one, in release format) on a companion's computer, and it broke his client to the point that he can't run it any more. This says to me that the code is changing something in the system (a dll or a registry entry or something) way early in the program. I think that the problem may go all the way back to this:

hr = CoInitialize(NULL);
hr = system.CreateInstance("EXTRA.System", NULL);

I tried throwing in if(FAILED(hr)), but hr doesn't fail in either case. If it's not possible that it's that line, it MUST be one of these:

sessions = system->Sessions; // try the raw function here?
session = sessions->Open(SessionName); // this is the line from above that's returning NULL
screen = session->Screen;

As aggravating as this problem is, it's also really quite interesting.