Two or more gauges calling the same update function

#1
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.
 
#3
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.
 
#4
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
#6
@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.
 
#7
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...
 
#9
@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;
    }
}
 
#11
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
 
#12
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.
 
#13
@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...
 
#15
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
 
#17
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.
 
#18
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
#19
@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?
 
#20
@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