Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как вернуть через API массив структур? API эту сам пишу. / 25 сообщений из 43, страница 1 из 2
08.01.2016, 06:49
    #39143224
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Исходный код (мой) из которого пытаюсь родить нужную мне dll в соседнем топике:
Получение нестандартных полей (телефон,факс) из Windows Contacts -диалог Select Recipients
Ну или под спойлером (Юникод вариант я таки осилил):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
#include <windows.h>
#include <Shlobj.h>
#include <wab.h>

typedef HRESULT (WINAPI *fWABOpen)(LPADRBOOK*,LPWABOBJECT*,LPWAB_PARAM,DWORD);


int main()
{
  HRESULT hRes;
  LPADRBOOK lpAdrBook;
  LPWABOBJECT lpWABObject;
  LPWAB_PARAM lpWABParam = NULL;
  DWORD Reserved2 = 0;

  HINSTANCE hinstLib;

  TCHAR szPath[MAX_PATH];
  TCHAR buf[1024];
  //CSIDL_PROGRAM_FILES_COMMON -для 32-битного кода все равно укажет на Program Files (x86)
  SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_DEFAULT, szPath);
  wsprintf(buf, L"%s\\System\\wab32", szPath);
  hinstLib = LoadLibrary(buf); //"C:\\Program Files (x86)\\Common Files\\System\\wab32"
  fWABOpen procWABOpen;

  if (hinstLib != NULL)
  {
    procWABOpen = (fWABOpen)GetProcAddress(hinstLib, "WABOpen");
    if (procWABOpen != NULL)
    {
      hRes = (procWABOpen)(&lpAdrBook, &lpWABObject, NULL, Reserved2);
      if (hRes != S_OK) exit(1);

      ULONG lpulUIParam = 0;// (ULONG_PTR *)hWnd;
      ADRPARM lpAdrParms;
      lpAdrParms.cbABContEntryID = 0;
      lpAdrParms.lpABContEntryID = NULL;
      lpAdrParms.ulFlags = DIALOG_MODAL+MAPI_UNICODE;
      lpAdrParms.lpReserved = NULL;
      lpAdrParms.ulHelpContext = 0;
      lpAdrParms.lpszHelpFileName = NULL;
      lpAdrParms.lpfnABSDI = NULL;
      lpAdrParms.lpfnDismiss = NULL;
      lpAdrParms.lpvDismissContext = NULL;
      lpAdrParms.lpszCaption = L"Выбрать получателей";
      lpAdrParms.lpszNewEntryTitle = NULL;
      lpAdrParms.lpszDestWellsTitle = NULL;
      lpAdrParms.cDestFields = 3;
      lpAdrParms.nDestFieldFocus = 0;
      //lpAdrParms.lppszDestTitles = NULL;
			LPTSTR rglpszDestTitles[] = { L"Кому:", L"Копия:", L"Скрытая копия" };
      lpAdrParms.lppszDestTitles = rglpszDestTitles;
      lpAdrParms.lpulDestComps = NULL;
      lpAdrParms.lpContRestriction = NULL;
      lpAdrParms.lpHierRestriction = NULL;
      LPADRLIST lppAdrList = NULL;
      hRes = lpAdrBook->Address(&lpulUIParam, &lpAdrParms, &lppAdrList);
      if (hRes != S_OK) return 0;
      if (lppAdrList==NULL)return 0;
      for(ULONG i=0;i<lppAdrList->cEntries;i++)
      {
        LPWSTR m_DisplayName = L"";
        LPWSTR m_EmailAddress = L"";
        ULONG m_ReceipType=0; //1-To,2-CC,3-BCC
        LPWSTR m_HomeTelephoneNumber = L"";
        LPWSTR m_HomeFaxNumber = L"";
        LPWSTR m_BusinessTelephoneNumber = L"";
        LPWSTR m_BusinessFaxNumber = L"";
        ULONG cProps = 0;
        LPSPropValue lpProps = NULL;
        for(ULONG j=0;j<lppAdrList->aEntries[i].cValues;j++)//
        {
          SPropValue *lpProp = &lppAdrList->aEntries[i].rgPropVals[j];

          if (lpProp->ulPropTag == PR_DISPLAY_NAME_W)
            m_DisplayName=lpProp->Value.lpszW;
          if (lpProp->ulPropTag == PR_EMAIL_ADDRESS_W)
            m_EmailAddress=lpProp->Value.lpszW;
          if (lpProp->ulPropTag == PR_RECIPIENT_TYPE) //1-To,2-CC,3-BCC
            m_ReceipType=lpProp->Value.ul;
          if (lpProp->ulPropTag == PR_ENTRYID){
            ULONG ulFlags = 0 ;//MAPI_BEST_ACCESS;
            ULONG ulObjType = NULL;
            LPUNKNOWN lpUnk = NULL;
            hRes = lpAdrBook->OpenEntry(lpProp->Value.bin.cb,(LPENTRYID)(lpProp->Value.bin.lpb),NULL,ulFlags,&ulObjType,&lpUnk);
            if (hRes == S_OK){
              ulFlags = NULL;
              if (ulObjType == MAPI_MAILUSER){
                IMailUser *lpMailUser = static_cast <IMailUser *>(lpUnk);
                ulFlags=MAPI_UNICODE;
                hRes = lpMailUser->GetProps(NULL,ulFlags,&cProps,&lpProps);
                if (hRes == S_OK){
                  for(ULONG k=0;k<cProps;k++)//
                  {
                    if (lpProps[k].ulPropTag == PR_HOME_TELEPHONE_NUMBER_W)
                     m_HomeTelephoneNumber=lpProps[k].Value.lpszW;
                    if (lpProps[k].ulPropTag == PR_HOME_FAX_NUMBER_W)
                      m_HomeFaxNumber=lpProps[k].Value.lpszW;
                    if (lpProps[k].ulPropTag == PR_BUSINESS_TELEPHONE_NUMBER_W)
                      m_BusinessTelephoneNumber=lpProps[k].Value.lpszW;
                    if (lpProps[k].ulPropTag == PR_BUSINESS_FAX_NUMBER_W)
                      m_BusinessFaxNumber=lpProps[k].Value.lpszW;
                  }
                }
              }
            }
          }
        }
        wsprintf(buf, L"Display Name: %s\nEmail Address: %s\nReceiptype: %d\nHome Phone: %s\nHome Fax: %s\n\
Office Phone: %s\nOffice Fax: %s",
          m_DisplayName,m_EmailAddress,m_ReceipType,m_HomeTelephoneNumber,m_HomeFaxNumber,
          m_BusinessTelephoneNumber,m_BusinessFaxNumber);
        MessageBox(NULL, buf, L"Recipient info", MB_OK);
        lpWABObject->FreeBuffer(lpProps);
      }
    }
  }
  FreeLibrary(hinstLib);
  return 0;
}



