Проблема с передачей массива структур из COM в C#.
От: Klisang  
Дата: 29.06.10 11:04
Оценка:
Доброго времени суток.
После перехода на 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

}
Re: Проблема с передачей массива структур из COM в C#.
От: Vi2 Удмуртия http://www.adem.ru
Дата: 29.06.10 13:31
Оценка: 3 (1)
Здравствуйте, 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>}
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: Проблема с передачей массива структур из COM в C#.
От: Klisang  
Дата: 30.06.10 10:44
Оценка:
Спасибо за детальный ответ, помогло ! Но возникла другая проблема.

Функция 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;
}
Re[3]: Проблема с передачей массива структур из COM в C#.
От: Аноним  
Дата: 10.07.10 12:26
Оценка:
Читать лень, но на мой взгляд, нужно переписать все с использованием 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>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.