Hello Marc,
Its a good thing you replied to this post and said that everything looks Ok. Because when I was trying to trim down the VB code so I can post it here ... I thought of a solution which worked!!!
Ok, first off, what I was trying to do was something like this:
Quote:
|
ice client -->> internet --> ice server -->> vb dll --> proprietary COM libraries
|
What I was doing from the code above is that the IceServer is creating an instance of the vb dll when it initializes. If you would recall your documentation on Chapter 14:
Threads and Concurrency with C++, you guys kept pointing out that ICE is a multi-threaded system. So from my own testing, it seems that
each calls made by the client to the server is given its own thread. So the Access Violation occurs when the newly created thread for the client is trying to access the variable initialized by the main application thread:
The pjServer was initialized by the Main Application
Quote:
bool jSocketsI::initialize() {
// Make sure that were thread safe
IceUtil::Mutex::Lock lock(_jServerMutex);
// Make sure that were connected
CoInitialize(NULL);
pjServer.CreateInstance(__uuidof(jServer));
// Return that all is well
return true;
}
jSocketsI::jSocketsI() {
// Initialize the COM environment, this
// extra call ensures that the Adapter Class will
// not go out of scope.
initialize();
}
|
and was access by the new thread here ... where it fails
Quote:
std::string jSocketsI::jclCommand(const ::std::string& command, const Ice::Current&) {
// Make sure that were thread safe
IceUtil::Mutex::Lock lock(_jServerMutex);
// Declare used variables
std::string retval;
_bstr_t data = command.c_str();
// Call the J Object and get the return parameter
retval = pjServer->jclCommand(data);
// Return the values
return retval;
}
|
My Solution
So my solution was to modify my VB DLL from an ActiveX Apartment Threaded DLL to an ActiveX EXE library (
please refer to the attached image on how I configured the VB project for this). Then I modified the my Ice Adapter in such a way that each new call made by the client will create a new instance of the ActiveX EXE library. Here's the change codes:
jSocketsI.h
Quote:
#include <jSockets.h>
#include <IceUtil/Mutex.h>
#define INITGUID
#import "..\jIceServer\bin\jIceServer.exe"
#include "icrsint.h"
using namespace jIceServer;
class jSocketsI : public jSockets {
public:
virtual ::std::string jclCommand(const ::std::string& command, const Ice::Current&);
jSocketsI();
~jSocketsI();
private:
_jServerPtr pjServer;
IceUtil::Mutex _jServerMutex;
};
|
jSocketsI.cpp
Quote:
#include "stdafx.h"
#include "jSocketsI.h"
using namespace std;
std::string jSocketsI::jclCommand(const ::std::string& command, const Ice::Current&) {
// Make sure that were thread safe
IceUtil::Mutex::Lock lock(_jServerMutex);
// Declare used variables
std::string retval;
_bstr_t data = command.c_str();
_bstr_t temp;
_jServerPtr lpjServer;
// Make a new connection to the J Server ONLY for this thread
CoInitialize(NULL);
lpjServer.CreateInstance(__uuidof(jServer));
// Call the J Object and get the return parameter
temp = lpjServer->jclCommand(data);
retval = temp;
// Uninitalize the COM Automation for this thread
CoUninitialize();
// Return the values
return retval;
}
jSocketsI::jSocketsI() {
// Initialize the COM environment, this call
// ensures that an instance of J will be running
// until this application quit
CoInitialize(NULL);
pjServer.CreateInstance(__uuidof(jServer));
}
jSocketsI::~jSocketsI() {
CoUninitialize();
}
|
So, if you would look closely in the
jSocketsI::jclCommand function, I create a local variable called
lpjServer that is initialized and closed at that function level.
Summary
As I say, this works. Unfortunately, I'm not satisfied with my solutions. Let me put it this way: To get into a living room of a house, all you need to do is walk up to the door and go in. What I just did was make my own ladder, climb up to the second floor, crawl through the window and go down the stairs just to get to the living room.
Although, because of time constraints, I'll have to stick with my current solution (until a better one comes up) and move to making an IceClient DLL that can be called by our proprietary libraries. I was wondering if anybody has insights, thought and/or ideas on this issue of mine. Also, did I really understand how ICE works or I'm just fooling myself?
Thanks.
Alex