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.