我在VC6.0平台下用ATL编写COM组件(没有选择对MFC类库的支持),接口函数UpdateRole(SAFEARRAY **pSaRole),安全数组封装的是自定义的结构体(RoleInfo),以下是组件函数代码,函数可以实现更新数据的目的,但是当调用完成后,返回的不是S_OK,
而是错误码0x8002000d,内存已锁定,如果接口函数传递oleautomation类型的参数不会产生这种错误。我现在是一头雾水,不知道从哪里着手,请高手指点,谢谢!STDMETHODIMP CSysMgr::UpdateRole(SAFEARRAY **pSaRole)
{
// TODO: Add your implementation code here
USES_CONVERSION;
_bstr_t bstrSQL, bstrRoleID; 

RoleInfo* pRole = NULL;
SafeArrayAccessData(*pSaRole, (void**)&pRole);//从安全数组中取出数据
//nRoleID在结构体中是short类型,先将整型转换为字符型,然后从ANSI编码转换成Unicode编码,
//我本来想用_itow函数,但是不成功,不知道为什么
char ch[5] = "";
itoa(pRole[0].nRoleID, ch, 10);
bstrRoleID = A2BSTR(ch);
// _itow(pRole[0].nRoleID, bstrRoleID, 10);
_bstr_t bstrRoleName = pRole[0].bstrRoleName;
_bstr_t bstrOwner = pRole[0].bstrOwner;
short nRight = pRole[0].nRight;
SafeArrayUnaccessData(*pSaRole);
SafeArrayDestroy(*pSaRole); 
//SQL SERVER数据库表role,主键roleID
bstrSQL = "SELECT * FROM role WHERE roleID = '" + bstrRoleID + "'";
_ConnectionPtr pConnection;
_RecordsetPtr pRecordset;
pConnection.CreateInstance("ADODB.Connection");
pRecordset.CreateInstance(__uuidof(Recordset));
pConnection->Open("DSN=SharePDM3;UID=;PWD=;", "", "", adModeUnknown);//ODBC数据源
pRecordset->Open(bstrSQL, pConnection.GetInterfacePtr(), 
adOpenStatic, adLockOptimistic, adCmdText); long lNumRecord = pRecordset->RecordCount;
if(lNumRecord != 1)
{
pRecordset->Close();
pConnection->Close();
return E_FAIL;
}
//下面是把数据库字段名和字段值封装到安全数组中
_variant_t varName[3], varValue[3];
varName[0] = L"roleName";
varName[1] = L"owner";
varName[2] = L"accessRight";
varValue[0] = bstrRoleName;
varValue[1] = bstrOwner;
varValue[2] = _variant_t(nRight);
const int nCrit = sizeof(varName) / sizeof(varName[0]);
// Create SafeArray Bounds and initialize the array
SAFEARRAYBOUND rgsaName[1], rgsaValue[1];
rgsaName[0].lLbound = 0;  
rgsaName[0].cElements = nCrit;
SAFEARRAY *psaName = SafeArrayCreate(VT_VARIANT, 1, rgsaName);
rgsaValue[0].lLbound = 0;
rgsaValue[0].cElements = nCrit;
SAFEARRAY *psaValue = SafeArrayCreate(VT_VARIANT, 1, rgsaValue);
// Set the values for each element of the array
HRESULT hr1 = S_OK, hr2 = S_OK;
for( long i = 0 ; i < nCrit && SUCCEEDED(hr1) && SUCCEEDED(hr2);i++)  
{     
hr1 = SafeArrayPutElement(psaName, &i, &varName[i]);
hr2 = SafeArrayPutElement(psaValue, &i, &varValue[i]);
}
  
// Initialize and fill the SafeArray
VARIANT vsaName, vsaValue;  
vsaName.vt = VT_VARIANT | VT_ARRAY;
vsaValue.vt = VT_VARIANT | VT_ARRAY;
V_ARRAY(&vsaName) = psaName;//&vsaName->parray=psaName;
//see definition in oleauto.h file.
V_ARRAY(&vsaValue) = psaValue;
   
hr1 = pRecordset->Update(vsaName, vsaValue);//更新数据
SafeArrayDestroy(psaName);
SafeArrayDestroy(psaValue);
if(FAILED(hr1))
{
pRecordset->Close();
pConnection->Close();
return E_FAIL;
} pRecordset->Close();
pConnection->Close();
return S_OK;
}
接下来我在MFC编写的客户端程序中调用了UpdateRole方法,代码如下
{
......
SAFEARRAY *pSaRole = SafeArrayCreateEx(...);
//安全数组的定义以及数据的封装
......
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
COSERVERINFO ServerInfo = {0,L"c01",NULL,0};
MULTI_QI MultiQi = {&IID_IUnknown,NULL,NOERROR}; HRESULT hr = CoCreateInstanceEx(CLSID_SysMgr, NULL, CLSCTX_REMOTE_SERVER,
&ServerInfo,1,&MultiQi);
if(FAILED(hr))
{
SafeArrayDestroy(pSaRole);
CoUninitialize();
return FALSE;
}

IUnknown* pUnknown;
pUnknown = (IUnknown*)MultiQi.pItf;
ISysMgr* pSysMgr;
hr = pUnknown->QueryInterface(IID_ISysMgr, (void**)&pSysMgr);
pUnknown->Release();
if(FAILED(hr))
{
SafeArrayDestroy(pSaRole);
CoUninitialize();
return FALSE;
}

hr = pSysMgr->UpdateRole(&pSaRole);//这里调用了COM组件方法,调试时进入(dllhost)组件函数内部单步执行
//可以看到执行了return S_OK语句,但是退出dllhost返回到客户端时,hr值为出错码0x8002000d,内存已锁定,这是什么原因?
pSysMgr->Release();
if(FAILED(hr))
{
SafeArrayDestroy(pSaRole);
CoUninitialize();
return FALSE;
}
......
}