Problem Invalid VESSEL3 being passed to dialog function

Zatnikitelman

Addon Developer
Addon Developer
Joined
Jan 13, 2008
Messages
2,302
Reaction score
6
Points
38
Location
Atlanta, GA, USA, North America
I've run into an interesting problem working with dialogs and Orbiter. Using the DeltaGlider's source as a guide, I'm getting a VESSEL3 pointer of a vessel, but it's not a valid vessel. Thanks to dbeachy1 finding the getHandle() function for me, I now have the OBJHANDLE. However, when I pass it to oapiIsVessel() it returns false. Unfortunately, the dialog is designed to alter a vessel as a scenario editor page. I'm currently using the same code the DeltaGlider sample project uses to get the VESSEL3*:
Code:
BOOL CALLBACK EdPgProc (HWND hTab, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   VESSEL3 *ves = (uMsg == WM_INITDIALOG ? (VESSEL3*)lParam : (VESSEL3*)oapiGetDialogContext (hTab));
   OBJHANDLE theves = ves->GetHandle();
   if(oapiIsVessel(theves))
   {
      //does not enter
      ...
   }
...
}
What do I need to do to ensure I get the right vessel?
Thanks,
Matt
 

Bibi Uncle

50% Orbinaut, 50% Developer
Addon Developer
Joined
Aug 12, 2010
Messages
192
Reaction score
0
Points
0
Location
Québec, QC
First of all, the documentation clearly says:
Note that oapiGetDialogContext() can not be used when processing the WM_INITDIALOG message. In this case, the context pointer can be acessed via lParam instead.

Therefore, you should remove it from your code inside WM_INITDIALOG.

Second, you can't cast the lParam to VESSEL3*, you need to use Windows macro LPARAM.

Your code should look something like this (I prefer using switches instead of numerous if. This code was not tested BTW.):
Code:
BOOL CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   {
   case(WM_INITDIALOG):
      {
         VESSEL3* vessel = (VESSEL3*)LPARAM(lParam);

         // This code is unnecessary, since you casted the pointer to VESSEL3,
         // you assumed that it was a vessel...
         OBJHANDLE obj = vessel->GetHandle();
         if(oapiIsVessel(obj))
         {
            //...
         }
      }
   }
   //...
}

You should be ok with this ! :thumbup:
 

Zatnikitelman

Addon Developer
Addon Developer
Joined
Jan 13, 2008
Messages
2,302
Reaction score
6
Points
38
Location
Atlanta, GA, USA, North America
It doesn't appear to have worked. Here's the code as it currently stands:
Code:
BOOL CALLBACK EdPgProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   VESSEL3* ves = (VESSEL3*)LPARAM(lParam);
   OBJHANDLE theves = ves->GetHandle();
   if(oapiIsVessel(theves))
   {
      //this is skipped because oapiIsVessel returns false;
   }
   ...
}
Very slightly altered code:
Code:
BOOL CALLBACK EdPgProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   VESSEL3* ves; = (VESSEL3*)LPARAM(lParam);
   OBJHANDLE theves = ves->GetHandle();
   switch(uMsg)
   {
   case WM_INITDIALOG:
      ves = (VESSEL3*)LPARAM(lParam);
      theves = ves->GetHandle();
      if(oapiIsVessel(theves))
      {
         //this doesn't execute either
      }
      ...
   }
   ...
}
Neither of these work as noted.
I know converting "back" to OBJHANDLE is kind of redundant, but it's a fast way of knowing if ves is a valid vessel.
Also, where is the note about oapiGetDialogContext()? I checked both the HTML documentation (what I normally use) and the PDF API_GUIDE and didn't see the note you're referencing.
Thanks.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
Therefore, you should remove it from your code inside WM_INITDIALOG.
The initial code already handles that case, by checking whether uMsg is WM_INITDIALOG, and passing lParam if it is and using oapiGetDialogContext otherwise:
Code:
(uMsg == WM_INITDIALOG ? (VESSEL3*)lParam : (VESSEL3*)oapiGetDialogContext (hTab));


Second, you can't cast the lParam to VESSEL3*, you need to use Windows macro LPARAM.
Actually, you can cast that to VESSEL* without using LPARAM, which would only make a LPARAM type... a LPARAM type.



Note that WM_INITDIALOG isn't the only case when oapiGetDialogContext doesn't return the context. I don't have the full list of messages now, but for example WM_CTLCOLORSTATIC is on it.

