提问人:darbid 提问时间:9/28/2023 最后编辑:darbid 更新时间:9/29/2023 访问量:61
如何使用扩展 MAPI GetNamesFromID 获取 Outlook 属性名称
How to get Outlook Property Names using extended MAPI GetNamesFromIDs
问:
我正在尝试使用扩展 MAPI(即 MAPINAMEID 结构的内容)查看 Outlook 邮件中的属性名称。
我得到一个消息的属性标签列表,然后我向下面的代码传递一个值大于0x80000000的标签(uTag)。
GetNamesFromIDs(out IntPtr lppPropTags, ref Guid lpPropSetGuid, uint ulFlags,
out uint lpcPropNames, out IntPtr lpppPropNames);
来自更大内容的相关代码片段。
IntPtr propNames;
SPropTagArray ptArray = new SPropTagArray
{
cValues = (uint)1,
aulPropTag = new uint[] { uTag },
};
IntPtr propTagArrayPtr = Marshal.AllocHGlobal(Marshal.SizeOf<SPropTagArray>());
Marshal.StructureToPtr(ptArray, propTagArrayPtr, true);
HRESULT hr = mapiObj_.GetNamesFromIDs(out propTagArrayPtr, Guid.Empty, 0, out uint pNames, out propNames);
if (hr == HRESULT.S_OK && propNames != IntPtr.Zero)
{
MAPINAMEID nameID = (MAPINAMEID)Marshal.PtrToStructure(propNames, typeof(MAPINAMEID));
LPGuid = (Guid)Marshal.PtrToStructure(nameID.pGuid, typeof(Guid));
ULKind = (uint)nameID.ulKind;
PropKind = nameID.Kind;
if ((KindTypes)ULKind == KindTypes.MNID_ID)
{
IID = nameID.Kind.lID;
}
else if ((KindTypes)ULKind == KindTypes.MNID_STRING)
{
Name = Marshal.PtrToStringUni(nameID.Kind.lpszNameW);
}
}
MAPINative.MAPIFreeBuffer(propTagArrayPtr);
MAPINative.MAPIFreeBuffer(propNames);
结构如下所示
[StructLayout(LayoutKind.Sequential)]
public struct SPropTagArray
{
public uint cValues;
public uint[] aulPropTag;
}
[StructLayout(LayoutKind.Sequential)]
struct MAPINAMEID
{
public IntPtr pGuid;
public int ulKind;
public Kind Kind;
}
[StructLayout(LayoutKind.Explicit)]
struct Kind
{
[FieldOffset(0)]
public int lID;
[FieldOffset(0)]
public IntPtr lpszNameW;
}
- MAPINAMEID 的 PtrToStructure 是否正确?我在 SPropTagArray 中只给出 1 个标签,而 pNames 总是等于 1。
- IntPtr pGuid 实际上是一个 Guid 还是我需要一个特殊的结构?在邮件中找不到它产生的结果。
- ulKind 是否有可能返回 0 或 1 以外的数字?(假设这是MNID_STRING (1) 和 MNID_ID (2) 应该返回的内容)
- Marshal.PtrToStringUni(nameID.Kind.lpszNameW) 还引发了尝试读取或写入受保护的内存。这通常表示其他内存已损坏。打了几个电话后。
最初我什至没有看 MAPINAMEID 。我只是传递了 IntPtr propNames,而没有使用 CREATE 标志将其重新触及 GetIDsFromNames 以将属性添加到新消息中。我注意到对 GetIDsFromNames 的一些调用失败,结果显示参数无效。我认为这是因为 MAPINAMEID 中的某些内容。
编辑 1 - 基于德米特里的评论由于他需要更多的上下文,因此此代码是 VSTO Outlook 外接程序的一部分,该外接程序从 OOM 中获取 MAPIOBJECT,然后复制每个单独的属性。复制的一部分包括 NamedProperties,但是,出于某些原因,我想检查一些添加并删除它们,因此需要知道名称。
我现在使用以下内容,前 2 个参数是 ref 我为 lpPropSetGuid 传递 null
HRESULT GetNamesFromIDs(ref IntPtr lppPropTags, ref IntPtr lpPropSetGuid, uint ulFlags,out uint lpcPropNames, out IntPtr lpppPropNames);
我确实尝试为lppPropTags使用unit[],但我认为有人建议,但得到了无效的args响应。
这似乎有效。
SPropTagArray propTagArray = new SPropTagArray
{
cValues = 1,
aulPropTag = new uint[1]
};
propTagArray.aulPropTag[0] = uTag;
IntPtr propTagArrayPtr = Marshal.AllocHGlobal(Marshal.SizeOf(propTagArray));
Marshal.StructureToPtr(propTagArray, propTagArrayPtr, false);
我所做的最重大的更改是 MAPINAMEID
[StructLayout(LayoutKind.Sequential)]
private struct MAPINAMEID_A
{
public IntPtr lpguid;
public uint ulKind;
public IntPtr lpwstrName; // or lID
};
文档似乎说我只得到一个 GUID 结构,所以我换了一个
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
public struct _GUID
{
public Int32 Data1;
public Int16 Data2;
public Int16 Data3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Data4;
}
我还略微改变了获取 MAPINAMEID 的方式(目前仅针对 1 个元素进行硬编码)
MAPINAMEID_A nameID = new MAPINAMEID_A();
for (int i = 0; i < 1; i++)
{
// Get the pointer at the current index
IntPtr ptrElement = Marshal.ReadIntPtr(mAPINAMEIDArray, i * IntPtr.Size);
// Marshal the pointer to a MAPINAMEID structure
nameID = Marshal.PtrToStructure<MAPINAMEID_A>(ptrElement);
}
_GUID DLPGuid = (_GUID)Marshal.PtrToStructure(nameID.lpguid, typeof(_GUID));
LPGuid = new Guid(DLPGuid.Data1, DLPGuid.Data2, DLPGuid.Data3,
DLPGuid.Data4[0], DLPGuid.Data4[1], DLPGuid.Data4[2], DLPGuid.Data4[3],
DLPGuid.Data4[4], DLPGuid.Data4[5], DLPGuid.Data4[6], DLPGuid.Data4[7]);
目前没有错误,但不确定是否清理内存。
德米特里,我的理解(再次来自你)是,当我在 GetIDsFromNames 中使用 CREATE 将命名属性添加到新消息时,会创建一个新的标记号。但是,据我所知,在复制这些属性时是否有可能生成相同的标签?
答: 暂无答案
评论
GetNamesFromIDs
ref
out
null
GUID.Empty
GetNamesFromIDs
IMAPIProp
RDOStore / RDOFolder / RDOMail / RDOAttachment
GetNamesFromIDs