powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как вернуть через API массив структур? API эту сам пишу.
43 сообщений из 43, показаны все 2 страниц
Как вернуть через API массив структур? API эту сам пишу.
    #39143224
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Исходный код (мой) из которого пытаюсь родить нужную мне 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
Как вернуть через API массив структур? API эту сам пишу.
    #39143264
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,
размер нужно тоже возвращать. например, сделать еще один выходной параметр. (в функцию передать указатель на size_t, в функции под этому адресу записать значение)
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143267
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZiv,
детальнее в эту хрень не волновался, извини...
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143362
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivразмер нужно тоже возвращать.)
Так именно его я возвращаю. 0- если элементов нет или к-во элементов если они есть.
Но к-во элементов в массиве становится известно только внутри самой ф-ции.

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

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

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

Код: 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
Как вернуть через API массив структур? API эту сам пишу.
    #39143423
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну вот так вроде выводит:

Код: 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
Как вернуть через API массив структур? API эту сам пишу.
    #39143448
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий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
Как вернуть через API массив структур? API эту сам пишу.
    #39143478
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77на стороне C через malloc.
ответ в вопросе - выделяй через CoTaskMemAlloc
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143503
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилДмитрий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
Как вернуть через API массив структур? API эту сам пишу.
    #39143525
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77безжалостно глючит
содержательная диагностика
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143530
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

размеры структур сравни в с++ и бейсик коде. выравнивание может быть разным
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143620
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилДмитрий77безжалостно глючит
содержательная диагностика
Я писал выше ошибку в .Net.
авторНеобработанное исключение типа "System.AccessViolationException" в WabTestNet.exe
Дополнительные сведения: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
И происходит она до того как ф-ция чего-то возвращает.
Ошибка очевидно в C-коде при заполнении элемента массива отличного от первого, я выделил строчки в коде.
Сказать какая с т. зр. C не могу, это dll, компилируется нормально.
Я думаю человек пишущий на C сразу поймет, но я то оч. редко к C обращаюсь.
Изопропилразмеры структур сравни в с++ и бейсик коде. выравнивание может быть разным
12 и там и там. Две строки и число по 4 байта на элемент структуры.
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143685
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не получается у меня больше одного элемента вернуть.
Неужели такая сложная задача
Код: 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
Как вернуть через API массив структур? API эту сам пишу.
    #39143695
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

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


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

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

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

Пытаюсь так:
Код: 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
Как вернуть через API массив структур? API эту сам пишу.
    #39143723
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мне реальным только вариант в таком духе видится:

Код: 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
Как вернуть через API массив структур? API эту сам пишу.
    #39143744
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

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

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

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

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

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

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

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



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

память не забудь аккуратно почистить, лучше всего доверить это с++ коду
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143782
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилДмитрий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
Как вернуть через API массив структур? API эту сам пишу.
    #39143785
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Ну, не считая естественно очистки структур в самих интерфейсах, где это указано в msdn, что действительно делается в си.
об этом и речь.

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

я другого пока не понимаю
дописал типа код (на предмет телефонов), расширил структуру

Код: 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.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
typedef struct _RECIPLIST
{
    LPTSTR          lpszDisplayName;
    LPTSTR          lpszEmailAddress;
    ULONG           ulReceipType;
    LPTSTR          lpszHomeTelephoneNumber;
    LPTSTR          lpszHomeFaxNumber;
    LPTSTR          lpszBusinessTelephoneNumber;
    LPTSTR          lpszBusinessFaxNumber;
} RECIPLIST, FAR * LPRECIPLIST;

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;
      * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(cEntries*sizeof(RECIPLIST));
      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 = 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;
                  } //k++
								} //GetProps
							} //ulObjType == MAPI_MAILUSER
            } //OpenEntry
          } //PR_ENTRYID
        } //j++
        (*lppRecipList)[i].lpszDisplayName = m_DisplayName;
        (*lppRecipList)[i].lpszEmailAddress = m_EmailAddress;
        (*lppRecipList)[i].ulReceipType = m_ReceipType;
        (*lppRecipList)[i].lpszHomeTelephoneNumber = m_HomeTelephoneNumber;
        (*lppRecipList)[i].lpszBusinessFaxNumber = m_HomeFaxNumber;
        (*lppRecipList)[i].lpszBusinessTelephoneNumber = m_BusinessTelephoneNumber;
        (*lppRecipList)[i].lpszBusinessFaxNumber = m_BusinessFaxNumber;
        lpWABObject->FreeBuffer(lpProps);
      } //i++
    } //WABOpen
  } //LoadLibrary
  FreeLibrary(hinstLib);
  return cEntries; 
}
}; // extern "C"



И теперь оно стало глючить случайным образом (чем больше элементов, тем больше вероятность) но уже на стороне .Net (количество возвращает). Все пустые строки вроде забиваю "" вместо NULL.