В общем как-то так пока:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
typedef struct _RECIPLIST
{
    LPWSTR          lpszDisplayName;
    LPWSTR          lpszEmailAddress;
    ULONG           ulReceipType;
} RECIPLIST, FAR * LPRECIPLIST;

extern "C" {
ULONG __stdcall CPP_AddressBook(ULONG hWnd, 
                                ULONG cDestFields, 
                                LPTSTR lpszCaption, 
                                LPTSTR FAR * lppszDestTitles,
                                BOOL bAddressOne,
                                LPRECIPLIST FAR *	lppRecipList)
{ 
  ULONG cEntries = 0;
...
      hRes = lpAdrBook->Address(&lpulUIParam, &lpAdrParms, &lppAdrList);
      if (hRes != S_OK) return 0;
      if (lppAdrList==NULL)return 0;
      cEntries = lppAdrList->cEntries;
      for(ULONG i=0;i<lppAdrList->cEntries;i++)
      {
        for(ULONG j=0;j<lppAdrList->aEntries[i].cValues;j++)//
        {
          SPropValue *lpProp = &lppAdrList->aEntries[i].rgPropVals[j];

          if (lpProp->ulPropTag == PR_DISPLAY_NAME_W)
            lppRecipList[i]->lpszDisplayName = lpProp->Value.lpszW;
          if (lpProp->ulPropTag == PR_EMAIL_ADDRESS_W)
            lppRecipList[i]->lpszEmailAddress = lpProp->Value.lpszW;
          if (lpProp->ulPropTag == PR_RECIPIENT_TYPE) //1-To,2-CC,3-BCC
            lppRecipList[i]->ulReceipType = lpProp->Value.ul;
        }
      }
    }
  }
  return cEntries; 
}
}; // extern "C"



Полный пока код функции под спойлером, но суть я в общем выделил выше:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
...
#include <Shlobj.h>
#include <wab.h>

typedef HRESULT (WINAPI *fWABOpen)(LPADRBOOK*,LPWABOBJECT*,LPWAB_PARAM,DWORD);