Does it need to be VESSEL3 passed as the context in your case, or can it be VESSEL or OBJHANDLE instead?

When do you need to check if something is the vessel? Maybe it could be done in some single WM_ message and not in all of them?
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
I've actually looked at the ScnEditor this time, and VESSEL instance isn't passed in the context in the scenario editor dialog, but instead scenario editor's instance. However, [highlight]vessel's OBJHANDLE (and not VESSEL instance)[/highlight] is passed in the lParam of WM_INITDIALOG of the TabProc.

Anyway, this is the right way to get the vessel in any place of the TabProc other than WM_INITDIALOG, or even from any place in your code, if scenario editor's window exists and you know its window handle:
Code:
OBJHANDLE hVessel;
SendMessage (hScnEditorWindow, WM_SCNEDITOR, SE_GETVESSEL, (LPARAM)&hVessel);



This should work too, as OBJHANDLE hVessel is public in the scenario editor class:
Code:
BOOL CALLBACK EdPgProc (HWND hTab, UINT uMsg, WPARAM wParam, LPARAM lParam) {
   OBJHANDLE hVes = (uMsg == WM_INITDIALOG ? (OBJHANDLE)lParam : ((ScnEditor *)oapiGetDialogContext (hTab))->hVessel);
   if (oapiIsVessel (hVes)) {
      //should enter this time
      ...
   }
...
}
 

Bibi Uncle

50% Orbinaut, 50% Developer
Addon Developer
Joined
Aug 12, 2010
Messages
192
Reaction score
0
Points
0
Location
Québec, QC
The initial code already handles that case, by checking whether uMsg is WM_INITDIALOG, and passing lParam if it is and using oapiGetDialogContext otherwise:
Code:
(uMsg == WM_INITDIALOG ? (VESSEL3*)lParam : (VESSEL3*)oapiGetDialogContext (hTab));

Oups... I misread the code. I thought he was checking if there was something in lParam and if not, he would get the oapiGetDialogContext(). Brain fart...

Actually, you can cast that to VESSEL* without using LPARAM, which would only make a LPARAM type... a LPARAM type.

I'm sure I read somewhere in MSDN that you have to use the macro to cast it. Something related the compatibility of 64-bit builds... I'll check this and I'll write back if I find it.

Edit:
I did my homeworks, and LPARAM is not a macro at all. It's simply a typedef saying that LPARAM is a LONG_PTR and WPARAM is a UINT_PTR. The problem with the 64-bit that I was talking is simply that if you write WndProc(HWND hWnd, UINT uMsg, UINT wParam, LONG lParam), the code compiles in 32-bit (because UINT can be casted to UINT_PTR), but fails in 64-bit, because the casting is impossible.
 
Last edited:

Zatnikitelman

Addon Developer
Addon Developer
Joined
Jan 13, 2008
Messages
2,302
Reaction score
6
Points
38
Location
Atlanta, GA, USA, North America
Thanks to talking with orb on IRC and some pokings around, I figured out how to get a valid OBJHANDLE. It is passed as the lParam so all I had to do was:
Code:
OBJHANDLE hves = (OBJHANDLE)lParam;

But now I have another unrelated problem, but I hate spamming the forum with small questions so I'll ask here. I'm using a spin control, but visual studio can't seem to find UDM_SETBUDDY in order to pair the control with an edit control. What's going on? Shouldn't this message be with all the other dialog controls?
 

Hielor

Defender of Truth
Donator
Beta Tester
Joined
May 30, 2008
Messages
5,580
Reaction score
2
Points
0
Have you tried using UDS_AUTOBUDDY as a style on the spin control?
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
Include "CommCtrl.h".
 

dbeachy1

O-F Administrator
Administrator
Orbiter Contributor
Addon Developer
Donator
Beta Tester
Joined
Jan 14, 2008
Messages
9,218
Reaction score
1,566
Points
203
Location
VA
Website
alteaaerospace.com
Preferred Pronouns
he/him
:hesaid:

BTW you can see what header file a given message or method needs by checking the 'Requirements' section of the Windows API documentation for the given message/method. e.g., from the UDM_SETACCEL message (Windows) page:

Requirements

Minimum supported client: Windows 2000 Professional [desktop apps only]
Minimum supported server: Windows 2000 Server [desktop apps only]
Header: Commctrl.h

:tiphat:
 
Top