Код: vbnet
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.
 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
  Public Structure RECIPLIST
    Dim lpszDisplayName As String
    Dim lpszEmailAddress As String
    Dim ulReceipType As UInteger
    Dim lpszHomeTelephoneNumber As String
    Dim lpszHomeFaxNumber As String
    Dim lpszBusinessTelephoneNumber As String
    Dim lpszBusinessFaxNumber As String
  End Structure

   Private Sub ButtonTestWab_Click(sender As Object, e As EventArgs) Handles ButtonTestWab.Click
    Dim PtrRecipList As New IntPtr
    Dim num As UInteger
    'MsgBox(CPP_AddressBook( _
    ' Me.Handle, _
    ' CType(Val(Me.TextBoxDestFields.Text), UInteger), _
    ' Me.TextBoxCaption.Text, _
    ' {Me.TextBoxTitleTo.Text, Me.TextBoxTitleCC.Text, Me.TextBoxTitleBCC.Text}, _
    ' Me.CheckBoxAddressOne.Checked, _
    ' PtrRecipList))
    num = CPP_AddressBook( _
     Me.Handle, _
     3, _
     "Выбрать получателей", _
     {"Кому:", "Копия:", "Скрытая копия:"}, _
     False, _
     PtrRecipList)
    MsgBox(num)
    'MsgBox(PtrRecipList)
    If num > 0 Then
      Dim NewReceipts() As RECIPLIST = Nothing
      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)
        'ulRecipClass =1 (To:) =2 (CC:) =3 (BCC:)
        Debug.Print(NewReceipts(i).ulReceipType.ToString & " : " & NewReceipts(i).lpszDisplayName & "<" & NewReceipts(i).lpszEmailAddress & _
         "> HomeTelephoneNumber=" & NewReceipts(i).lpszHomeTelephoneNumber & " HomeFaxNumber=" & NewReceipts(i).lpszHomeFaxNumber & _
        " BusinessTelephoneNumber=" & NewReceipts(i).lpszBusinessTelephoneNumber & _
        " BusinessFaxNumber=" & NewReceipts(i).lpszBusinessFaxNumber)
      Next
      Marshal.FreeCoTaskMem(PtrRecipList)
    End If
  End Sub


.NetВ среде выполнения обнаружена критическая ошибка. Ошибка произошла по адресу 0x73f59485 в потоке 0x11cc. Код ошибки 0xc0000005. Она может быть вызвана ошибкой в CLR или в небезопасных либо не поддающихся проверке фрагментах пользовательского кода. Обычно источниками таких ошибок бывают ошибки упаковки, допускаемые пользователями при COM-взаимодействии, либо PInvoke, повредивший стек.
И мне очень не нравится выделенное место, где я плюсую указатель,
вообще говоря в .Net2 такое вообще не пройдет, надо типа New IntPtr(ptr.toInt32/64 + дельта) но в .Net 4.5 прокатывает.
такое ощущение что я местами промазываю мимо структуры
Нет ли какого подвоха? Или другого приема?
М.б. можно попробовать параллельно вернуть массив указателей на элементы и применять их а не один, который двигаю?
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143803
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Перед глюком обычно начинает писать немного чуши (которой реально нет)

Код: plaintext
1.
2.
3.
2 : 2900112@mail.ru<;2900112@mail.ru>; HomeTelephoneNumber= HomeFaxNumber= BusinessTelephoneNumber= BusinessFaxNumber=
2 : 20@inbox.ru<;20@inbox.ru>; HomeTelephoneNumber= HomeFaxNumber=јански календар BusinessTelephoneNumber= BusinessFaxNumber=
2 : 1a2b3c-sat@inbox.ru<;1a2b3c-sat@inbox.ru>; HomeTelephoneNumber= HomeFaxNumber=ански календар BusinessTelephoneNumber= BusinessFaxNumber=



Предполагаю что в какой-то момент в Debug.Print ловится NULL (которого по логике там быть не должно) и на этом вылетает.
когда я делаю
Код: plaintext
1.
      * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(cEntries*sizeof(RECIPLIST));


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

преждевременное освобождение памяти
lpWABObject->FreeBuffer(lpProps);
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143818
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77,

копируй строки, а не ссылки
проще создавать/освобождать SysAllocString/SysFreeString (BSTR внутри будут)

освобождение памяти, как я уже и говорил, лучше сделать отдельным вызовом типа
CPP_AddressBookFree(PtrRecipList,num) - и строки почистить и массив структур - всё в c++ коде, который точно знает что и как размещалось

с пустыми строками - или NULL оставляй - в бейсике разберёшься, или SysAllocString("") делай.
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143952
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторИ теперь оно стало глючить случайным образом (чем больше элементов, тем больше вероятность) но уже на стороне .Net (количество возвращает). Все пустые строки вроде забиваю "" вместо NULL
Вылечил заменой
Код: plaintext
1.
2.
3.
4.
C
      * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(cEntries*sizeof(RECIPLIST));
.NET
      Marshal.FreeCoTaskMem(PtrRecipList)


на
Код: plaintext
1.
2.
3.
4.
5.
C
     HGLOBAL hMem = GlobalAlloc(GMEM_ZEROINIT,cEntries*sizeof(RECIPLIST));
      * lppRecipList=(LPRECIPLIST) GlobalLock(hMem);
.NET
      Marshal.FreeHGlobal(PtrRecipList)


