LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

ActiveX control returns error "This handle is invalid" or "Class not registered"

I'm trying to use a an ActiveX infterface to a high end audio analyzer. The analyzer app (ATS.exe) makes two interfaces available: ATS and ATS2. I used the Create ActiveX Controller wizard to create instrument drivers for both of these. They showed up in the server list in the wizard and also appear in MS OLE/COM Object Viewer, so the app is definitely registered. However, I've tried every imaginable way to start an instance of the app with no luck. First I tried placing an ActiveX object on the main panel, and then using GetObjHandleFromActiveXCtrl() to grab the handle. This handle always came back as 0 ("This handle is invalid"). Next, I removed the ActiveX object from the main panel, and tried CA_LoadObjectFromFileEx(). This always returned a 0 handle ("This handle is invalid"). Then I tried CA_LoadObjectFromFileByClassIdEx() using the GUID from OLE/COM Object Viewer. This always returns an error saying "Class not registered".

I'm probably just doing something incredibly naive. Any help in pointing out the flaw is appreciated. If you'd like to test this, you can download the analyzer installer here:
AudioPrecision ATS.exe

static int panelHandle;
int gMainPanel;

static CAObjHandle ATShandle;

int main (int argc, char *argv[])
{
    char tempStr[255] = "";
    HRESULT CAstat;
    GUID ATSclassId = {0x1E1BBC81, 0x0814, 0x11D5, 0x91, 0x28, 0x00, 0xA0, 0xC9, 0x5D, 0xE7, 0x12};
    
    if (InitCVIRTE(0,argv,0) == 0)
        return -1;
    
    CA_InitActiveXThreadStyleForCurrentThread (0, COINIT_APARTMENTTHREADED);
    
    if((gMainPanel = LoadPanel (0, "AcousticGUI.uir", MainPanel)) < 0)
        return -1;

    DisplayPanel (gMainPanel);
   
    //GetObjHandleFromActiveXCtrl(gMainPanel,MainPanel_ATSpanel,&ATShandle);
    //CAstat = CA_LoadObjectFromFileEx("C:\\Program Files\\Audio Precision\\ATS 1.40\\ATS.exe",NULL,&ATSiid,1,LOCALE_NEUTRAL,0,&ATShandle);
    CAstat = CA_LoadObjectFromFileByClassIdEx("C:\\Program Files\\Audio Precision\\ATS 1.40\\ATS.exe",&ATSclassId,NULL,&ATSclassId,1,LOCALE_NEUTRAL,0,&ATShandle);
    
    if(CAstat < 0)
    {
        CA_GetAutomationErrorString(CAstat,errStr,200);
        sprintf(tempStr,"%s ATS returned \"%s\"",TimeStr(),errStr);
    }
    InsertTextBoxLine(gMainPanel, MainPanel_StatusPanel, -1, tempStr);
   
    RunUserInterface ();

    return 0;
}
0 Kudos
Message 1 of 18
(6,089 Views)
Howdy jlgregg,

I downloaded that software and installed it on a test machine with just LabWindows/CVI. I then used the ActiveX Controller Wizard to generate instrument drivers for two different interfaces and tested out the code you posted below without any problems. See the attached screenshots for a simplified version of what I tested.

It sounds like some registry setting is corrupt on your system. Do you see the same behavior on other systems? Try unregistering and then re-registering the activeX components. Refer to
How Do I Manually Register Type Libraries, ActiveX Controls, and ActiveX Servers?

Hope this helps!

Best Regards,
Jonathan N.
National Instruments
Download All
0 Kudos
Message 2 of 18
(6,054 Views)
Thanks for your response, and for braving the registration to download the ATS software.

From your code, it seems you don't check to see if the ActiveX object ever got instantiated. All of the code in my previous code compiles and runs fine, but I can't call any function from the ATS or ATS-2 instruments because the object handle that gets returned by CA_LoadObject... is invalid. Could you add a quick check to see if your resulting handle is valid?

Also interesting is that the DSP instrument generation will create a New_ function and EventsReg function. Neither ATS nor ATS-2 created these crucial functions. Can you explain why this is?

I have tried UnRegServer and RegServer to no avail. I am preparing a clean machine to test on now and will report back if that solves things.
0 Kudos
Message 3 of 18
(6,047 Views)
Hi jlgregg,

I tested that software is LabVIEW, TestStand, LabWindows/CVI and Visual Basic and couldn't get passed that error. This seems to be an issue with the actual software and not our software. However, if you can get it to work in Visual Basic (non-NI), then send us some example code that we can dissect. As of now, there isn't much we can do.

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 4 of 18
(6,014 Views)
To do it in VB, simply create a basic project and reference ATS and ATS2. Give a call to this code in your initialization:

