C++ Question Can't redraw standard MFD labels

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
Hi all,

I'm working on a spacecraft with a .dll. I'm a complete C++ noob, and using VC++ 2008 express edition. I'm trying to put toghether a VC and am currently busy with standard MFD's.

I got to the point of correctly displaying the MFD's and making buttons work - now I'm stuck with the redraw of labels. Here's the code:

Code:
bool Strelka::clbkVCRedrawEvent(int id, int event, SURFHANDLE surf)
{
  int bt;
  const char *label;
  switch (id)
  {
    case AID_MFD_R_LEFT:
      hDC = oapiGetDC (surf);
      for (bt = 0; bt<6; bt++)
      {
        if (label = oapiMFDButtonLabel (MFD_RIGHT, bt))
        TextOut (hDC, 5, 2+20*bt, label, strlen(label));
        else break;
      };
    case AID_MFD_R_RIGHT:
      return true;
  };
oapiReleaseDC (surf, hDC);
return true;
}

I derived it from the OrbiterSDK API Guide and the code samples that come along with it (DG and ShuttleA). The point is that when I try and compile I get the following compiling error:

1>.\Strelka.cpp(134) : error C2664: 'TextOutW' : cannot convert parameter 4 from 'const char *' to 'LPCWSTR'
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

Some Google told me that the point lies in the charachter set (UNICODE or ANSI), thus I tried changing the configuration properties of my project from [Use Unicode Charachter Set] to [Use Multi-Byte Charachter Set]. The code compiles but I get a CTD if I try to switch to VC. Same result by keeping [Use Unicode...] and changing the line

TextOut (hDC, 5, 2+20*bt, label, strlen(label));

to

TextOut (hDC, 5, 2+20*bt, (LPCWSTR) label, strlen(label));

i.e.: it compiles, but I get a CTD when going to VC.

Some more Google pointed me to functions that perform the seemingly required conversion, but I find no trace of this in any of the Orbiter sample code, and noone else in the forum seems to have had the same problem, so I thought there might be a simpler solution - as I'm not quite sure how to implement these conversion functions.

A bit more of information that could be helpful: I'm using a texture for MFD and a different texture for buttons, which is flagged for Decompression.

Anyone can help?

Thank you,
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
I get the same error compiling an MFD addon if I have [Use Unicode...]. Using [Use Multi-Byte...] or [Not set] works fine. You would not expect the return string from oapiMFDButtonLabel to contain unicode.
 

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
Yes that goes for me, meaning if I take out that code snippet above and compile with Multi-Byte or no charachter set everything's fine, but WITH the code I get the CTD. What is it I am missing?
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
Looking at it, I would expect a compiler error to be raised as you are assigning to a const (label is defined as const, yet you are assigning to it)

Is the problem that you've previously released your handle to the device context in the previous call to the function? That may be the problem, rather than the label string. What is the value/contents of "label" when the call is made?
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
Yes that goes for me, meaning if I take out that code snippet above and compile with Multi-Byte or no charachter set everything's fine, but WITH the code I get the CTD. What is it I am missing?
I should clarify: I can successfully use TextOut to put text on the MFD DC with [Not set] in the options. Can you use the debugger to see what values you have for the arguments to TextOut?
 

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
I'll try debugging and update on outcome (I'm at work now ;))

---------- Post added at 11:59 PM ---------- Previous post was at 05:13 PM ----------

Here. I think you pointed me in the right direction somehow. I still missed the oapiTriggerRedrawArea functions, which I coded in, then moved the code above into a RedrawMFDButtons function which is called by clbkVCRedrawEvent. Now I compile with either Multi-Byte or No Set, buttons still work and I get no more CTD. I can't provide you with the contents of the [label] string as I can't make out how to debug with VC++.

But the problem's still there, meaning that I see no labels. Maybe I'm passing the wrong inputs to TextOut? In other words: in

TextOut (hDC, x, y, label, strlen (label))

x and y are 'logical coordinates', which I don't know the meaning of. From the code samples they don't look like texture coordinates. How do I set them?