Крашить перестало.
Но при этом глючки остались.
При достаточно большом к-ве элементов.
И исключительно в номерах телефонов и факсов (те поля которые выводятся через lpProps дополнительным кодом) - не везде но вполне стабильные:
Код: xml
1.
2.
3.
4.
5.
1 : Ольга<olga@rus*********.ru> HomeTelephoneNumber=&#19795;&#20564;&#14650;&#12344;&#12342;&#16438;&#16717;&#19529;&#21038;U&#5376;&#32768;&#37864;&#8172;&#4472;&#32768;SMTP HomeFaxNumber= BusinessTelephoneNumber= BusinessFaxNumber=
1 : Гоша<gm**@rus*********.ru> HomeTelephoneNumber=ComI&#37642;&#8130;&#5966;&#32768;&#8192;&#18384;&#1645;&#19795;&#20564;&#16698;&#19246;&#21327;&#20300;&#16470;&#19783;&#11864;&#20291;M HomeFaxNumber= BusinessTelephoneNumber= BusinessFaxNumber=
1 : Молча*** С.Я.<cyn**-s@yandex.ru>; HomeTelephoneNumber=SMTP&#37838;&#8078;&#2816;&#32768;&#8192;&#4848;&#1638; HomeFaxNumber= BusinessTelephoneNumber=SMTP BusinessFaxNumber=
1 : Елена Николаевна-Авангард<os******@avangard.ru> HomeTelephoneNumber= HomeFaxNumber= BusinessTelephoneNumber=&#9744;&#8179;&#5690;&#32768;&#8192;&#22776;&#1644;4 BusinessFaxNumber=&#8192;&#23016;&#1644;1
1 : 3-й спецмаш<z11@mz.perm.ru>; HomeTelephoneNumber= HomeFaxNumber=&#14372;&#1640;SMTP BusinessTelephoneNumber= BusinessFaxNumber=


(*-ки мои, ???-вопросики-китайские крякозябры вместо набора цифр, не глючат только последние выводимые строки с телефонами)
Глюки для фиксированной большой выборки достаточно стабильны ( одни и те же крякозябры) Ну да, это большой непорядок, именно по телефонам может делаться большая выборка.

Изопропилпреждевременное освобождение памяти
lpWABObject->FreeBuffer(lpProps);
Не уверен, по крайней мере если закомментировать то те же глюки -крякозябры остаются.
lpProps вычисляется каждый раз для заново для каждого контакта - дополнительное рытье на предмет телефонов.
На самом деле не уверен что его надо грохать и именно через lpWABObject->FreeBuffer, эта ф-ция по мсдн должна грохать другой объект &lpWABObject возвращаемый "WabOpen".

IMailUser::GetProps MethodlppPropArray SPropValue
Address of a pointer to a variable of type SPropValue that receives the property values. The variable must be freed by the client.
сказано размыто лишь, что "must be freed by the client" но не сказано чем именно.
lpWABObject->FreeBuffer(lpProps); вято из одного из немногочисленных примеров что удалось найти и не уверен что с этим примером все эквивалентно. Еще где-то видел код где чел делал MapiFreeBuffer(lpProps), но мне кажется это другая опера и чел не прав.

Да, я задумался. Что можно поменять? Есть идеи?

Изопропилкопируй строки, а не ссылки
проще создавать/освобождать SysAllocString/SysFreeString (BSTR внутри будут)
Я знаю что ты любишь BSTR по очень старому топику(тоже делал dll). Если только в лоб покажешь как. Но честно не очень хочу, мне хватило утреннего маразма с * и скобками. И BSTR непонятно как с юникодом соотносится, там же другая ф-ция будет Marshal.ToBSTR ..кажется.
Лучше б допонять как собычными виндовыми LPWSTR указателями допилить до ума.
Тек. полный 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.
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.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
typedef struct _RECIPLIST
{
    LPTSTR          lpszDisplayName;
    LPTSTR          lpszEmailAddress;
    LONG            ulReceipType;
    LPTSTR          lpszHomeTelephoneNumber;
    LPTSTR          lpszBusinessTelephoneNumber;
    LPTSTR          lpszBusinessFaxNumber;
    LPTSTR          lpszHomeFaxNumber;
} RECIPLIST, FAR * LPRECIPLIST;
...
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;
      //* lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(cEntries*sizeof(RECIPLIST));
      LPWSTR m_DisplayName;
      LPWSTR m_EmailAddress;
      ULONG m_ReceipType=0; //1-To,2-CC,3-BCC
      LPWSTR m_HomeTelephoneNumber;
      LPWSTR m_HomeFaxNumber;
      LPWSTR m_BusinessTelephoneNumber;
      LPWSTR m_BusinessFaxNumber;
 	    HGLOBAL hMem = GlobalAlloc(GMEM_ZEROINIT,cEntries*sizeof(RECIPLIST));
      * lppRecipList=(LPRECIPLIST) GlobalLock(hMem);
      for(ULONG i=0;i<lppAdrList->cEntries;i++)
      {
        m_DisplayName = L"";
        m_EmailAddress = L"";
        m_ReceipType=0; //1-To,2-CC,3-BCC
        m_HomeTelephoneNumber = L"";
        m_HomeFaxNumber = L"";
        m_BusinessTelephoneNumber = L"";
        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;
                  } //k++
								} //GetProps
							} //ulObjType == MAPI_MAILUSER
            } //OpenEntry
          } //PR_ENTRYID
        } //j++
        (*lppRecipList)[i].lpszDisplayName = m_DisplayName;
        (*lppRecipList)[i].lpszEmailAddress = m_EmailAddress;
        (*lppRecipList)[i].ulReceipType = m_ReceipType;
        (*lppRecipList)[i].lpszHomeTelephoneNumber = m_HomeTelephoneNumber;
        (*lppRecipList)[i].lpszHomeFaxNumber = m_HomeFaxNumber;
        (*lppRecipList)[i].lpszBusinessTelephoneNumber = m_BusinessTelephoneNumber;
        (*lppRecipList)[i].lpszBusinessFaxNumber = m_BusinessFaxNumber;
        lpWABObject->FreeBuffer(lpProps);
      } //i++
    } //WABOpen
  } //LoadLibrary
  FreeLibrary(hinstLib);
  return cEntries; 
}
}; // extern "C"