Try
   AtsObj = New ATS.Global
   Ats2Obj = New ATS2.Global
   AtsEventObj = AtsObj.Events
Catch ex As Exception
   If ex.Message = "Server execution failed" Then
    MsgBox("ATS Control Software failed to start." & vbCrLf & "Program Terminiating.", MsgBoxStyle.Critical + MsgBoxStyle.OKOnly, "Fatal Error")
      End
   End If
End Try
ATSObjectsCreated = True
AtsObj.Application.Visible = TRUE
'Pass Errors to VB
AtsObj.Application.ThrowErrors = True
0 Kudos
Message 5 of 18
(5,996 Views)
Hi jlgregg,

I was able to get everthing working in LabVIEW and TestStand, but are still having issues in CVI. It might just be a matter of setting up the appropriate class and interface IDs. In your code, you had a ATSid also. What ID were you giving that parameter?

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 6 of 18
(5,962 Views)
I've made some progress. I have the ATS.exe software launching, but I still have troubles instantiating the ATS instrument. This makes it so I can't do anything with the app. I'm pretty sure the problem is in finding the right GUIDs and IIDs. Search the registry, I found the ATS2Global, but not the ATS global used in the VB code. Here's what I have so far:

int main (int argc, char *argv[])
{
    HRESULT CAstat = -1;
    char errStr[200] = "";
    GUID ATS_Application_classId = {0xE8596241, 0x140D, 0x11D5, 0x96, 0xF8, 0x00, 0x10, 0x4B, 0x70, 0xE9, 0xEC};
   
    GUID ATS2classId2       = {0xAB0622AF, 0xEF9A, 0x4895, 0x99, 0x03, 0x1E, 0xE3, 0xFB, 0x9E, 0x8B, 0xF6};
    GUID ClassID_ATS2Golbal = {0x0608FE8B, 0x2A53, 0x44E9, 0xB4, 0xA2, 0x7F, 0x4A, 0x3C, 0x90, 0xB0, 0x8D};
   
    if (InitCVIRTE(0,argv,0) == 0)
        return -1;
   
    CA_InitActiveXThreadStyleForCurrentThread (0, COINIT_APARTMENTTHREADED);
   
    if((gMainPanel = LoadPanel (0, "AcousticGUI.uir", MainPanel)) < 0)
        return -1;
   
    DisplayPanel (gMainPanel);
   
    ConfigCommPortsOnUI();

    // This was a suggestion from NI's Sue Park... still doesn't work (see wb6ent.ocx in the ATS 1.40 folder)
    //CAstat = Wb6ent_New_IBasicIdeObj (NULL,1, LOCALE_NEUTRAL,0,&ATShandle);
   
    CAstat = CA_CreateObjectByClassIdEx (&ATS2classId2, NULL, &ClassID_ATS2Golbal,1, LOCALE_NEUTRAL,0, &ATS2GlobalHandle);
    CA_GetAutomationErrorString(CAstat,errStr,200);
    sprintf(tempStr,"%s ATS returned \"%s\"",TimeStr(),errStr);
    InsertTextBoxLine(gMainPanel, MainPanel_StatusPanel, -1, tempStr);
   
    CAstat = CA_CreateObjectByClassIdEx (&ATS2classId2, NULL, &ATS_Application_classId,1, LOCALE_NEUTRAL,0, &ATShandle);
    CA_GetAutomationErrorString(CAstat,errStr,200);
    sprintf(tempStr,"%s ATS returned \"%s\"",TimeStr(),errStr);
    InsertTextBoxLine(gMainPanel, MainPanel_StatusPanel, -1, tempStr);

    RunUserInterface ();

    return 0;
}

0 Kudos
Message 7 of 18
(5,957 Views)
Here's the code to instantiate ATS and ATS2. The key was to use the right registry IDs. After that, it seemed that using the ByProperty instrument generation failed to create valid IIDs. To get around that, we are trying this with ByServer instruments (thus the Set/GetProperty calls). These Set/Get calls always return "Property is not optional".