typedef struct _RECIPLIST
{
    LPWSTR          lpszDisplayName;
    LPWSTR          lpszEmailAddress;
    ULONG           ulReceipType;
} RECIPLIST, FAR * LPRECIPLIST;
...
extern "C" {
ULONG __stdcall CPP_AddressBook(ULONG hWnd, 
                                ULONG cDestFields, 
                                LPTSTR lpszCaption, 
                                LPTSTR FAR * lppszDestTitles,
                                BOOL bAddressOne,
                                LPRECIPLIST FAR *	lppRecipList)
{ 
  ULONG cEntries = 0;
  HRESULT hRes;
  LPADRBOOK lpAdrBook;
  LPWABOBJECT lpWABObject;
  LPWAB_PARAM lpWABParam = NULL;
  DWORD Reserved2 = 0;

  HINSTANCE hinstLib;

  TCHAR szPath[MAX_PATH];
  TCHAR buf[1024];
  //CSIDL_PROGRAM_FILES_COMMON -для 32-битного кода все равно укажет на Program Files (x86)
  SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_DEFAULT, szPath);
  wsprintf(buf, L"%s\\System\\wab32", szPath);
  hinstLib = LoadLibrary(buf); //"C:\\Program Files (x86)\\Common Files\\System\\wab32"
  fWABOpen procWABOpen;

  if (hinstLib != NULL)
  {
    procWABOpen = (fWABOpen)GetProcAddress(hinstLib, "WABOpen");
    if (procWABOpen != NULL)
    {
      hRes = (procWABOpen)(&lpAdrBook, &lpWABObject, NULL, Reserved2);
      if (hRes != S_OK) return 0;

      ULONG lpulUIParam = hWnd;
      ADRPARM lpAdrParms;
      lpAdrParms.cbABContEntryID = 0;
      lpAdrParms.lpABContEntryID = NULL;
      lpAdrParms.ulFlags = DIALOG_MODAL + MAPI_UNICODE;
      if (bAddressOne && (cDestFields == 0))
        lpAdrParms.ulFlags = lpAdrParms.ulFlags + ADDRESS_ONE;
      lpAdrParms.lpReserved = NULL;
      lpAdrParms.ulHelpContext = 0;
      lpAdrParms.lpszHelpFileName = NULL;
      lpAdrParms.lpfnABSDI = NULL;
      lpAdrParms.lpfnDismiss = NULL;
      lpAdrParms.lpvDismissContext = NULL;
      lpAdrParms.lpszCaption = lpszCaption;
      lpAdrParms.lpszNewEntryTitle = NULL;
      lpAdrParms.lpszDestWellsTitle = NULL;
      lpAdrParms.cDestFields = cDestFields;
      lpAdrParms.nDestFieldFocus = 0;
      lpAdrParms.lppszDestTitles = lppszDestTitles; // To,CC,BCC
      lpAdrParms.lpulDestComps = NULL;
      lpAdrParms.lpContRestriction = NULL;
      lpAdrParms.lpHierRestriction = NULL;
      LPADRLIST lppAdrList = NULL;
      hRes = lpAdrBook->Address(&lpulUIParam, &lpAdrParms, &lppAdrList);
      if (hRes != S_OK) return 0;
      if (lppAdrList==NULL)return 0;
      cEntries = lppAdrList->cEntries;
      for(ULONG i=0;i<lppAdrList->cEntries;i++)
      {
        for(ULONG j=0;j<lppAdrList->aEntries[i].cValues;j++)//
        {
          SPropValue *lpProp = &lppAdrList->aEntries[i].rgPropVals[j];

          if (lpProp->ulPropTag == PR_DISPLAY_NAME_W)
            lppRecipList[i]->lpszDisplayName = lpProp->Value.lpszW;
          if (lpProp->ulPropTag == PR_EMAIL_ADDRESS_W)
            lppRecipList[i]->lpszEmailAddress = lpProp->Value.lpszW;
          if (lpProp->ulPropTag == PR_RECIPIENT_TYPE) //1-To,2-CC,3-BCC
            lppRecipList[i]->ulReceipType = lpProp->Value.ul;
        }
      }
    }
  }
  return cEntries; 
}
}; // extern "C"



Проблема в чем.
Последний аргумент функции LPRECIPLIST FAR * lppRecipList
это типа указатель на массив структур RECIPLIST.
Размерность массива соответствует числу выбранных в диалоге адресной книги получателей, посему заранее (на вызывающей стороне) не известна.
Функция также возвращает число этих самых элементов массива в return cEntries