...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39143954
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Не уверен, по крайней мере если закомментировать то те же глюки -крякозябры остаются.
lpProps вычисляется каждый раз для заново для каждого контакта - дополнительное рытье на предмет телефонов.
На самом деле не уверен что его надо грохать и именно через lpWABObject->FreeBuffer, эта ф-ция по мсдн должна грохать другой объект &lpWABObject возвращаемый "WabOpen".

это не повод возвращать ссылки на освобождённую память, и без того граблей с этим древним API выше крыши
(забавно, при создании этого API OleVariant был ещё неизвестен)


никакой мистики в BSTR нет - указатель кажет на первый символ строки, длина - впереди, для чтения ничем
не отличается от LPWSTR. С юникодом всё прозрачно, в конце концов - BSTR - это стандартные строки в COM и твоём любимом VB6
SysAllocString(строка) - просто создаёт копию строки


Дмитрий77сказано размыто лишь, что "must be freed by the client" но не сказано чем именно.
не освободишь - получишь утечку памяти. в WinAPI таких мутных мест много

откуда контакты в примере - из локальной книги или из Active Directory?

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

ИзопропилBSTR.
Ну м.б. попробую но завтра если только (утро вечера мудренее). Я в той первой своей dll пробовал и вроде получалось, но остановился все же на возврате char *, почему именно не помню. ByRef там нигде не использовал, и там чистое ANSI было(прибамбас к AsProtect чисто EN , причем в .Net без dll с той кухней по определению вообще никак).
Какую ф-цию использовать ты вроде сказал, хотя я эти вещи на лету не схватываю.

[quot Изопропил]откуда контакты в примере - из локальной книги или из Active Directory?
Папка "контакты" в Win 8.1, но конкретно этот набор был экспортирован однажды из OE6 (XP).
С Active Directory (Win Server +Domen,) никогда не работал, и сервера тестирую только в режиме "рабочей группы", Domen пару раз делал давно, но глючно это, и без глюков назад уже не преобразуешь.

ИзопропилPS для начала отладь это хозяйство без dotnet
Легко сказать, хотелось бы хоть как то уже доделать и воспользоваться.
Изопропилвызывает подозрение, что пишется где-то что-то мимо
Какое-то понимание выше начального есть, но когда слишком задумываешься, крыша таки едет.
Напр. выделяю память под структуру, строка - 4 байта-понятно, указатель,
а сама строка по этому адресу насколько неприкосновенна.. все ...крыша поехала.
Если честно, хочется сделать - главное чтоб работало, забыть и пользоваться.
То что чуть-чуть чего-то теряется - не, стараюсь вовсю как правильно, но часто это не очень то и существенно.
<Адресная книга> - по логике кнопка редко нажимаемая, лично мне нужна для нескольких настроек где надо выбрать мыло, и для окна отправки факса, где надо задать номер(а) факса - окно живущее мб. полминуты пока этот номер не выберут(а скорее всего просто напечатают) + пару параметров может быть (это не таймер который иконки генерит по 5 раз на секунду - классический пример когда я конкретно однажды накололся -через несколько часов все висло). При том что у меня в основном приложении своей адресной книги пока нет , идея думается не плоха, стандартна и посему правильная, м.б. ей и не будут пользоваться, но хорошее впечатление это производит.
А вот крякозябры вместо номеров телефонов - это да, косяк практически ощущаемый.

Из VB(6 или .Net) обычно на ура все делаю, рука набита, но не с интерфейсами.
А в C вроде все еще проще, но прикладные моменты убивают наповал.
Разные рантаймы с одной стороны (поэтому и делаю в 2005-й чтоб не связываться, подмечено/годами проверено что любой .Net >= 2.0 SP1 (и независимый 4.5 тоже) ставит нужный рантайм под эту 2005-ю сборку 50727 кажется, а этот .Net (2.0 SP1 для XP, 4.5 или выше для семерки/висты, на остальных по дефолту) я вместе с прогой при установке требую, т.е. не надо других дистрибюшенов), куча заумностей с теми же строками с другой стороны и т.п.
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39144008
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Если честно, хочется сделать - главное чтоб работало, забыть и пользоваться.
память утечёт
в коде как минимум двум интерфейсам не делается Release()
если с освобождением памяти разобраться не удастся(ввиду кривой документации, в частности)
- говнокод следует изолировать в отдельном процессе

Дмитрий77Напр. выделяю память под структуру, строка - 4 байта-понятно, указатель,
а сама строка по этому адресу насколько неприкосновенна.. все ...крыша поехала.
получил строку - скопируй к себе - будешь уверен что преждевременно её никто не освободит и твоя ссылка не будет указывать в небо.
Дмитрий77Из VB(6 или .Net) обычно на ура все делаю, рука набита, но не с интерфейсами.
это основы COM - не разберёшься - будешь и дальше жрать кактус

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

