3,245
社区成员
发帖
与我相关
我的任务
分享
/// <include file='doc\COM2TypeInfoProcessor.uex' path='docs/doc[@for="Com2TypeInfoProcessor.ProcessTypeInfoEnum"]/*' />
/// <devdoc>
/// This converts a type info that describes a IDL defined enum
/// into one we can use
/// </devdoc>
private static Type ProcessTypeInfoEnum(UnsafeNativeMethods.ITypeInfo enumTypeInfo, StructCache structCache) {
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum entered");
if (enumTypeInfo == null) {
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum got a NULL enumTypeInfo");
return null;
}
try {
IntPtr pTypeAttr = IntPtr.Zero;
int hr = enumTypeInfo.GetTypeAttr(ref pTypeAttr);
if (!NativeMethods.Succeeded(hr) || pTypeAttr == IntPtr.Zero) {
throw new ExternalException(SR.GetString(SR.TYPEINFOPROCESSORGetTypeAttrFailed, hr), hr);
}
NativeMethods.tagTYPEATTR typeAttr = (NativeMethods.tagTYPEATTR)structCache.GetStruct(typeof(NativeMethods.tagTYPEATTR));//(tagTYPEATTR)Marshal.PtrToStructure(pTypeAttr, typeof(tagTYPEATTR));
UnsafeNativeMethods.PtrToStructure(pTypeAttr, typeAttr);
if (pTypeAttr == IntPtr.Zero) {
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum: failed to get a typeAttr");
return null;
}
try {
int nItems = typeAttr.cVars;
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum: processing " + nItems.ToString(CultureInfo.InvariantCulture) + " variables");
ArrayList strs = new ArrayList();
ArrayList vars = new ArrayList();
NativeMethods.tagVARDESC varDesc = (NativeMethods.tagVARDESC)structCache.GetStruct(typeof(NativeMethods.tagVARDESC));
Object varValue = null;
string enumName = null;
string name = null;
string helpstr = null;
enumTypeInfo.GetDocumentation(NativeMethods.MEMBERID_NIL, ref enumName, ref helpstr, null, null);
// For each item in the enum type info,
// we just need it's name and value, and helpstring if it's there.
//
for (int i = 0; i < nItems; i++) {
IntPtr pVarDesc = IntPtr.Zero;
hr = enumTypeInfo.GetVarDesc(i, ref pVarDesc);
if (!NativeMethods.Succeeded(hr) || pVarDesc == IntPtr.Zero) {
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, String.Format(CultureInfo.CurrentCulture, "ProcessTypeInfoEnum: ignoring item 0x{0:X} because ITypeInfo::GetVarDesc returned hr=0x{1:X} or NULL", hr));
continue;
}
try {
//varDesc = (tagVARDESC)Marshal.PtrToStructure(pVarDesc, typeof(tagVARDESC));
UnsafeNativeMethods.PtrToStructure(pVarDesc, varDesc);
if (varDesc == null ||
varDesc.varkind != (int)NativeMethods.tagVARKIND.VAR_CONST ||
varDesc.unionMember == IntPtr.Zero) {
continue;
}
name = helpstr = null;
varValue = null;
// get the name and the helpstring
hr = enumTypeInfo.GetDocumentation(varDesc.memid, ref name, ref helpstr, null, null);
if (!NativeMethods.Succeeded(hr)) {
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, String.Format(CultureInfo.CurrentCulture, "ProcessTypeInfoEnum: ignoring item 0x{0:X} because ITypeInfo::GetDocumentation returned hr=0x{1:X} or NULL", hr));
continue;
}
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum got name=" + (name == null ? "(null)" : name) + ", helpstring=" + (helpstr == null ? "(null)" : helpstr));
// get the value
try {
//varValue = (VARIANT)Marshal.PtrToStructure(varDesc.unionMember, typeof(VARIANT));
varValue = Marshal.GetObjectForNativeVariant(varDesc.unionMember);
}
catch (Exception ex) {
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum: PtrtoStructFailed " + ex.GetType().Name + "," + ex.Message);
}
/*if (varValue == null) {
Debug.Fail("Couldn't get VARIANT from VARIANTDESC");
continue;
}*/
//variant v = varValue.ToVariant();
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum: adding variable value=" + Convert.ToString(varValue, CultureInfo.InvariantCulture));
vars.Add(varValue);
// if we have a helpstring, use it, otherwise use name
string nameString;
if (helpstr != null) {
nameString = helpstr;
}
else {
Debug.Assert(name != null, "No name for VARDESC member, but GetDocumentation returned S_OK!");
nameString = name;
}
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum: adding name value=" + nameString);
strs.Add(nameString);
}
finally {
if (pVarDesc != IntPtr.Zero) {
enumTypeInfo.ReleaseVarDesc(pVarDesc);
}
}
}
structCache.ReleaseStruct(varDesc);
Debug.WriteLineIf(DbgTypeInfoProcessorSwitch.TraceVerbose, "ProcessTypeInfoEnum: returning enum with " + strs.Count.ToString(CultureInfo.InvariantCulture) + " items");
// just build our enumerator
if (strs.Count > 0) {
// get the IUnknown value of the ITypeInfo
IntPtr pTypeInfoUnk = Marshal.GetIUnknownForObject(enumTypeInfo);
try {
enumName = pTypeInfoUnk.ToString() + "_" + enumName;
if (builtEnums == null) {
builtEnums = new Hashtable();
}
else if (builtEnums.ContainsKey(enumName)) {
return (Type)builtEnums[enumName];
}
Type enumType = typeof(int);
if (vars.Count > 0 && vars[0] != null) {
enumType = vars[0].GetType();
}
EnumBuilder enumBuilder = ModuleBuilder.DefineEnum(enumName, TypeAttributes.Public, enumType);
for (int i = 0; i < strs.Count; i++) {
enumBuilder.DefineLiteral((string)strs[i], vars[i]);
}
Type t = enumBuilder.CreateType();
builtEnums[enumName] = t;
return t;
}
finally {
if (pTypeInfoUnk != IntPtr.Zero) {
Marshal.Release(pTypeInfoUnk);
}
}
}
}
finally {
enumTypeInfo.ReleaseTypeAttr(pTypeAttr);
structCache.ReleaseStruct(typeAttr);
}
}
catch {
}
return null;
}