• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

Two or more gauges calling the same update function

Messages
43
Country
us-texas
After a few days of trial and error, looking in the SDK, other forums, and this one, I can't find where this is specified or prohibited. Is it possible for two or more gauges (GDI+), with the proper gauge declarations, utilize the same 18hz update function call in a DLL? Or does each gauge declaration have to have their own update function? I'm wondering how does the update function know which gauge the parameter PGAUGEHDR pGauge belongs to.
 

JB3DG

Resource contributor
Messages
1,325
Country
southafrica
You mean the panel service pre update case in the gauge callback?
 
Messages
531
Country
france
I confirm several gauges can use the same gauge callback if needed, this is not prohibited.
But you have to be careful if the gauge callback is in charge of drawing using GDI+ because the HDC on which you base the Graphics instance is not the same for all gauges.
 
Messages
43
Country
us-texas
Thank you @eric_marciano I have one follow-up the reference to an HDC variable (I'm familar with it, just never programmed in GDI+ before now); All I have is an HMODULE. I have one GDI+ gauge working, but the model hasn't caught up with the code yet on the other gauge so I have time to figure this out. Can you elaborate on how an HDC used in this context?
 

JB3DG

Resource contributor
Messages
1,325
Country
southafrica
@Jim Johnson just an FYI, if you are using the MSDN GDI+ example which I posted in the resources section, although the code appears to be using the same callback for all gauges, it is actually using a instantiated class method, which means the callback is basically different for every gauge instance that uses it, even if you have multiple instances of the same gauge with different 5th parameters.
 
Messages
531
Country
france
Jim, you are correct. As you could see on the code sample provided, the Graphics instance is created by providing the HDC. The code shown here can work with the same callback invoked for all gauges because a new Graphics call is instantiated each time the callback is invoked, it works. But this is not what I usually do. In my code, each gauge has its own Graphics instead, created once when the gauge is created, which avoids having to re-create it at each drawing cycle. I did this to make it faster, but I am not sure it is worth it...
 
Messages
43
Country
us-texas
@JB3DG Thank you for your help, I referred to it as an example as the base class (was derived from the example) and two derived classes that make up one of the gauges.
@eric_marciano Thank you as well.
 
Messages
43
Country
us-texas
@eric_marciano So to acquire an HDC I assume something like this example snippet would work:

Code:
    case PANEL_SERVICE_PRE_DRAW:
            PELEMENT_STATIC_IMAGE pelement = reinterpret_cast<PELEMENT_STATIC_IMAGE>(pGauge->elements_list[0]);
            if (pelement)
            {
                HDC hdc = pelement->hdc;

                if (hdc)
                {
                    if (pGunsight)
                        pGunsight->DrawGraphics(pGauge);
                }
            }
            break;
    }
}
 
Messages
531
Country
france
@eric_marciano So to acquire an HDC I assume something like this example snippet would work:

Code:
    case PANEL_SERVICE_PRE_DRAW:
            PELEMENT_STATIC_IMAGE pelement = reinterpret_cast<PELEMENT_STATIC_IMAGE>(pGauge->elements_list[0]);
            if (pelement)
            {
                HDC hdc = pelement->hdc;

                if (hdc)
                {
                    if (pGunsight)
                        pGunsight->DrawGraphics(pGauge);
                }
            }
            break;
    }
}
Yes, exactly
 
Messages
43
Country
us-texas
Guys, I finally had a chance to test this code today and when I went to get an HDC as in the example code above (which I simplified for this discussion) this is what I see in the debugger. Note that the earlier snippet was particular to the Gunsight class itself, this screenshot is the same call to the gunsight but with an intermediate class that controls all of the "avionics" that use GDI+ like the gunsight. It has a separate gauge declaration and update function from another GDI+ gauge (there are only two at this point). I guess the question is now what? Since the HDC isn't used according to the Debugger, I have no idea where to go next to get this cockpit working again.

gdi+debug.jpg
 