Ну смотри.
Виновата действительно
Код: plaintext
1.
lpWABObject->FreeBuffer(lpProps);


если убрать то все OK
тогда уж видимо
Код: plaintext
1.
2.
        lpWABObject->FreeBuffer(lpProps);
        lpWABObject->FreeBuffer(lppAdrList->aEntries[i].rgPropVals);


проще убрать
не уверен что оно здесь вообще надо в моем контексте

IWABObject::FreeBuffer Method
Frees memory allocated with IWABObject::AllocateBuffer or any of the other Windows Address Book (WAB) methods.
AllocateBuffer я нигде не делаю

Документации действительно не очень
Например
ADRLIST Structure
про память мало чего сказано и дальше если идти по ссылкам ->ADRENTRY->SPropValue

Зато вот здесь в аналогичной штуке
ADRLIST (Office 2013)
до фига чего есть
The MAPIAllocateBuffer and MAPIFreeBuffer functions must be used to allocate and free the ADRLIST structure and all its parts.
(аналог lpWABObject->AllocateBuffer lpWABObject->FreeBuffer)
и дальше
Managing Memory for ADRLIST and SRowSet Structures
+ картинка прилагается

Что до MSDN(Windows)
явно смущает только
IMailUser::GetProps Method
lppPropArray SPropValue
Address of a pointer to a variable of type SPropValue that receives the property values. The variable must be freed by the client.
откуда и родилась строчка lpWABObject->FreeBuffer(lpProps);

Изопропилесли с освобождением памяти разобраться не удастся(ввиду кривой документации, в частности)
- * следует изолировать в отдельном процессе
При завершении приложения память все равно освобождается(думаю да)? Или утекает до перезагрузки компа?
Если ДА то проще забить на все FreeBuffer(lpProps), и не уверен что нужны,
иначе я действительно все указатели грохаю до того как их надо прочесть в VB.
Как я сказал, использование этой кухни нечастое и неактивное (выбрать пару e-mail -структуры небольшие), а окно выбора списка телефонов - отдельный exe, открыл, выбрал закрыл.

Про BSTR и копирование строк я идею понял.

А если с указателями как у меня, то как их грохать (если мне их надо сначала вернуть)?
Или давай так, как мне скопировать указатели в другие (новые) указатели, которые я грохаю уже в VB (моя структура которую я возвращаю).
Потому что в VB я грохаю не все props (есть props в ориг. структуре, кот. я не использую, использую 3 из 12 + 4 из 18, остальное стало быть утечка).
И тогда уж надо не FreeBuffer(lpProps), а еще FreeBuffer(lpProp[i]) для каждого, и т.д. как разжевано в офисовской документации.

Изопропилв коде как минимум двум интерфейсам не делается Release()
Где чего писать?
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39144026
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Изопропилв коде как минимум двум интерфейсам не делается Release()
Где чего писать?
lpAdrBook->Release( что сюда писать?)
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39144028
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77lpAdrBook->Release( что сюда писать?)
А фу,
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
  LPADRBOOK lpAdrBook;
  LPWABOBJECT lpWABObject;
...
    IMailUser *lpMailUser = static_cast <IMailUser *>(lpUnk);
    ...
    lpMailUser->Release(); 
...
  lpAdrBook->Release();
  lpWABObject->Release();


добавил.
; забыл вставить, компилятор ругнулся
а там же void
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39144203
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропилкопируй строки, а не ссылки
проще создавать/освобождать SysAllocString/SysFreeString (BSTR внутри будут)
Здесь ты думаю прав.

С
Код: 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.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
typedef struct _RECIPLIST
{
    BSTR            lpszDisplayName;
    BSTR            lpszEmailAddress;
    LONG            ulReceipType;
    BSTR            lpszHomeTelephoneNumber;
    BSTR            lpszBusinessTelephoneNumber;
    BSTR            lpszBusinessFaxNumber;
    BSTR            lpszHomeFaxNumber;
} RECIPLIST, FAR * LPRECIPLIST;

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;
      * lppRecipList=(LPRECIPLIST)CoTaskMemAlloc(cEntries*sizeof(RECIPLIST));
      LPWSTR m_DisplayName;
      LPWSTR m_EmailAddress;
      ULONG m_ReceipType=0; //1-To,2-CC,3-BCC
      LPWSTR m_HomeTelephoneNumber;
      LPWSTR m_HomeFaxNumber;
      LPWSTR m_BusinessTelephoneNumber;
      LPWSTR m_BusinessFaxNumber;
      //HGLOBAL hMem = GlobalAlloc(GMEM_ZEROINIT,cEntries*sizeof(RECIPLIST));
      //* lppRecipList=(LPRECIPLIST) GlobalLock(hMem);
      for(ULONG i=0;i<lppAdrList->cEntries;i++)
      {
        m_DisplayName = L"";
        m_EmailAddress = L"";
        m_ReceipType=0; //1-To,2-CC,3-BCC
        m_HomeTelephoneNumber = L"";
        m_HomeFaxNumber = L"";
        m_BusinessTelephoneNumber = L"";
        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) //PR_DISPLAY_NAME_W
                      m_BusinessTelephoneNumber=lpProps[k].Value.lpszW;
                    if (lpProps[k].ulPropTag == PR_BUSINESS_FAX_NUMBER_W)
                      m_BusinessFaxNumber=lpProps[k].Value.lpszW;
                  } //k++
                  lpMailUser->Release();
                } //GetProps
              } //ulObjType == MAPI_MAILUSER
            } //OpenEntry
          } //PR_ENTRYID
        } //j++
        (*lppRecipList)[i].lpszDisplayName = SysAllocString(m_DisplayName);
        (*lppRecipList)[i].lpszEmailAddress = SysAllocString(m_EmailAddress);
        (*lppRecipList)[i].ulReceipType = m_ReceipType;
        (*lppRecipList)[i].lpszHomeTelephoneNumber = SysAllocString(m_HomeTelephoneNumber);
        (*lppRecipList)[i].lpszHomeFaxNumber = SysAllocString(m_HomeFaxNumber);
        (*lppRecipList)[i].lpszBusinessTelephoneNumber = SysAllocString(m_BusinessTelephoneNumber);
        (*lppRecipList)[i].lpszBusinessFaxNumber = SysAllocString(m_BusinessFaxNumber);
        lpWABObject->FreeBuffer(lpProps);
        lpWABObject->FreeBuffer(lppAdrList->aEntries[i].rgPropVals);
      } //i++
      lpWABObject->FreeBuffer(lppAdrList->aEntries);
      lpWABObject->FreeBuffer(lppAdrList);
      lpAdrBook->Release();
      lpWABObject->Release();
    } //WABOpen
  } //LoadLibrary
  FreeLibrary(hinstLib);
  return cEntries; 
}


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


