Доброго времени суток.
После перехода на x64 возникла проблема с передачей параметров из COM в C#. На Win x86 все работало отлично, на Win x64 перестало. Тестили конкретно на Win 7 x64.
При получении данных из COM'a в C# приходит мусор.
Ниже небольшой тестовый пример.
// Описание функции в idl
[id(515), helpstring("method AnalyzeControllerApplicationFile")] HRESULT AnalyzeControllerApplicationFile([in, out] struct MFStruct* info);
//Описание структуры в которой хранятся передаваемые данные
[uuid(6D87AFA3-0255-47d6-A7FA-B4611D06C468)]
struct Attribute
{
BSTR key; // attribute's key (name)
BSTR value; // key data
};
//Структура с массивом структур
[uuid(6D87AFA3-0255-47e6-A7FA-B4611D06C257)]
struct MFStruct
{
SAFEARRAY(struct Attribute) attributes; // attributes array
};
// COM Функция генерящаяя данные для C#
STDMETHODIMP CChannel::AnalyzeControllerApplicationFile(MFStruct* info)
{
USES_CONVERSION;
HRESULT hr = S_OK;
//struct filling
MFStruct* fileInfo = info;
Attribute *pAttributesStruct = NULL;
//create SAFEARRAY
CComPtr<IRecordInfo> spRecAttr;
hr = GetRecordInfoFromGuids(LIBID_SPIIPLUSCOM521Lib, 1, 0, 0, __uuidof(Attribute), &spRecAttr);
fileInfo->attributes = SafeArrayCreateVectorEx(VT_RECORD, 0, 2, spRecAttr);
hr = SafeArrayAccessData(fileInfo->attributes, (void**)&pAttributesStruct);
//set elements values
for(UINT i = 0; i < 2; i++)
{
pAttributesStruct[i].key = CComBSTR("attrib k");
pAttributesStruct[i].value = CComBSTR("attrib v");
}
//free access to SAFEARRAY
hr = SafeArrayUnaccessData(fileInfo->attributes);
return S_OK;
}
//С# функция
void GetFunction()
{
MFStruct ff = new MFStruct();
Ch.AnalyzeControllerApplicationFile(ref ff); // После вызова функции, структура ff содержит мусор в масисе attributes
}
Здравствуйте, Klisang, Вы писали:
Внутри.
K>// COM Функция генерящаяя данные для C#
K>STDMETHODIMP CChannel::AnalyzeControllerApplicationFile(MFStruct* info)
K>{
K> USES_CONVERSION;
K> HRESULT hr = S_OK;
K> //struct filling
K> MFStruct* fileInfo = info;
K> Attribute *pAttributesStruct = NULL;
K> //create SAFEARRAY
K> CComPtr<IRecordInfo> spRecAttr;
K> hr = GetRecordInfoFromGuids(LIBID_SPIIPLUSCOM521Lib, 1, 0, 0, __uuidof(Attribute), &spRecAttr);
Vi2 - прежде чем писать в fileInfo, нужно сначала освободить предыдущее значение в этой структуре,
Vi2 - поскольку параметр является входным и может иметь реальные значение в полях структуры, отличные от тривиальных.
K> fileInfo->attributes = SafeArrayCreateVectorEx(VT_RECORD, 0, 2, spRecAttr);
K> hr = SafeArrayAccessData(fileInfo->attributes, (void**)&pAttributesStruct);
K> //set elements values
K> for(UINT i = 0; i < 2; i++)
K> {
// pAttributesStruct[i].key = CComBSTR("attrib k");
// pAttributesStruct[i].value = CComBSTR("attrib v");
Vi2 - поскольку CComBSTR разрушает свой адрес после деструктора, то нужно делать копию (.Copy()) или забирать собственность (.Detach()):
pAttributesStruct[i].key = CComBSTR("attrib k").Detach();
pAttributesStruct[i].value = CComBSTR("attrib v").Detach();
K> }
K> //free access to SAFEARRAY
K> hr = SafeArrayUnaccessData(fileInfo->attributes);
K> return S_OK;
K>}
Спасибо за детальный ответ, помогло

! Но возникла другая проблема.
Функция AnalyzeControllerApplicationFile вызывается из C# и падает с ошибкой "Попытка чтения или записи в защищенную память." Падает при обращении к интовым(вроде) полям массива структур.
Повторюсь в Win32 все работает, в Win64 — нет