In the DG cockpit mesh the button mesh group has no texture, no material, and is flagged 4. I used the same settings but still labels don't show up.

Thank you for your help...
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
I can't provide you with the contents of the [label] string as I can't make out how to debug with VC++.
Debugging's quite easy. At the top of your VS window, there should be a drop down menu saying eitheir "Release" or "Debug". If not, then it's on the "Standard" toolbar, or you can get at it by setting the current configuration (Build --> Configuration --> Active configuration).

Once you've set this to debug, you need to set the output directory in your project (Project --> Properties --> Configuration Properties --> Linker --> General --> Output file) to copy the DLL to in the plugins or modules directory in the orbiter directory (where you install it to). Make sure that the active configuration is set to debug! From there, go to Project --> Properties --> Debugging and set the 'command' option to be orbiter.exe and set "Working Directory" to be the directory that orbiter.exe is in.

From there, all you need to do is hit F5 (or the play icon in the tool bar) and orbiter will run (best run orbiter in windowed mode!). If you go to a line of code and press F9, a red blob will appear next to it. This is a breakpoint and the execution of the code will stop when it reaches here. You can then view the value of variables (Debug --> Windows -->Autos/Locals/Watch) and step through the code one line at a time with F10.

Maybe we should make a tutorial for this as it's so important.
 

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
I followed the directions. I got a message saying that orbiter.exe is not built with debugging information, anyways I got on with debug and got <undefined> as a value for [label] when I make the assigment in the [if] section. I understand this is the problem both Agentgonzo and Tblaxland were suggesting?

I actually just copied that bit so I myself cannot understand why I have to assign to a constant when I make a test for a condition - but looks like what the sample code e.g. of DeltaGlider does.

To me it looks like I'm doing nothing different from what the API guide and code samples show, but I'm currently reviewing those to pinpoint where I break from the road of truth.
 

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
I actually just copied that bit so I myself cannot understand why I have to assign to a constant when I make a test for a condition - but looks like what the sample code e.g. of DeltaGlider does.
This is just a shortcut for
Code:
label = oapiMFDButtonLabel(...);
if (label) {
   ...
}
Your code looks a bit mixed up: you assign the HDC inside one of your switch conditions, but you release it globally.
Also, your AID_MFD_R_LEFT switch isn't terminated with a break, so the following AID_MFD_R_RIGHT code will also be executed, which means that the HDC is never released.

No guarantee that fixing these bugs will solve your problem, but it is a first step.
 

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
I cleaned up things a bit (I think). Now I have the following:

Code:
bool Strelka::clbkVCRedrawEvent(int id, int event, SURFHANDLE surf)
{
  switch (id)
  {
  case AID_MFD_R_LEFT:
    RedrawMFDButtons (surf, MFD_RIGHT, 0);
    return true;
  };
  return false;
}
 
...
 
void Strelka::RedrawMFDButtons (SURFHANDLE surf, int mfd, int side)
{
  HDC hDC = oapiGetDC (surf);
  const char *label;
    for (int bt = 0; bt<6; bt++)
    {
      if (label = oapiMFDButtonLabel (MFD_RIGHT, bt))
        TextOut (hDC, 0, 0+bt*20, label, strlen (label));
      else break;
     }
   oapiReleaseDC (surf, hDC);
}

If I got Martin right, now the HDC is assigned and released in the right context (hoping I'm using terms correctly here). Debug seems to confirm as the value of [hDC] changes from 0xA911BB7 to 0xCDCDCDCD when the code is executed.

But Debug also shows [label] invariably as <undefined value>. So there's something wrong in the way I use oapiMFDButtonLabel, I should think?
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
code]

