(MAPI)尝试从PR_EMS_AB_PROXY_ADDRESSES获取SMTP地址时出现算术溢出



所以我试图使用上面的属性获取SMTP地址属性。但是我得到了算术溢出。

基本使用:

IUnknown = Marshal.GetIUnknownForObject(recipientAddress.MAPIOBJECT);
HrGetOneProp(IMAPIProperty, PR_EMS_AB_PROXY_ADDRESSES, ref pPropValue);
SPropValue propValue = (SPropValue)Marshal.PtrToStructure(pPropValue, typeof(SPropValue));
IntPtr ptrToConvert = new IntPtr(propValue.Value); //arithmetic overflow
sProperty = Marshal.PtrToStringAnsi(ptrToConvert);               

我创建的结构是:

private struct SPropValue {
public unit ulPropTag
public uint dwAlignPad
public long Value
} 

我认为问题出在结构上:http://msdn.microsoft.com/en-us/library/bb415341.aspx

问题是,propValue.Value真的很"长",不适合IntPtr,我认为这个结构实际上是SPropValue结构的指针,

所以我真的不知道如何使用它以及如何解决这个问题。

任何帮助都会被告知。。。

**编辑**我试图创建一个联合PV类,从c++开始,这就是联合类:

typedef union _PV
{
short int           i;          /* case PT_I2 */
LONG                l;          /* case PT_LONG */
ULONG               ul;         /* alias for PT_LONG */
float               flt;        /* case PT_R4 */
double              dbl;        /* case PT_DOUBLE */
unsigned short int  b;          /* case PT_BOOLEAN */
CURRENCY            cur;        /* case PT_CURRENCY */
double              at;         /* case PT_APPTIME */
FILETIME            ft;         /* case PT_SYSTIME */  
...
...

所以我创建了这个结构:

      [StructLayout(LayoutKind.Explicit)]
  private struct PV_Union
  {
        [FieldOffset(0)]
        public Int16            i;          /* case PT_I2 */
     [FieldOffset(0)]
         public Int32               l;          /* case PT_LONG */
     [FieldOffset(0)]
         public UInt32              ul;         /* alias for PT_LONG */
 ....

现在我得到了垃圾价值。。

SPropValue.value结构是一个并集,这意味着成员相互重叠。

为什么不使用AddressEntry.PropertyAccessor.GetProperty来检索属性?

所以我设法解决了它!我来解释。Value实际上是并集类型,我确实找到了正确的内存区域,但读错了。

当我们读取这个内存区域时,我们得到以下内容:

  • uint表示"值"类型和命令,我将其分为2个ushort(第一个-较高的位是返回的类型:PT_MV_TSTRINGS,它等于MV_FLAGS | PT_UNICODE(多值+UNICODE字符串)
  • dwAlignedPad的uint
  • SWStringArray-它是实际的"Value",它有数组长度的uint,后面跟着实际字符串数组的uint(指向数组指针的指针)

所以我创建了以下结构,并将HrGetOneProp读取到其中:

private struct SMultivalueStructure
  {
     public ushort PropType; // Type of returned value
     public ushort Command; //Command we entered (PR_EMS_PROXY...)
     public uint dwAlignPad; // Reserved - usually 4 bytes of 0
     public uint stringArrayLength; // SWStringArray length
     public uint pStringArrayMemoryAddress; //SWStringArray pointer to string array
  }

所以在元帅之后

SMultivalueStructure propValue = (SMultivalueStructure)Marshal.PtrToStructure(pPropValue, typeof(SMultivalueStructure));

我创建了一个长度正确的指针数组来保存指向字符串的指针:

IntPtr[] pStrings = new IntPtr[propValue.stringArrayLength];

然后我在结构中有字符串数组的内存地址,所以我会将指针复制到我刚刚创建的数组中:

Marshal.Copy(new IntPtr(propValue.pStringArrayMemoryAddress), pStrings, 0, (int)propValue.stringArrayLength);

现在我有了每个字符串的内存地址数组,现在只需将其封送到字符串:

for (int i = 0; i < pStrings.Length; ++i)
   {
        string smtpTest = Marshal.PtrToStringAnsi(pStrings[i]);
   }

顺便说一下,字符串数组可以是两个可能的值:(http://msdn.microsoft.com/en-us/library/bb446176.aspx)

  • PT_MV_STRING8-SLPSTRArray
  • PT_MV_UNICODE-SWStringArray

所以我添加了一个检查(针对PropType)-ANSI字符串应该是MV_FLAG|PT_STRING8,UNICODE应该是MV-FLAG|PT_UNICODE,然后使用正确的MarshalPtrToStringAnsi/Uni

我需要检查的几个问题:

  1. 在64位outlook中-这段代码可以吗?还是我必须以不同的方式处理
  2. 检查每个outlook版本(2003200720102010 64位)