Frage

I'm trying to connect to an OPC server via openscada.

I already know the OPC server program ID given by MatrikonOPC explorer but the connection doesn't work probably due to a wrong DCOM configuration. Before to go further I would like to try to connect via the server CLSID.

How can I find out the OPC server CLSID?

War es hilfreich?

Lösung 2

There's probably other ways to find it out but I finally found an answer myself in this forum thread:

http://www.control.com/thread/1026190171

If you are on Windows, open regedit: Start -> Run -> type "regedit" + enter

Search for your OPC server program ID (ProgID) of type VendorName.OPC.Name.1.

Example: Matrikon.OPC.Universal.1

You will find several entries in the registry but in the My Computer\HKEY_CLASSES_ROOT\VendorName.OPC.Name.1 section you will see a CLSID directory containing the searched CLSID.

Andere Tipps

If you are using Windows System,

Click on START -> Run -> Enter "dcomcnfg.exe"

Expand Component Services ->Computers -> My Computer -> DCOM Config

Then locate your OPC Server and right click on that you will get all the details of your OPC Server

I am not familiar with OpenSCADA. However I have developed OPC clients in c++. If you are looking for a class id for an OPC server running locally, you can use this function:

CLSID clsid;
hr = CLSIDFromProgID(L"Matrikon.OPC.Simulation", &clsid);
printf("OPC Server clsid: %p %p %p %p%p%p%p%p%p%p%p\n", (void*)opcServerId.Data1, (void*)opcServerId.Data2, (void*)opcServerId.Data3, (void*)opcServerId.Data4[0], (void*)opcServerId.Data4[1], (void*)opcServerId.Data4[2], (void*)opcServerId.Data4[3], (void*)opcServerId.Data4[4], (void*)opcServerId.Data4[5], (void*)opcServerId.Data4[6], (void*)opcServerId.Data4[7]);

If you are connecting to an OPC server which is installed on a remote computer which has not been installed locally, you must create a connection to OPCEnum (hopefully installed on both local and remote computer). You can create an COM object on the remote server which will translate a OPC server name into a CLSID. Here is some code demonstrating this.

//the first part of an OPC client is to connect to the OPCEnum service on the remote machine so we can look up the clsid of the OPC Server (given as a string).
//This code should get a list of OPC servers on a remote or local machine assuming that OPCEnum is running.
const CLSID CLSID_OpcServerList = {0x13486D51,0x4821,0x11D2, {0xA4,0x94,0x3C, 0xB3,0x06,0xC1,0x0,0x0}}; //{ 0x50fa5e8c, 0xdfae, 0x4ba7, { 0xb6, 0x9a, 0x8f, 0x38, 0xc2, 0xfd, 0x6c, 0x27 } }; //{0x13486D50,0x4821,0x11D2, {0xA4,0x94,0x3C, 0xB3,0x06,0xC1,0x0,0x0}};
const IID IID_IOPCServerList = {0x13486D50,0x4821,0x11D2, {0xA4,0x94,0x3C, 0xB3,0x06,0xC1,0x0,0x0}}; //for some reason the interface IID is the same as the CLSID.
const IID IID_IOPCServerList2 = {0x9DD0B56C,0xAD9E,0x43EE, {0x83,0x05,0x48, 0x7F,0x31,0x88,0xBF,0x7A}};

IOPCServerList *m_spServerList = NULL;
IOPCServerList2 *m_spServerList2 = NULL;

COSERVERINFO ServerInfo = {0};
ServerInfo.pwszName = hostName; //L"localhost"; 
ServerInfo.pAuthInfo = NULL;

MULTI_QI MultiQI [2] = {0};

MultiQI [0].pIID = &IID_IOPCServerList;
MultiQI [0].pItf = NULL;
MultiQI [0].hr = S_OK;

MultiQI [1].pIID = &IID_IOPCServerList2;
MultiQI [1].pItf = NULL;
MultiQI [1].hr = S_OK;