If I got Martin right, now the HDC is assigned and released in the right context (hoping I'm using terms correctly here). Debug seems to confirm as the value of [hDC] changes from 0xA911BB7 to 0xCDCDCDCD when the code is executed.
Which part of code? 0xCDCDCDCD sounds like an invalid handle to me, which is fine if it's the ReleaseDC that's doing it, but likely to fail if it's the GetDC.

But Debug also shows [label] invariably as <undefined value>. So there's something wrong in the way I use oapiMFDButtonLabel, I should think?
I still think that something is wrong with this, as you have defined label as a const and then you are trying to assign to it? I'm very surprised that the compiler isn't throwing an error at this. Is it giving you a warning? If so, then what I imagine is happening is that the compiler is *not* doing the assignment and is warning you about this, and you may (like most VS nwebies) ignore the warnings to your detriment. Either way, you should not be assigning to a const. Remove the const from the label declaration. As label is undefined I'm not surprised that TextOut is failing. This is the step that you need to address.

In short, change label so that it's not const and *always* try to result in code that has *no* warnings (if you are just ignoring warnings at present).
 

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
0xCDCDCDCD sounds like an invalid handle to me, which is fine if it's the ReleaseDC that's doing it, but likely to fail if it's the GetDC.

I should have been clearer here: yes that's the ReleaseDC that's doing it, so it is fine.

Is it giving you a warning? [...] you should not be assigning to a const. Remove the const from the label declaration. As label is undefined I'm not surprised that TextOut is failing. This is the step that you need to address.

I took your advice when you pointed this out to me earlier. But the fact is that when I compile the code as you see it (meaning, assigning to the constant), I get no error and NO warning. Still I removed the [const] from the declaration and I get the following:

1>.\Strelka.cpp(156) : error C2440: '=' : cannot convert from 'const char *' to 'char *'
1> Conversion loses qualifiers

'char *' is how I declared [label], 'const char *' is what is required from oapiMFDButtonLabel, as I derive from the fact that the error happens at line 156, which is actually

if (label = oapiMFDButtonLabel (MFD_RIGHT, bt))

I agree that this is the step I need to address, but I cannot make out why [label] is not defined.
 

tblaxland

O-F Administrator
Administrator
Addon Developer
Webmaster
Joined
Jan 1, 2008
Messages
7,320
Reaction score
25
Points
113
Location
Sydney, Australia
I still think that something is wrong with this, as you have defined label as a const and then you are trying to assign to it?
The return type of oapiMFDButtonLabel is "const char *" so the receiving variable needs to be const so that the const-ness is respected. As you can see above, the compiler spits a error if it is not.

There is no problem with the assignment or declaration. To demonstrate, I find it useful to read declarations right to left, so "const char *label" means: label is a pointer(*) to a char that is const. In other words, label is not const but what it points to is:
Code:
label = malloc(5*sizeof(char)); // legal
*label = 'h' // illegal
DesideriusPapp, a problem with the code you posted:
Code:
void Strelka::RedrawMFDButtons (SURFHANDLE surf, int mfd, int side)
{
  HDC hDC = oapiGetDC (surf);
  const char *label;
  [B][COLOR=Red]int bt; [/COLOR][/B]// bt must be declared here otherwise its scope will be limited to the bit inside the braces of: for(...)
    for ([COLOR=Red][B]bt = 0[/B][/COLOR]; bt<6; bt++)
    {
      if (label = oapiMFDButtonLabel (MFD_RIGHT, bt))
        TextOut (hDC, 0, 0+bt*20, label, strlen (label));
      else break;
     }
   oapiReleaseDC (surf, hDC);
}
Also, you say label always has <undefined value> which indicates that you are getting no proper return value from oapiMFDButtonLabel which would be very strange. Can you put a breakpoint on the TextOut line and give us a screen grab showing the "Locals" tab once the breakpoint is hit? (the "Locals" tab should be one of the ones at the bottom of the screen and should show the variable "label" in there automatically)
 

Matt Decker

New member
Joined
May 9, 2008
Messages
40
Reaction score
0
Points
0
Location
Denver
error C2664: 'TextOutW' : cannot convert parameter 4 from 'const char *' to 'LPCWSTR'

I had the same problem with something I'm working on. I pulled my hair out for days before I found the answer somewhere on the internet.

It was one of the following settings in the project properties.

Configuration Properties
C/C++
Precompiled Headers

Pre Compiled Headers = OFF

Configuration Properties
General
Character Set = Use Multi-Byte Character Set

I forget which one was for this error, but I found that both of these settings are need for it to work.

 

Hielor

Defender of Truth
Donator
Beta Tester
Joined
May 30, 2008
Messages
5,580
Reaction score
2
Points
0
DesideriusPapp, a problem with the code you posted:
Code:
void Strelka::RedrawMFDButtons (SURFHANDLE surf, int mfd, int side)
{
  HDC hDC = oapiGetDC (surf);
  const char *label;
  [B][COLOR=Red]int bt; [/COLOR][/B]// bt must be declared here otherwise its scope will be limited to the bit inside the braces of: for(...)
    for ([COLOR=Red][B]bt = 0[/B][/COLOR]; bt<6; bt++)
    {
      if (label = oapiMFDButtonLabel (MFD_RIGHT, bt))
        TextOut (hDC, 0, 0+bt*20, label, strlen (label));
      else break;
     }
   oapiReleaseDC (surf, hDC);
}
There is no problem here. Since he is not using bt outside of the for block, there is no need for it to be declared separately.

error C2664: 'TextOutW' : cannot convert parameter 4 from 'const char *' to 'LPCWSTR'

I had the same problem with something I'm working on. I pulled my hair out for days before I found the answer somewhere on the internet.
Yes, Orbiter does not use Unicode...
 

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
Here you go:


Strelka-00-Tests.png


I tried TextOut with a dummy label ("abc") outside the [if], just to see if the problem had something to do with my texture, but the label shows up all right.
The snapshot above is from the 'else break' line because the TextOut is not hit at all (presumably because i don't get the return from oapiMFDButtonLabel).
I also tried moving oapiMFDButtonLabel to a different point in the code (namely, in clbkVCMouseEvent) and debugged, and in that case the function DID return the correct label.

As for the UNICODE issue, I don't know if I'm entitled to, but I'd suggest to add it to the Compiler Setup tutorial...

I made another trial: I put a breakpoint in clbkVCRedrawEvent when RedrawMFDButtons (surf, MFD_RIGHT) is called. here, the 'Locals' tab shows an error for surf: cannot obtain value. The code goes on, a value is passed anyway to the surf argument in RedrawMFDButtons and it should be the right one because I then pass this to oapiGetDC and draw the dummy label outside of the if block. Then the if block is skipped, execution goes back to clbkVCRedrawEvent. At this point in the 'Locals' tab surf is greyed out. Mousing over tells me that the expression could not be evaluated because a value could not be retrieved. If I re-evaluate at this point, the error (cannot obtain value) comes back. May be here lies the problem?
 
Last edited:

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
So oapiMFDButtonLabel never returns a nonzero result? Are you sure that your AID_MFD_R_LEFT identifier refers to the left column of buttons on the right MFD, rather than the other way round? The name is a bit ambiguous.
 

agentgonzo

Grounded since '09
Addon Developer
Joined
Feb 8, 2008
Messages
1,649
Reaction score
4
Points
38
Location
Hampshire, UK
Website
orbiter.quorg.org
The return type of oapiMFDButtonLabel is "const char *" so the receiving variable needs to be const so that the const-ness is respected. As you can see above, the compiler spits a error if it is not.

There is no problem with the assignment or declaration. To demonstrate, I find it useful to read declarations right to left, so "const char *label" means: label is a pointer(*) to a char that is const. In other words, label is not const but what it points to is:
Wow, You learn something new every day!
 

DesideriusPapp

New member
Joined
May 23, 2009
Messages
21
Reaction score
0
Points
0
Are you sure that your AID_MFD_R_LEFT identifier refers to the left column of buttons on the right MFD

Yes, I checked that too. I've not yet defined any button for the left MFD.
 
E

ex-orbinaut

Guest
Hi,

Recently went through all of this, too. Integrating the textures, meshes and code is extremely trying when you are first starting off with the API. If it is any help I published a demonstration ship with some basic code and some pointers to organizing textures and meshes. There is a thin chance there might be something in there to help you....

[ame="http://www.orbithangar.com/searchid.php?ID=4054"]AstroMatizII[/ame]

All the best.
 
Top