Т.е. что сделал:
1) заменил в структуре строки на BSTR, добавил SysAllocString(m_строка)
2) применил lpWABObject->FreeBuffer() ко всему к чему применилось и не противоречит здравому смыслу (начитавшись оффисовской документации по структуре ADRLIST)
Код: plaintext
1.
2.
3.
4.
5.
        lpWABObject->FreeBuffer(lpProps);
        lpWABObject->FreeBuffer(lppAdrList->aEntries[i].rgPropVals);
...
      lpWABObject->FreeBuffer(lppAdrList->aEntries);
      lpWABObject->FreeBuffer(lppAdrList);


при этом компилятор не дал мне сделать
Код: plaintext
1.
2.
 lpWABObject->FreeBuffer(lpProps[k]);
lpWABObject->FreeBuffer(lppAdrList->aEntries[i].


хз
3) Вернул опять CoTaskMemAlloc/ Marshal.FreeCoTaskMem(PtrRecipList)
4) ->Release для интерфейсов в 3 места добавил как было сказано
Вроде все прилично вышло, без иероглифов, вылетов и висяков.

Изопропилосвобождение памяти, как я уже и говорил, лучше сделать отдельным вызовом типа
CPP_AddressBookFree(PtrRecipList,num) - и строки почистить и массив структур - всё в c++ коде, который точно знает что и как размещалось)
здесь хуже
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
void __stdcall CPP_AddressBookFree(LPRECIPLIST FAR * lppRecipList,ULONG ulNum)
{ 
  if (ulNum>0) {
    for(ULONG i=0;i<ulNum;i++) {
      SysFreeString((*lppRecipList)[i].lpszDisplayName);
      SysFreeString((*lppRecipList)[i].lpszEmailAddress);
      SysFreeString((*lppRecipList)[i].lpszHomeTelephoneNumber);
      SysFreeString((*lppRecipList)[i].lpszHomeFaxNumber);
      SysFreeString((*lppRecipList)[i].lpszBusinessTelephoneNumber);
      SysFreeString((*lppRecipList)[i].lpszBusinessFaxNumber);
    }
  }
  CoTaskMemFree(* lppRecipList);
}


Код: vbnet
1.
2.
3.
4.
 Public Declare Sub CPP_AddressBookFree Lib "mydll.dll" ( _
   ByVal lppRecipList As IntPtr, ByVal ulNum As UInteger)
...
      CPP_AddressBookFree(PtrRecipList, num)



1) если CPP_AddressBookFree в СИ сделать пустую (в теле ф-ции оставить только ;), то съедает (естественно ничего не делая)
2) на блок с SysFreeString .Net дает ошибку
Необработанное исключение типа "System.AccessViolationException" в WabTestNet.exe
Дополнительные сведения: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
3) Если блок с SysFreeString .Net закомментировать (оставить только CoTaskMemFree(* lppRecipList);),
то .Net не ругается но тупо виснет с колесиком типа "песочные часики".

Чет напортачил опять, пока идей нет.
CoTaskMemFree конечно можно сделать и из VB (Marshal.FreeCoTaskMem) как и делал, а насчет SysFreeString чет не уверен.
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39144292
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77а насчет SysFreeString чет не уверен.
Marshal.FreeBSTR