//  Create the OPC server object and query for the IOPCServer interface of the object
HRESULT hr = CoCreateInstanceEx (CLSID_OpcServerList, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &ServerInfo, 1, MultiQI); // ,IID_IOPCServer, (void**)&m_IOPCServer);
//hr = CoCreateInstance (CLSID_OpcServerList, NULL, CLSCTX_LOCAL_SERVER ,IID_IOPCServerList, (void**)&m_spServerList);
if (hr == S_OK)
{
    printf("Part1 okay\n");
    m_spServerList = (IOPCServerList*)MultiQI[0].pItf;
    //m_spServerList2 = (IOPCServerList2*)MultiQI[1].pItf;
}
else
{
    printf("Co create returned: %p\n",(void *)hr);
    m_spServerList = NULL;
    //qDebug() << (void *)REGDB_E_CLASSNOTREG;
}



//try and get the class id of the OPC server on the remote host

CLSID opcServerId;
CLSID clsid;

if (m_spServerList)
{
    hr=m_spServerList->CLSIDFromProgID(serverName,&opcServerId);
    m_spServerList->Release();
}
else
{
    hr = S_FALSE;
    opcServerId.Data1 = 0;
    clsid.Data1 = 0;
}

//try to attach to an existing OPC Server (so our OPC server is a proxy)

if (hr != S_OK)
{   
    wprintf(L"Couldn't get class id for %s\n Return value: %p", serverName, (void *)hr);
}
else
{
    printf("OPC Server clsid: %p %p %p %p%p%p%p%p%p%p%p\n", (void*)opcServerId.Data1, (void*)opcServerId.Data2, (void*)opcServerId.Data3, (void*)opcServerId.Data4[0], (void*)opcServerId.Data4[1], (void*)opcServerId.Data4[2], (void*)opcServerId.Data4[3], (void*)opcServerId.Data4[4], (void*)opcServerId.Data4[5], (void*)opcServerId.Data4[6], (void*)opcServerId.Data4[7]);
}

//  Create the OPC server object and query for the IOPCServer interface of the object.
//Do it on the remote computer.

MultiQI [0].pIID = &IID_IOPCServer;
MultiQI [0].pItf = NULL;
MultiQI [0].hr = S_OK;

if (opcServerId.Data1)
{
    hr = CoCreateInstanceEx (opcServerId, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &ServerInfo, 1, MultiQI); 
}
else
{
    hr = S_FALSE;
}

if (hr != S_OK)
{
    m_IOPCServer = NULL;
    printf("Couldn't create server.\n");
}
else
{
    //CoCreateInstanceEx should have returned an array of pointers to interfaces. Since we only asked for 1, lets just get it.
    m_IOPCServer = (IOPCServer*) MultiQI[0].pItf;
    printf("Created remote OPC server.\n");
}

Here is also some commented out code demonstrating how you can enumerate all remote OPC servers. Interestingly, you can get the CLSID for these remote servers, but I believe there is a separate COM object you must create on the remote computer in order to back calculate a readable name for these. (I looked into it, but didn't need it myself so I have forgotten which interface it was).

//list all the OPC interfaces.

CLSID catid[2];
catid[0]=CATID_OPCDAServer10;  //= CATID_OPCDAServer10;    //OPC1.0
catid[1] = CATID_OPCDAServer20;
IOPCEnumGUID *pEnumGUID;
hr = m_spServerList->EnumClassesOfCategories(2, catid, 0, NULL, (IEnumGUID**)&pEnumGUID);
printf("Enum Result: %u", (void*) hr);

if (hr == S_OK)
{
    //pEnumGUID->Reset();

    GUID serverGUID;
    ULONG numberServers = 8;
    //pEnumGUID->Next(maxServers,serverGUIDs, &numberServers);

    while ((hr = pEnumGUID->Next (1, &serverGUID, &numberServers)) == S_OK)
    {
        WCHAR* wszProgID;
        hr = ProgIDFromCLSID (serverGUID, &wszProgID); //This probably won't work unless the same OPC server is installed locally.

        printf("server: %ls \n",wszProgID);

        CoTaskMemFree (wszProgID);
    };
}   

You can use Prosys OPC Client to browse the servers. It will show the CLSID of the selected server for you and you can copy it to clipboard.

The registry can be used locally to find out the CLSID. Remotely you seldom have access to the registry, but the client application can use OpcEnum for that.

Typically, if you are trying to connect remotely, the connection may fail with ProgID, if the application tries to use the local registry to convert the ProgID to CLSID. And ithis information is not available, when the server is not installed locally.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top