Пока с lppRecipList не стал играться все работало.

Тест-Код на стороне VB.Net клиента такой:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
  Public Declare Unicode Function CPP_AddressBook Lib "testwab32.dll" ( _
   ByVal hWnd As IntPtr, _
   ByVal cDestFields As UInteger, _
   ByVal lpszCaption As String, _
   ByVal lppszDestTitles() As String, _
   ByVal bAddressOne As Boolean, _
   ByRef lppRecipList As IntPtr) As UInteger

 Private Sub ButtonTestWab_Click(sender As Object, e As EventArgs) Handles ButtonTestWab.Click
    Dim PtrRecipList As IntPtr
    MsgBox(CPP_AddressBook( _
     Me.Handle, _
     3, _
     "Выбрать получателей", _
     {"Кому:", "Копия:", "Скрытая копия:"}, _
     False, _
     PtrRecipList))
    MsgBox(PtrRecipList)
  End Sub



Для начала хочу получить указатель на массив, т.е. PtrRecipList.
Ошибка вылазит:
.NetНеобработанное исключение типа "System.AccessViolationException" в WabTestNet.exe
Дополнительные сведения: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.

Что я напортачил в C++? Предполагаю, что не выделил память под элементы массива.
Внутри C кода мне известна размерность lppAdrList->cEntries
И я потом начинаю заполнять элементы
lppRecipList[i]->lpszDisplayName = lpProp->Value.lpszW;
lppRecipList[i]->lpszEmailAddress = lpProp->Value.lpszW;

Или где-то тупо ошибся в "грамматике", делал как бы по образу-подобию чего под руку подвернулось.
В .Net предполагаю сначала получить указатель IntPtr на массив структур,
потом воспользоваться Marshal.PtrToStructure (Ptr)
сдвигая Ptr на размер структуры для получения след. элемента (количество функция возвратит)
...
Рейтинг: 0 / 0
08.01.2016, 10:42
    #39143264
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77,
размер нужно тоже возвращать. например, сделать еще один выходной параметр. (в функцию передать указатель на size_t, в функции под этому адресу записать значение)
...
Рейтинг: 0 / 0
08.01.2016, 10:44
    #39143267
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
MasterZiv,
детальнее в эту хрень не волновался, извини...
...
Рейтинг: 0 / 0
08.01.2016, 14:52
    #39143362
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
MasterZivразмер нужно тоже возвращать.)
Так именно его я возвращаю. 0- если элементов нет или к-во элементов если они есть.
Но к-во элементов в массиве становится известно только внутри самой ф-ции.

MasterZiv (в функцию передать указатель на size_t, в функции под этому адресу записать значение)
Ну так я и передаю указатель ByRef LPRECIPLIST FAR * lppRecipList.

По идее ф-ция должна в этом параметре вернуть указатель,
и по этому указателю записать массив.
При этом наверно выделить нужную память перед тем как писать.
И вот как это сделать?
А освобождать эту память видимо надо уже в вызывающем приложении после прочтения массива.

Зарезервировать память по указателю в вызывающем приложении и кинуть в ф-цию конкретный указатель я не могу, т.к. заранее не знаю сколько нужно памяти (к-во элементов в массиве становится известно только внутри самой ф-ции).
...
Рейтинг: 0 / 0
08.01.2016, 16:11
    #39143394
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Хорошо, давайте по простому, а то слишком много кода привел:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
typedef struct _RECIPLIST
{
    LPWSTR          lpszDisplayName;
    LPWSTR          lpszEmailAddress;
    ULONG           ulReceipType;
} RECIPLIST, FAR * LPRECIPLIST;