но лучше баги вычистить
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39145064
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилMarshal.FreeBSTR
через .Net у меня что-то с ходу не получилось.
Изопропилно лучше баги вычистить
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
void __stdcall CPP_AddressBookFree(LPVOID lpRL,ULONG ulNum)
{ 
 LPRECIPLIST lpRecipList = (LPRECIPLIST)lpRL;
 //TCHAR buf[1024];

 if (ulNum>0) {
    for(ULONG i=0;i<ulNum;i++) {
      //wsprintf(buf, L"%s test", lpRecipList[i].lpszDisplayName);
      //MessageBox(0,buf,NULL,0);
      SysFreeString(lpRecipList[i].lpszDisplayName);
      SysFreeString(lpRecipList[i].lpszEmailAddress);
      SysFreeString(lpRecipList[i].lpszHomeTelephoneNumber);
      SysFreeString(lpRecipList[i].lpszHomeFaxNumber);
      SysFreeString(lpRecipList[i].lpszBusinessTelephoneNumber);
      SysFreeString(lpRecipList[i].lpszBusinessFaxNumber);
    }
  }
  CoTaskMemFree(lpRL);
}

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

Но я еще задачу хочу решить.
Допустим есть выбранный список,
ну т.е.
[DispayName<]myemail@myserver.com[>]
(или напр. 3 списка To CC BCC)

Я хочу подать эту входную инфо в IAdrBook::Address ,
чтобы отобразить уже выбранные адреса в диалоге Выбор Адресата, удалить дополнить и т.п.

Для этого мне надо подать LPADRLIST lppAdrList ( ADRLIST Structure ) на вход вместо NULL.

Далее адресаты бывают Resolved (полноценная структура ADRENTRY Structure ) -соответствуют записи в контактах - отображается нормальным образом (в To,CC, или BCC)
и Unresolved (неполноценная структура) -не выяснено или отсутствует в контактах адресной книги отображается красным знаком вопроса (в To,CC, или BCC)

Чтобы сделать Unresolved-> Resolved надо так понял применить IAddrBook::ResolveName Method к грубо набросанной структуре LPADRLIST lppAdrList (напр. указывается только одно св-во: email адрес, ResolveName вытаскивает имя и т.п.)

Попробовал такой тест:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
#define CbNewSPropValue(_centries) \
    ((_centries)*sizeof(SPropValue))
...
      LPADRLIST lppAdrList = NULL;

      HRESULT hrAdrList = lpWABObject->AllocateBuffer(CbNewADRLIST(1),(LPVOID*) &lppAdrList);        
      lppAdrList->cEntries=1; // lppAdrList contains one entry
      lppAdrList->aEntries[0].cValues=3; // this entry has 3 properties
      hrAdrList = lpWABObject->AllocateBuffer(CbNewSPropValue(3), (LPVOID*)&lppAdrList->aEntries[0].rgPropVals);  // allocate buffer for 3 props
      lppAdrList->aEntries[0].rgPropVals[0].ulPropTag=PR_RECIPIENT_TYPE; 
      lppAdrList->aEntries[0].rgPropVals[0].Value.ul=MAPI_TO;
      lppAdrList->aEntries[0].rgPropVals[1].ulPropTag=PR_EMAIL_ADDRESS_W; 
      lppAdrList->aEntries[0].rgPropVals[1].Value.lpszW=L"12345@mail.ru";
      lppAdrList->aEntries[0].rgPropVals[2].ulPropTag=PR_DISPLAY_NAME_W; 
      lppAdrList->aEntries[0].rgPropVals[2].Value.lpszW=L"12345@mail.ru";
      //lppAdrList->aEntries[0].rgPropVals[3].ulPropTag=PR_ADDRTYPE_W;  
      //lppAdrList->aEntries[0].rgPropVals[3].Value.lpszW=L"SMTP";
      hRes=lpAdrBook->ResolveName(0, MAPI_UNICODE, NULL, lppAdrList);
      if (hRes!=S_OK)
				MessageBox(0,L"error",NULL,0);


      hRes = lpAdrBook->Address(&lpulUIParam, &lpAdrParms, &lppAdrList);




Если выделенная строчка ResolveName закомментирована или дает "error", то передаваемый lppAdrList не модифицируется (т.е. адресат добавляется но со знаком красного вопроса -Unresolved).

А вот если OK, то возвращается структура в которой все строки пустые (кроме PR_RECIPIENT_TYPE который ULONG).
Соответственно адресат вообще не отображается.

Что тут не так в моем коде? (насчет AllocateBuffer/FreeBuffer пока не делал, просьба не предираться, AllocateBuffer-ы вроде сделал правильно ).

Пока пробую в чисто C exe.
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39146356
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я вот чего не понимаю,

попробовал в ANSI -все работает:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
     LPADRLIST lppAdrList = NULL;

      HRESULT hrAdrList = lpWABObject->AllocateBuffer(CbNewADRLIST(1),(LPVOID*) &lppAdrList);  // allocate the lpadrlist with old list's size +1 size. 
      lppAdrList->cEntries=1; // lppAdrList contains one entry
      lppAdrList->aEntries[0].cValues=3; // this entry has 3 properties
      hrAdrList = lpWABObject->AllocateBuffer(CbNewSPropValue(3), (LPVOID*)&lppAdrList->aEntries[0].rgPropVals);  // allocate buffer for 3 props
      lppAdrList->aEntries[0].rgPropVals[0].ulPropTag=PR_RECIPIENT_TYPE; 
      lppAdrList->aEntries[0].rgPropVals[0].Value.ul=MAPI_CC;
      lppAdrList->aEntries[0].rgPropVals[1].ulPropTag=PR_EMAIL_ADDRESS_A; 
      lppAdrList->aEntries[0].rgPropVals[1].Value.lpszA="myname@myemail.ru";
      lppAdrList->aEntries[0].rgPropVals[2].ulPropTag=PR_DISPLAY_NAME_A; 
      lppAdrList->aEntries[0].rgPropVals[2].Value.lpszA="Вася";
      //lppAdrList->aEntries[0].rgPropVals[3].ulPropTag=PR_ADDRTYPE_A;  
      //lppAdrList->aEntries[0].rgPropVals[3].Value.lpszA="SMTP";
      hRes=lpAdrBook->ResolveName(0, 0, NULL, lppAdrList);
      if (hRes!=S_OK)
				MessageBox(0,"error",NULL,0);
      hRes = lpAdrBook->Address(&lpulUIParam, &lpAdrParms, &lppAdrList);



