Multi-Valued Crawled Properties

Jun 5, 2009 at 6:16 PM
Edited Jun 5, 2009 at 6:19 PM

First of all, thanks so much for this code, it has been incredibly useful.  I noticed that in your latest version you're supporting support for other properties besides just strings.  I was wondering how I would go about adding a property to my ContentEnumerator that would be crawled as a multi-valued property.  From looking at IUrlAccessor it seems like I need to add a CAPROPVARIANT, but I'm having trouble getting a pointer to an array of PROPVARIANTs.  I would appreciate it if someone could provide a sample for adding, say, an array of strings as a property in the ContentEnumerator.  Here's what I've got so far:

CAPROPVARIANT tags;
string[] sTags = //An array of strings;

PROPVARIANT[] propVarTags = new PROPVARIANT[sTags.Length];

for (int i = 0; i < sTags.Length; i++)
{
propVarTags[i] = new PROPVARIANT(sTags[i]);
}

tags = new CAPROPVARIANT();
tags.cElems = (uint)propVarTags.Length;
tags.pElems = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(PROPVARIANT)) * propVarTags.Length);

Marshal.StructureToPtr(propVarTags, tags.pElems, false);

But it doesn't like that last Marshal command because you can't directly marshal an array.  Am I on the right track here?  Thanks.

CAPROPVARIANT

</font></font>

Jun 5, 2009 at 7:16 PM

I've gotten a bit further with this, and this is how I'm setting up the IntPtr in the CAPROPVARIANT:

tags.pElems = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(PROPVARIANT)) * propVarTags.Length);

IntPtr ptrRunner = tags.pElems;
for (int i = 0; i < propVarTags.Length; i++)
{
Marshal.StructureToPtr(propVarTags[i], ptrRunner, false);
ptrRunner = (IntPtr)((int)ptrRunner + Marshal.SizeOf(typeof(PROPVARIANT)));
}

Using this method, the property gets crawled and the crawled property shows up as a MultiValued property, but the type of the crawled property is Binary Data and it shows as not included in the index.  So I'm a bit closer, but I still need to figure out how to make it show up as type Text instead of Binary Data.  Anyone have any ideas?

Jun 10, 2009 at 5:29 PM
Edited Jun 10, 2009 at 5:35 PM

I was finally able to get this working.  Here's what I did:

Added the following struct to IUrlAccessor:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct STRINGARRAYVARIANT
{
 public ULONG cElems;
 public IntPtr pElems; // Pointer to an array of lpwstrs
}

Added the following element to PROPVARIANT_UNION:
[FieldOffset(0)]
public STRINGARRAYVARIANT stringArrayPropVar; //VT_VECTOR | VT_LPWSTR

Added the following else statement to the big if/else in the PROPVARIANT constructor:
else if (objVal.GetType() == typeof(string[]))
{
 vt = (VARTYPE)(VarEnum.VT_VECTOR | VarEnum.VT_LPWSTR);
 string[] stringArray = (string[])objVal;
 union.stringArrayPropVar.cElems = (uint)stringArray.Length;
 union.stringArrayPropVar.pElems = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)) * stringArray.Length);

 IntPtr ptrRunner = union.stringArrayPropVar.pElems;
 for (int i = 0; i < stringArray.Length; i++)
 {
  IntPtr strPtr = Marshal.StringToCoTaskMemUni(stringArray[i]);
  Marshal.StructureToPtr(strPtr, ptrRunner, false);
  ptrRunner = (IntPtr)((int)ptrRunner + Marshal.SizeOf(typeof(IntPtr)));
 }
}

I can now add string[] properties in my content enumerator, and they are properly crawled by Sharepoint as multi-valued text properties.  Hope this helps someone else.