extern "C" {
ULONG __stdcall CPP_Test(LPRECIPLIST FAR * lppRecipList)
{
	lppRecipList[0]->lpszDisplayName=L"Name";
	lppRecipList[0]->lpszEmailAddress=L"example@server.com";
	lppRecipList[0]->ulReceipType=1;
	return 1;
}



Вызов из клиента

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
  Public Declare Unicode Function CPP_Test Lib "mydll.dll" ( _
   ByRef lppRecipList As IntPtr) As UInteger

  Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim PtrRecipList As IntPtr
    MsgBox(CPP_Test(PtrRecipList))
    MsgBox(PtrRecipList)
  End Sub



ошибка на клиенте при вызове CPP_TestНеобработанное исключение типа "System.AccessViolationException" в WabTestNet.exe
Дополнительные сведения: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.

Не, ну то что я делаю что-то сильно не так, это я понимаю.
А как сделать так?


Я хочу сделать по аналогии с MAPIAddress function
Последний параметр _Out_ lpMapiRecipDesc *lppNewRecips
lppNewRecips outPointer to an array of MapiRecipDesc structures containing the final list of recipients. This array is allocated by MAPIAddress, cannot be NULL, and must be freed using MAPIFreeBuffer, even if there are no new recipients.
Чтобы можно было из клиента использовать код типа как здесь сделал:
18646419
(к сожалению у меня нет исходников ф-ции MAPIAddress чтобы посмотреть C-начинку как они этот чертов массив внутри API формируют).
...
Рейтинг: 0 / 0
08.01.2016, 16:59
    #39143423
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Ну вот так вроде выводит:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
typedef struct _RECIPLIST
{
    LPTSTR          lpszDisplayName;
    LPTSTR          lpszEmailAddress;
    ULONG           ulReceipType;
} RECIPLIST, FAR * LPRECIPLIST;

extern "C" {
ULONG __stdcall CPP_Test(LPRECIPLIST FAR * lppRecipList)
{
  * lppRecipList=(LPRECIPLIST ) malloc(sizeof(RECIPLIST));
	lppRecipList[0]->lpszDisplayName=L"Name";
	lppRecipList[0]->lpszEmailAddress=L"example@server.com";
	lppRecipList[0]->ulReceipType=1;
	return 1;
}


Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
  Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim PtrRecipList As IntPtr
    Dim num As UInteger
    num = CPP_Test(PtrRecipList)
    MsgBox(num)
    If num > 0 Then
      Dim NewReceipts() As RECIPLIST = Nothing
      If num > 0 Then
        ReDim NewReceipts(0 To num - 1)
        For i As Integer = 0 To num - 1
          NewReceipts(i) = CType(Marshal.PtrToStructure(PtrRecipList + i * Marshal.SizeOf(NewReceipts(0)), GetType(RECIPLIST)), RECIPLIST)
          MsgBox(NewReceipts(i).ulReceipType.ToString & " : " & NewReceipts(i).lpszDisplayName.ToString & "<" & NewReceipts(i).lpszEmailAddress.ToString & ">")
        Next
        Marshal.FreeCoTaskMem(PtrRecipList)
      End If
    End If
  End Sub


Но у меня .Net прога почему-то виснет.
Выводит
MsgBox(NewReceipts( 0 ).ulReceipType.ToString & " : " & NewReceipts( 0 ).lpszDisplayName.ToString & "<" & NewReceipts( 0 ).lpszEmailAddress.ToString & ">")
и виснет.
...
Рейтинг: 0 / 0
08.01.2016, 17:26
    #39143448
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77Но у меня .Net прога почему-то виснет.
Виснет из за Marshal.FreeCoTaskMem(PtrRecipList)
Если убрать, то не виснет.
Но тогда вопрос как освободить память захапанную на стороне C через malloc.

И дальше, пытаюсь напр. выводить массив из 2-х элементов:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
ULONG __stdcall CPP_Test(LPRECIPLIST FAR * lppRecipList)
{
  * lppRecipList=(LPRECIPLIST ) malloc(2*sizeof(RECIPLIST));
	lppRecipList[0]->lpszDisplayName=L"Name";
	lppRecipList[0]->lpszEmailAddress=L"example@server.com";
	lppRecipList[0]->ulReceipType=1;
	lppRecipList[1]->lpszDisplayName=L"Name1";
	lppRecipList[1]->lpszEmailAddress=L"example1@server.com";
	lppRecipList[1]->ulReceipType=2;
	return 2;
}


Гадина рушится очевидно при попыке заполнения lppRecipList[1] (выделенные строчки)
Как правильно память выделить под массив из 2-х или n элементов? (внутри c я размер знаю)
Или надо как-то объяснить в коде что это именно массив и что там n элементов.
...
Рейтинг: 0 / 0
08.01.2016, 18:07
    #39143478
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77на стороне C через malloc.
ответ в вопросе - выделяй через CoTaskMemAlloc
...
Рейтинг: 0 / 0
08.01.2016, 18:37
    #39143503
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
ИзопропилДмитрий77на стороне C через malloc.
ответ в вопросе - выделяй через CoTaskMemAlloc
За это спасибо.

Если убрать malloc и сделать в C
Код: plaintext
1.
  * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(sizeof(RECIPLIST));


то на стороне .Net
Код: vbnet
1.
       Marshal.FreeCoTaskMem(PtrRecipList)


не приводит к висяку и надо думать вопрос высвобождения памяти таким образом решается

Но что делать если элементов больше одного
Вот этот код
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
ULONG __stdcall CPP_Test(LPRECIPLIST FAR * lppRecipList)
{
  * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(2* sizeof(RECIPLIST));
  lppRecipList[0]->lpszDisplayName=L"Name";
  lppRecipList[0]->lpszEmailAddress=L"example@server.com";
  lppRecipList[0]->ulReceipType=1;
  lppRecipList[1]->lpszDisplayName=L"Name1";
  lppRecipList[1]->lpszEmailAddress=L"example1@server.com";
  lppRecipList[1]->ulReceipType=1;
  return 2;
}


безжалостно глючит

Не хочет понимать что lppRecipList это массив из двух элементов и под него выделена память под два элемента.
Если убрать заполнение lppRecipList[1] то не глючит.
Но я то массив хочу вернуть, а размер задать внутри ф-ции.
...
Рейтинг: 0 / 0
08.01.2016, 19:01
    #39143525
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77безжалостно глючит
содержательная диагностика
...
Рейтинг: 0 / 0
08.01.2016, 19:08
    #39143530
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77,

размеры структур сравни в с++ и бейсик коде. выравнивание может быть разным
...
Рейтинг: 0 / 0
08.01.2016, 20:52
    #39143620
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
ИзопропилДмитрий77безжалостно глючит
содержательная диагностика
Я писал выше ошибку в .Net.
авторНеобработанное исключение типа "System.AccessViolationException" в WabTestNet.exe
Дополнительные сведения: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
И происходит она до того как ф-ция чего-то возвращает.
Ошибка очевидно в C-коде при заполнении элемента массива отличного от первого, я выделил строчки в коде.
Сказать какая с т. зр. C не могу, это dll, компилируется нормально.
Я думаю человек пишущий на C сразу поймет, но я то оч. редко к C обращаюсь.
Изопропилразмеры структур сравни в с++ и бейсик коде. выравнивание может быть разным
12 и там и там. Две строки и число по 4 байта на элемент структуры.
...
Рейтинг: 0 / 0
09.01.2016, 00:19
    #39143685
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Не получается у меня больше одного элемента вернуть.
Неужели такая сложная задача
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
typedef struct _RECIPLIST
{
    LPWSTR          lpszDisplayName;
    LPWSTR          lpszEmailAddress;
    ULONG           ulReceipType;
} RECIPLIST, FAR * LPRECIPLIST;

ULONG __stdcall CPP_Test(LPRECIPLIST FAR * lppRecipList)
{
  * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(2* sizeof(RECIPLIST));
  lppRecipList[0]->lpszDisplayName=L"Name";
  lppRecipList[0]->lpszEmailAddress=L"example@server.com";
  lppRecipList[0]->ulReceipType=1;
  lppRecipList[1]->lpszDisplayName=L"Name1";
  lppRecipList[1]->lpszEmailAddress=L"example1@server.com";
  lppRecipList[1]->ulReceipType=1;
  return 2;
}


Ну что тут может быть не так? Все уже перепробовал, как гуглить эти вещи не знаю.
Почему не пишет второй элемент lppRecipList[1]?

Не, могу наверно все данные в одну строку "распечатать" и вернуть,
а потом сидеть как дебил в бейсике парсить километровую строку (результат можно достичь и гавнокодом), но хотелось бы по нормальному.
...
Рейтинг: 0 / 0
09.01.2016, 00:49
    #39143695
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77,

попробуй памяти выделить с запасом,
в отладчике посмотри что происходит
...
Рейтинг: 0 / 0
09.01.2016, 01:20
    #39143703
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Изопропилпопробуй памяти выделить с запасом,
Это не помогает.
Так написал:
Код: plaintext
1.
  * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(200000*sizeof(RECIPLIST));


Куда больше?
А вылетает точно также на заполнении второго элемента.
Там что-то другое. Просто C ни хрена не знаю, навыка нет, но иногда надо, вот и мучаюсь.

Я вот думаю, у меня в структуре строки.
Размер 12 байтов, 4 байта на строку.
Но 4 байта это указатель на массив байтов, где эта строка сидит.
Когда я память выделяю, я ее выделяю под указатель на массив байтов а не под сам этот массив.
Где гарантия что там все корректно будет?

Не не то, с одним элементом же корректно работает.
...
Рейтинг: 0 / 0
09.01.2016, 08:26
    #39143722
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Как мне хотя б массив строк вывести?

Пытаюсь так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
ULONG __stdcall CPP_Test2(LPTSTR * lppDisplayName)
{
  //* lppDisplayName=(LPTSTR)CoTaskMemAlloc(6*sizeof(LPTSTR));
  //* lppDisplayName=(LPTSTR)CoTaskMemAlloc(6*sizeof(LPTSTR));
	lppDisplayName[0]=L"Очень длинная строка";
	lppDisplayName[1]=L"Name";
	lppDisplayName[2]=L"Hello";
	lppDisplayName[3]=L"Еще текст";
	lppDisplayName[4]=L"Еще чего нибудь";
	lppDisplayName[5]=L"In English";
	return 6;
}



Достаю так (ну хоть как то):
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
  Public Declare Unicode Function CPP_Test2 Lib "mydll.dll" ( _
   ByRef ptrDisplayName As IntPtr) As UInteger

  Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    Dim ptrDisplayName As New IntPtr 
    Dim num As UInteger
    num = CPP_Test2(ptrDisplayName)
    MsgBox(num)
     If num > 0 Then
      Dim DisplayName(num - 1) As String
      For i As Integer = 0 To num - 1
        If i > 0 Then
          ptrDisplayName = New IntPtr(ptrDisplayName.ToInt32 + Strings.Len(DisplayName(i - 1)) * Marshal.SystemDefaultCharSize + 4)
        End If
        DisplayName(i) = Marshal.PtrToStringUni(ptrDisplayName)
        MsgBox(DisplayName(i))
      Next
    End If
  End Sub


В последних трех словах из примера первая буква теряется.
Это дурдом какой-то.

Как мне через API вывести набор?

Имя
e-mail
тип адресата
телефон
факс

количество этих выборок и все данные мне внутри C-кода доступны.

Данные я получил.
Вывести не могу.

Длинные строки (5 строк с разделителями а потом парсить) я вернуть могу конечно,
но в си объединение строк через всякие wsprintf это тоже задница
буфер придется делать немеренный (а вдруг выборка на 20000 адресатов?)
плохой вариант.

Мне надо хотяб пять массивов строк, если не один массив структур.
...
Рейтинг: 0 / 0
09.01.2016, 08:50
    #39143723
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Мне реальным только вариант в таком духе видится:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
ULONG __stdcall CPP_Test(LPRECIPLIST FAR * lppRecipList)
{
  TCHAR DisplayNames[100000]=L"";
	wsprintf(DisplayNames,L"%s%s",DisplayNames,L"Name\r\n");
	wsprintf(DisplayNames,L"%s%s",DisplayNames,L"Name1\r\n");
	wsprintf(DisplayNames,L"%s%s",DisplayNames,L"Name2\r\n");
  TCHAR EmailAddresses[100000]=L"";
	wsprintf(EmailAddresses,L"%s%s",EmailAddresses,L"example@server.com\r\n");
	wsprintf(EmailAddresses,L"%s%s",EmailAddresses,L"example1@server.com\r\n");
	wsprintf(EmailAddresses,L"%s%s",EmailAddresses,L"example2@server.com\r\n");
  TCHAR ReceipType[100000]=L"";
	wsprintf(ReceipType,L"%s%s",ReceipType,L"1\r\n");
	wsprintf(ReceipType,L"%s%s",ReceipType,L"2\r\n");
	wsprintf(ReceipType,L"%s%s",ReceipType,L"3\r\n");

  * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(sizeof(RECIPLIST));
	lppRecipList[0]->lpszDisplayName=DisplayNames;
	lppRecipList[0]->lpszEmailAddress=EmailAddresses;
	lppRecipList[0]->ulReceipType=ReceipType;
	return 3;
}



Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim PtrRecipList As New IntPtr
    Dim num As UInteger
    num = CPP_Test(PtrRecipList)
    MsgBox(num)
    If num > 0 Then
      Dim NewReceipts As RECIPLIST
      NewReceipts = CType(Marshal.PtrToStructure(PtrRecipList, GetType(RECIPLIST)), RECIPLIST)
      Marshal.FreeCoTaskMem(PtrRecipList)
      For i As Integer = 0 To num - 1
        Dim str_DisplayName As String = Split(NewReceipts.lpszDisplayName, vbCrLf)(i)
        Dim str_EmailAddress As String = Split(NewReceipts.lpszEmailAddress, vbCrLf)(i)
        Dim str_ReceipType As String = Split(NewReceipts.ulReceipType, vbCrLf)(i)
        MsgBox(str_ReceipType & ": " & str_DisplayName & "<" & str_EmailAddress & ">")
      Next
    End If
  End Sub



Он работает, но это через одно место.
Причем теоретически буфера в 100000 для строки тоже могут переполниться.
Если считать что поле 20 символов,
то 100000/20=5000 записей.
Смотря какие цели. Если добавить 2 e-mail то это излишки,
а если выборка из номеров телефонов, то может и не хватить.
И думаю транжирство памяти, хорошо если не утекает.
...
Рейтинг: 0 / 0
09.01.2016, 12:00
    #39143744
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77,

воспроизвести ошибку никак не удалось, всё возвращается как положено

какой фрагмент приведённого кода действующий, а какой мысли вслух - понять не могу
лучше всего - приложи целиком проект с++
...
Рейтинг: 0 / 0
09.01.2016, 12:24
    #39143752
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77,

внимательно прочитал твои портянки, ошибочка простая. Причина - говнокод в качестве заготовкм
в твоём коде - lppRecipList - трактуется не как указатель на массив структур, а массив указателей на структуры
...
Рейтинг: 0 / 0
09.01.2016, 13:16
    #39143767
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Изопропиллучше всего - приложи целиком проект с++
Лови.
CPP_AddressBook -собственно ради чего все делается (вылетает при выборе 2-х и более адресатов)
CPP_Test - попытка вернуть 2 элемента структуры (соответственно также вылетает)
CPP_Test2- попытка вернуть массив просто строк (не вылетает и даже выводит, но не совсем правильно)

Проект VC++2005EE, но конвертация в 2010 не спасает.
...
Рейтинг: 0 / 0
09.01.2016, 13:18
    #39143768
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
На всякий случай сопряженный VB.NET (2013)
Пути в декларациях указаны абсолютные, надо менять на свои.
...
Рейтинг: 0 / 0
09.01.2016, 13:27
    #39143770
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
ИзопропилДмитрий77,

внимательно прочитал твои портянки, ошибочка простая. Причина - ...
в твоём коде - lppRecipList - трактуется не как указатель на массив структур, а массив указателей на структуры
Ты лучше скажи как записать чтоб было правильно. Я на C вообще пишу очень редко и от этих звездочек справа слева честно крыша сразу съезжает.
И очень хочется чтоб ты был прав, потому как измотался уж.

Со строками, которые соединять а потом парсить - не вариант. Макс. буфера и длины строки хватает на 30 где-то контактов, потом Stack Overflow.
Уже думал в файл результат написать, а потом из VB его прочесть. Но это уже ни в какие ворота (в рамках вызова одной ф-ции).
...
Рейтинг: 0 / 0
09.01.2016, 13:48
    #39143774
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77,

Код: plaintext
1.
2.
(*lppRecipList)[0].lpszDisplayName = L"aaa";
(*lppRecipList)[1].lpszDisplayName = L"bbbb";



PS а насчёт звёздочек - эт ты зря )
...
Рейтинг: 0 / 0
09.01.2016, 13:56
    #39143778
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
Дмитрий77,

память не забудь аккуратно почистить, лучше всего доверить это с++ коду
...
Рейтинг: 0 / 0
09.01.2016, 14:14
    #39143782
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как вернуть через API массив структур? API эту сам пишу.
ИзопропилДмитрий77,

Код: plaintext
1.
2.
(*lppRecipList)[0].lpszDisplayName = L"aaa";
(*lppRecipList)[1].lpszDisplayName = L"bbbb";



Заработало, однако. До меня б никогда не доперло.
Огромное спасибо.

Изопропилпамять не забудь аккуратно почистить, лучше всего доверить это с++ коду
С
Код: plaintext
1.
  * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(cEntries*sizeof(RECIPLIST));


.Net
Код: vbnet
1.
      Marshal.FreeCoTaskMem(PtrRecipList)


Недостаточно?
(на стороне C++ наверно не смогу, иначе затрется то что возвращаю)

Ну, не считая естественно очистки структур в самих интерфейсах, где это указано в msdn, что действительно делается в си.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как вернуть через API массив структур? API эту сам пишу. / 25 сообщений из 43, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]