Вася добавляется в список адресатов, причем даже без знака вопроса (c возможностью сразу добавить в адр. книгу через свойства).

Аналогичный код в Юникоде:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
     LPADRLIST lppAdrList = NULL;

      HRESULT hrAdrList = lpWABObject->AllocateBuffer(CbNewADRLIST(1),(LPVOID*) &lppAdrList);  // allocate the lpadrlist with old list's size +1 size. 
      lppAdrList->cEntries=1; // lppAdrList contains one entry
      lppAdrList->aEntries[0].cValues=3; // this entry has 3 properties
      hrAdrList = lpWABObject->AllocateBuffer(CbNewSPropValue(3), (LPVOID*)&lppAdrList->aEntries[0].rgPropVals);  // allocate buffer for 3 props
      lppAdrList->aEntries[0].rgPropVals[0].ulPropTag=PR_RECIPIENT_TYPE; 
      lppAdrList->aEntries[0].rgPropVals[0].Value.ul=MAPI_CC;
      lppAdrList->aEntries[0].rgPropVals[1].ulPropTag=PR_EMAIL_ADDRESS_W; 
      lppAdrList->aEntries[0].rgPropVals[1].Value.lpszW=L"myname@myemail.ru";
      lppAdrList->aEntries[0].rgPropVals[2].ulPropTag=PR_DISPLAY_NAME_W; 
      lppAdrList->aEntries[0].rgPropVals[2].Value.lpszW=L"Вася";
      //lppAdrList->aEntries[0].rgPropVals[3].ulPropTag=PR_ADDRTYPE_W;  
      //lppAdrList->aEntries[0].rgPropVals[3].Value.lpszW=L"SMTP";
      hRes=lpAdrBook->ResolveName(0, MAPI_UNICODE, NULL, lppAdrList);
      if (hRes!=S_OK)
				MessageBox(0,L"error",NULL,0);
      hRes = lpAdrBook->Address(&lpulUIParam, &lpAdrParms, &lppAdrList);


не работает как писал в посте выше,
хотя вроде все корректно заменил:_W, .lpszW, MAPI_UNICODE флаг задал
Мне нужен Юникод.
...
Рейтинг: 0 / 0
Как вернуть через API массив структур? API эту сам пишу.
    #39146393
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Все, заработало:
UNICODE Support in WAB

ResolveNameSpecify WAB_RESOLVE_UNICODE (not MAPI_UNICODE) if all strings in the ADRLIST are in UNICODE. The returned strings are in UNICODE. Otherwise, all in and out strings are ANSI/DBCS.

Почему-то смотрел в описание совсем другой ф-ции:
IABContainer::ResolveNames

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
      HRESULT hrAdrList = lpWABObject->AllocateBuffer(CbNewADRLIST(1),(LPVOID*) &lppAdrList);  // allocate the lpadrlist with old list's size +1 size. 
      lppAdrList->cEntries=1; // lppAdrList contains one entry
      lppAdrList->aEntries[0].cValues=4; // this entry has 4 properties
      hrAdrList = lpWABObject->AllocateBuffer(CbNewSPropValue(4), (LPVOID*)&lppAdrList->aEntries[0].rgPropVals);  // allocate buffer for one props
      lppAdrList->aEntries[0].rgPropVals[0].ulPropTag=PR_RECIPIENT_TYPE; 
      lppAdrList->aEntries[0].rgPropVals[0].Value.ul=MAPI_CC;
      lppAdrList->aEntries[0].rgPropVals[1].ulPropTag=PR_EMAIL_ADDRESS_W; 
      lppAdrList->aEntries[0].rgPropVals[1].Value.lpszW=L"myname@myemail.ru";
      lppAdrList->aEntries[0].rgPropVals[2].ulPropTag=PR_DISPLAY_NAME_W; 
      lppAdrList->aEntries[0].rgPropVals[2].Value.lpszW=L"Вася";
      lppAdrList->aEntries[0].rgPropVals[3].ulPropTag=PR_ADDRTYPE_W;  
      lppAdrList->aEntries[0].rgPropVals[3].Value.lpszW=L"SMTP";
      hRes=lpAdrBook->ResolveName(0, WAB_RESOLVE_UNICODE , NULL, lppAdrList);
      if (hRes!=S_OK)
				MessageBox(0,L"error",NULL,0);
      hRes = lpAdrBook->Address(&lpulUIParam, &lpAdrParms, &lppAdrList);
...
Рейтинг: 0 / 0
43 сообщений из 43, показаны все 2 страниц
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как вернуть через API массив структур? API эту сам пишу.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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