none
Interop problem, client recieves NULL object, but server sends notNULL RRS feed

  • Question

  • Hello everyone,

     I'm developing an OPC client (in C#) and an OPC server (in C++ COM). The client is tested with Martrikon's and Iconics' free OPC server(both COM) and works fine (functionally as well as the interoperability).

     However, I found some troublesome bug, I try to explain with some steps:
     - server starts (all the COM components are registered in the registry)
     - client starts and connects to server
     (
     I used

            Type srv = Type.GetTypeFromProgID(ProgID);
            myServer = (IOPCServer)Activator.CreateInstance(srv, false);

    and it returns a valid server object
     )
     -client tries to call a method (AddGroup) on the server and this is where the exception occurs
     Details:
     server method

    HRESULT CServer::AddGroup(LPCWSTR szName, BOOL bActive, DWORD dwRequestedUpdateRate, OPCHANDLE hClientGroup, LONG *pTimeBias, FLOAT *pPercentDeadband, DWORD dwLCID, OPCHANDLE *phServerGroup, DWORD *pRevisedUpdateRate, REFIID riid, LPUNKNOWN *ppUnk)
    {
    	...
    
    	*phServerGroup = ServerGroupHandle++;
    
    	...
    
    	HRESULT hr;
    	if(dwRequestedUpdateRate >= 100){
    		*pRevisedUpdateRate = dwRequestedUpdateRate;
    		hr = 0; // S_OK
    	}
    	else{
    		*pRevisedUpdateRate = 100;
    		hr = 0x0004000DL; // OPC_S_UNSUPPORTEDRATE
    	}
    
    	COPCGroup* g = new COPCGroup(szName, bActive, dwRequestedUpdateRate, hClientGroup, pTimeBias, pPercentDeadband, dwLCID, phServerGroup, pRevisedUpdateRate);
    
    	...
    	
    	if (riid == IID_IOPCGroupStateMgt) 
    		*ppUnk = (LPUNKNOWN)((IOPCGroupStateMgt*)g);
            return hr;
    }
    


    client method

        public void AddGroup(string name, int bActive, uint dwUpdateRate, float fDeadband, ref uint phGroup) { 
          Guid IID_IOPCGroupStateMgt = new Guid ("39C13A50-011E-11D0-9675-0020AFD8ADB3");
          uint hServerGroup;
          uint dwRevUpdateRate = 0;
          int pTimeBias = 0;
          object pUnk;
    
          try
          { 
            myServer.AddGroup(name, bActive, dwUpdateRate, ++hClientGroup, ref pTimeBias, ref fDeadband, 0, out hServerGroup, out dwRevUpdateRate, ref IID_IOPCGroupStateMgt, out pUnk);
    
            phGroup = hServerGroup;
            myGroups.Insert(/*(int)hServerGroup*/numGrps++ , new OPC_Group(pUnk, name, mydwFlags, phGroup));
          }
          catch (Exception e) {
            Console.WriteLine(e.ToString());
          }
        }


    The clients calls the server correctly, the server executes the method without errors, and returns all out and ref parameters correctly except the ppUnk which is set to NULL when it arrives to the client, although the server generated the value.

     The client throws the exception:
     BadImageFormatException "Invalid access to memory location. (Exception from HRESULT: 0x800703E6)" at AddGroup(...).
     While the server states in the Immediate Window the following at that moment:
     First-chance exception at 0x7c80980f in OPCDAServerCOM.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.
     First-chance exception at 0x7c809823 in OPCDAServerCOM.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.

     I experimented around and found a peculiar circumstance, namely if I modify the assignment of ppUnk in the server AddGroup to

    ppUnk = new LPUNKNOWN((IOPCGroupStateMgt*)g);

    no exception occurs, but in the client the pUnk is still NULL.

     At last I find it important to mention that during the debugging of the server, the method is completed successfully but after that, when using step by step debugging, I'm redirected to the disassembly of the server, and there the exception is thrown somewhere, but I wasn't able to track down where.

     What do you think the problem is? Any suggestions in what direction I should look will help, because I'm pretty much out of idea. The only thing that goes through my mind is that the error lies somewhere in the ptr-to-ptr assignment. I doubt there are any interoperability issues, given that the client was tested on other COM server and that the method's signature is defined by the OPC specification.

     Thank you

     PS:
     A few words to the semantics of the method:
     As you might guess, the client calls this method to add a group to the server, and expects, among the other parameters, to get the COPCGroup object back (via pUnk). The interface cast is necessary, because it is required that the client specifies the interface which is to be returned by the server.

    Friday, July 29, 2011 8:47 AM

All replies