. Возможно что-то не так с размерами типов или выравниванием структур? Подскажите кто знает.
Ниже пример.
[uuid(6D87AFA3-0255-47d6-A7FA-B4611D06C257)]
struct ApplicationFileInfo
{
BSTR filename; // file name
BSTR description; // file description
int isNewFile; // 1 - if writing new file, 0 - if adding
SAFEARRAY (struct SectionT) sectionsT; // sections array
__int64 reserved; //for pointer to C structure saving
};
[uuid(6D87AFA3-0255-47d6-A9FA-B4611D06C459)]
struct SectionT
{
BSTR filename; // section(controller file) name
BSTR description; // section description
unsigned int CRC; // data CRC
};
[uuid(6D87AFA3-0255-47d6-A7FA-B4611D06C958)]
enum FileType
{
ADJ, // Adjusting Data
SP, // Program and Data for DSP
ACSPL, // ACSPL+ programs
PAR, // Parameters
USER, // User data
PROT_STRING // protection string
};
STDMETHODIMP CChannel::AnalyzeControllerApplicationFile(ApplicationFileInfo* info, VARIANT* res)
{
USES_CONVERSION;
HRESULT hr = S_OK;
memset(info, 0, sizeof(ApplicationFileInfo));
ApplicationFileInfo* fileInfo = info;
//********************* Sections **********************************//
SectionT *pSectionStruct = NULL;
//create SAFEARRAY
CComPtr<IRecordInfo> spRecSect;
hr = GetRecordInfoFromGuids(LIBID_SPIIPLUSCOM521Lib, 1, 0, 0, __uuidof(SectionT), &spRecSect);
fileInfo->sectionsT = SafeArrayCreateVectorEx(VT_RECORD, 0, 3, spRecSect);
hr = SafeArrayAccessData(fileInfo->sectionsT , (void**)&pSectionStruct);
//set elements values
for(UINT i = 0; i < 3; i++)
{
pSectionStruct[i].description = CComBSTR("asdfasdf").Detach(); // Это проходит нормально
pSectionStruct[i].filename = CComBSTR("qwerty").Detach(); // Это тоже
pSectionStruct[i].CRC = 555; // А вот здесь уже падает, вылетает Access Violation("Попытка чтения или записи в защищенную память.")
pSectionStruct[i].offset = 0x223; // На этой и следующих двух строках так же валится
pSectionStruct[i].inuse = 1;
pSectionStruct[i].type = ADJ;
}
//free access to SAFEARRAY
hr = SafeArrayUnaccessData(fileInfo->sectionsT);
return S_OK;
}
Читать лень, но на мой взгляд, нужно переписать все с использованием CComSafeArray вместо SafeArrayCreateVectorEx,...
Код упрощает значительно. Тогда поймете в чем проблема сами.
>Здравствуйте, Klisang, Вы писали:
K>Спасибо за детальный ответ, помогло
! Но возникла другая проблема.
K>Функция AnalyzeControllerApplicationFile вызывается из C# и падает с ошибкой "Попытка чтения или записи в защищенную память." Падает при обращении к интовым(вроде) полям массива структур.
K>Повторюсь в Win32 все работает, в Win64 — нет
. Возможно что-то не так с размерами типов или выравниванием структур? Подскажите кто знает.
K>Ниже пример.
K>K>[uuid(6D87AFA3-0255-47d6-A7FA-B4611D06C257)]
K>struct ApplicationFileInfo
K>{
K> BSTR filename; // file name
K> BSTR description; // file description
K> int isNewFile; // 1 - if writing new file, 0 - if adding
K> SAFEARRAY (struct SectionT) sectionsT; // sections array
K> __int64 reserved; //for pointer to C structure saving
K>};
K>[uuid(6D87AFA3-0255-47d6-A9FA-B4611D06C459)]
K>struct SectionT
K>{
K> BSTR filename; // section(controller file) name
K> BSTR description; // section description
K> unsigned int CRC; // data CRC
K>};
K>[uuid(6D87AFA3-0255-47d6-A7FA-B4611D06C958)]
K>enum FileType
K>{
K> ADJ, // Adjusting Data
K> SP, // Program and Data for DSP
K> ACSPL, // ACSPL+ programs
K> PAR, // Parameters
K> USER, // User data
K> PROT_STRING // protection string
K>};
K>STDMETHODIMP CChannel::AnalyzeControllerApplicationFile(ApplicationFileInfo* info, VARIANT* res)
K>{
K> USES_CONVERSION;
K> HRESULT hr = S_OK;
K> memset(info, 0, sizeof(ApplicationFileInfo));
K> ApplicationFileInfo* fileInfo = info;
K> //********************* Sections **********************************//
K> SectionT *pSectionStruct = NULL;
K> //create SAFEARRAY
K> CComPtr<IRecordInfo> spRecSect;
K> hr = GetRecordInfoFromGuids(LIBID_SPIIPLUSCOM521Lib, 1, 0, 0, __uuidof(SectionT), &spRecSect);
K> fileInfo->sectionsT = SafeArrayCreateVectorEx(VT_RECORD, 0, 3, spRecSect);
K> hr = SafeArrayAccessData(fileInfo->sectionsT , (void**)&pSectionStruct);
K> //set elements values
K> for(UINT i = 0; i < 3; i++)
K> {
K> pSectionStruct[i].description = CComBSTR("asdfasdf").Detach(); // Это проходит нормально
K> pSectionStruct[i].filename = CComBSTR("qwerty").Detach(); // Это тоже
K> pSectionStruct[i].CRC = 555; // А вот здесь уже падает, вылетает Access Violation("Попытка чтения или записи в защищенную память.")
K> pSectionStruct[i].offset = 0x223; // На этой и следующих двух строках так же валится
K> pSectionStruct[i].inuse = 1;
K> pSectionStruct[i].type = ADJ;
K> }
K> //free access to SAFEARRAY
K> hr = SafeArrayUnaccessData(fileInfo->sectionsT);
K> return S_OK;
K>}
K>