Messages
2,077
Country
us-ohio
HDC is a numeric value... it is not a struct, nor a class. What you're not showing is the actual value of hdc. You are apparently trying to see inside it?? If so... you can't. Nothing to see. Also, not certain why you're checking for a valid HDC and then passing the entire gauge header to the render routine.... but, each their own. :) Just to be clear, the only time pelement->hdc is valid is when it is a static image with a IMAGE_CREATE_DIBSECTION flag.
 
Messages
43
Country
us-texas
@WarpD Thanks for the information, I assumed that it was a numeric value. :) Earlier today I went back and looked at the example again and how for this solution I structured it. There is a single place that the whole HDC thing gets done in a base class. So that isn't what's stopping the second GDI+ gauge from displaying. I have one GDI+ gauge that works (and has for months) and one that doesn't. I'm doing something wrong with the callbacks (tried one callback for both and individual callbacks for each) or something else. The search continues...
 

JB3DG

Resource contributor
Messages
1,325
Country
southafrica
How are you identifying which gauge is which in the code?
 
Messages
43
Country
us-texas
Here are the gauge declarations:

C++:
/////////////////////////////////////////////////////////////////////////////
// T37 DMEIndicator Declaration
/////////////////////////////////////////////////////////////////////////////
#define GAUGE_NAME    "T37\0" //Note this is actually the DME Indicator
#define GAUGEHDR_VAR_NAME gaugeHeader_T37
#define GAUGE_H  400
#define GAUGE_W  400

char t37Gauge_name[] = GAUGE_NAME;
extern PELEMENT_HEADER t37List;

static const GUID t37GaugeGuid = { 0x4e99c0e, 0xfd53, 0x4cc5,{ 0x89, 0xf1, 0xd5, 0x49, 0x98, 0xa2, 0x3a, 0xcd } };

void _stdcall t37Update(PGAUGEHDR pGauge, int service_id, UINT_PTR extra_data);

GAUGE_HEADER_FS1000(GAUGEHDR_VAR_NAME, GAUGE_W, t37Gauge_name, &t37List, 0, (GAUGE_CALLBACK *)t37Update, 0, 0, t37GaugeGuid, 0, 0, 0, 0, 0);

MAKE_STATIC(t37DMEImage, BMP_TCN_DME, NULL, NULL, IMAGE_USE_BRIGHT | IMAGE_CREATE_DIBSECTION | IMAGE_USE_TRANSPARENCY | IMAGE_USE_ALPHA | IMAGE_USE_ERASE | IMAGE_ERASE_ALWAYS, 0, 0, 0)

PELEMENT_HEADER t37List = &t37DMEImage.header;

#undef GAUGE_NAME
#undef GAUGEHDR_VAR_NAME
#undef GAUGE_H
#undef GAUGE_W

/////////////////////////////////////////////////////////////////////////////
// Gunsight Gauge Declaration
/////////////////////////////////////////////////////////////////////////////
#define     GAUGE_NAME          "Gunsight\0"
#define     GAUGEHDR_VAR_NAME   gaugehdr_Gunsight
#define     GAUGE_H                400
#define     GAUGE_W                400

char gunsight_name[] = GAUGE_NAME;
extern PELEMENT_HEADER gunsight_element_list;

static const GUID gunsight_guid = { 0x89c1b165, 0x667b, 0x4721, { 0x89, 0x31, 0x21, 0x1b, 0x0f, 0x86, 0x4f, 0x07 } };

void _stdcall gunsightUpdate(PGAUGEHDR pGauge, int service_id, UINT_PTR extra_data);

GAUGE_HEADER_FS1000(GAUGEHDR_VAR_NAME, GAUGE_W, gunsight_name, &gunsight_element_list, 0, (GAUGE_CALLBACK *)gunsightUpdate, 0, 0, gunsight_guid, 0, 0, 0, 0, 0);

MAKE_STATIC(gunsight_image, BMP_GUNSIGHT, NULL, NULL, IMAGE_USE_BRIGHT | IMAGE_CREATE_DIBSECTION | IMAGE_USE_TRANSPARENCY | IMAGE_USE_ALPHA | IMAGE_USE_ERASE | IMAGE_ERASE_ALWAYS, 0, 0, 0)

PELEMENT_HEADER gunsight_element_list = &gunsight_image.header;

