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


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