int main (int argc, char *argv[])
{
    VBOOL ATSvisible = VTRUE; //it starts as hidden (false), so we need to see this value change.
    HRESULT CAstat = -1;
    char errStr[200] = "";
    const IID ATSiid;
    GUID ATS_Application_classId = {0xE8596241, 0x140D, 0x11D5, 0x96, 0xF8, 0x00, 0x10, 0x4B, 0x70, 0xE9, 0xEC};
    GUID RabbitGlobalId =          {0x1085634B, 0x0CC7, 0x11D5, 0x91, 0x28, 0x00, 0xA0, 0xC9, 0x5D, 0xE7, 0x12};
   
    GUID ATS2classId2       = {0xAB0622AF, 0xEF9A, 0x4895, 0x99, 0x03, 0x1E, 0xE3, 0xFB, 0x9E, 0x8B, 0xF6};
    GUID ClassID_ATS2Golbal = {0x0608FE8B, 0x2A53, 0x44E9, 0xB4, 0xA2, 0x7F, 0x4A, 0x3C, 0x90, 0xB0, 0x8D};
   
    ERRORINFO errorInfo;
    char *returnValue = NULL;
    int interfacePtr;
    int  didAddRef;
   
    if (InitCVIRTE(0,argv,0) == 0)
        return -1;
   
    CA_InitActiveXThreadStyleForCurrentThread (0, COINIT_APARTMENTTHREADED);
   
    if((gMainPanel = LoadPanel (0, "AcousticGUI.uir", MainPanel)) < 0)
        return -1;
   
    sprintf(tempStr, "\n%s,%s,%s,\n", "Opened AcousticTest:", DateStr(), TimeStr());
    printToLog(tempStr);
   
    DisplayPanel (gMainPanel);
   
    ConfigCommPortsOnUI();

    //Doesn't seem to do anything, but might be useful later
    //CAstat = Wb6ent_New_IBasicIdeObj (NULL,1, LOCALE_NEUTRAL,0,&WB6handle);

    CAstat = CA_CreateObjectByClassIdEx (&ATS2classId2, NULL, &ClassID_ATS2Golbal,1, LOCALE_NEUTRAL,0, &ATS2GlobalHandle);
    CA_GetAutomationErrorString(CAstat,errStr,200);
    sprintf(tempStr,"%s ATS returned \"%s\"",TimeStr(),errStr);
    InsertTextBoxLine(gMainPanel, MainPanel_StatusPanel, -1, tempStr);

    CAstat = CA_CreateObjectByClassIdEx(&ATS_Application_classId, NULL, &RabbitGlobalId, 0, LOCALE_NEUTRAL, 0, &ATShandle);
    CA_GetAutomationErrorString(CAstat,errStr,200);
    sprintf(tempStr,"%s ATS returned \"%s\"",TimeStr(),errStr);
    InsertTextBoxLine(gMainPanel, MainPanel_StatusPanel, -1, tempStr);
   
    CAstat = ATS_SetProperty (ATShandle, NULL, ATS_IApplicationVisible, CAVT_BOOL, VTRUE);
//    CAstat = ATS_GetProperty (ATShandle, NULL, ATS_IApplicationVisible, CAVT_BOOL, &ATSvisible);
    CA_GetAutomationErrorString(CAstat,errStr,200);
    sprintf(tempStr,"%s ATS returned \"%s\"",TimeStr(),errStr);
    InsertTextBoxLine(gMainPanel, MainPanel_StatusPanel, -1, tempStr);
   
    CAstat = ATS_IApplicationPanelOpen (ATShandle, NULL, ATSConst_apbAnalogInput, CA_DEFAULT_VAL);
    CA_GetAutomationErrorString(CAstat,errStr,200);
    sprintf(tempStr,"%s ATS returned \"%s\"",TimeStr(),errStr);
    InsertTextBoxLine(gMainPanel, MainPanel_StatusPanel, -1, tempStr);

    RunUserInterface ();

    return 0;
}
0 Kudos
Message 8 of 18
(5,952 Views)
FYI: I've tried adding:

CAstat = CA_GetInterfaceFromObjHandle (ATShandle, &ATS_IID_IApplication, 1, &ATS_IAppInterface, &didAddRef);

to get a pointer the ATS_IApplication interface, where ATS_IID_IApplication is defined in the instrument ATS.c file, but it returns "No such interface supported".
0 Kudos
Message 9 of 18
(5,944 Views)
Hi jlgregg,

Apparently the hidden attribute in the IDL file was causing CVI not to be able to access and view the creatable objects. We removed this attribute in the IDL for the top level class and then regenerated the wrappers (instrument drivers).  These wrappers will now have the top level object that you can use directly without having to write helper functions and dig around for class IDs. Attached is the CVI project and screenshot of the hidden attribute.

Hope this helps!

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 10 of 18
(5,929 Views)