#undef GAUGE_NAME
#undef GAUGEHDR_VAR_NAME
#undef GAUGE_H
#undef GAUGE_W
 
Messages
43
Country
us-texas
I split them out as combining them didn't have any different effect on the display or non-display of the gauges. Here's the DME Indicator that works:

C++:
void FSAPI t37Update(PGAUGEHDR pGauge, int service_id, UINT_PTR extra_data)
{
    switch (service_id)
    {
        case PANEL_SERVICE_PRE_UPDATE:

        //Optional code to inhibit update while
        lookup_var(&eTime);
        if (eTime.var_value.n == prevTime)
            break;
        else
            prevTime = eTime.var_value.n;

        if (pIElectricalPowerSupplySystem)
            pIElectricalPowerSupplySystem->integrate();

            break;
            
            //... code removed for brevity
            
    case PANEL_SERVICE_POST_INSTALL:

        if (pICommunicationAndAssociatedElectronicSystems)
            pICommunicationAndAssociatedElectronicSystems->InitGraphics(reinterpret_cast<PELEMENT_STATIC_IMAGE>(pGauge->elements_list[0]));

        break;

    case PANEL_SERVICE_PRE_DRAW:

        if (pICommunicationAndAssociatedElectronicSystems)
            pICommunicationAndAssociatedElectronicSystems->DrawGraphics(pGauge);

        break;
    }
}

This is the one that I commented out and when I uncomment it, the declaration (previous post), and the gauge linkage it fails and kills the DME Indicator as well:

C++:
void FSAPI gunsightUpdate(PGAUGEHDR pGauge, int service_id, UINT_PTR extra_data)
{
    switch (service_id)
    {
        case PANEL_SERVICE_PRE_UPDATE:

            //Optional code to inhibit update while
            lookup_var(&eTime);
            if (eTime.var_value.n == prevTime)
                break;
            else
                prevTime = eTime.var_value.n;

            if (pIOffensiveAvionics)
                pIOffensiveAvionics->integrate();

            if (pIOffensiveAvionics)
                pIOffensiveAvionics->OnUpdate();

            break;

        case PANEL_SERVICE_POST_INSTALL:

            if (pIOffensiveAvionics)
                pIOffensiveAvionics->InitGraphics(reinterpret_cast<PELEMENT_STATIC_IMAGE>(pGauge->elements_list[0]));

            break;

        case PANEL_SERVICE_PRE_DRAW:

            if (pIOffensiveAvionics)
                pIOffensiveAvionics->DrawGraphics(pGauge);

            break;
    }
}

@JB3DG This is the last big hurdle before finishing this aircraft (my first) for a beta...your help has been and is greatly appreciated.
 
Messages
2,077
Country
us-ohio
So, they're two completely different gauges... they are NOT using the same callback function... they're both GDI+ gauges and if you try to run both of them... they both fail, but if you only create the DME it works?? How are you creating the gauge table entries?
 

JB3DG

Resource contributor
Messages
1,325
Country
southafrica
@Jim Johnson Everything looks good there. I will mention that I normally don't use separate Bitmap resources (BMP_GUNSIGHT vs BMP_TCN_DME) in my gauges. I use one and the same for all as it doesn't really matter in the end. You are creating a Device Independent Bitmap in memory of its own dimensions, getting the HDC from it, and drawing directly to it. The actual bitmap resource is just there to satisfy the requirements of the MAKE_STATIC macro.

Like Ed has just asked though, can we see your GAUGESLINKAGE table?
 
Messages
43
Country
us-texas
@JB3DG and @WarpD Thank you both for your help. @WarpD I had one callback/update function, then two...just to see what would happen. Then I just left it as two. Here's the gauges linkage table:

C++:
/////////////////////////////////////////////////////////////////////////////
// Gauges Linkage Table
/////////////////////////////////////////////////////////////////////////////
GAUGESLINKAGE Linkage = {
    0x00000013,
    module_init,
    module_deinit,
    0,
    0,
    FS9LINK_VERSION,
    {
        &gaugeHeader_T37,
        &gaugehdr_Gunsight,
        0
    }
};
 
Top