Exemplo n.º 1
0
			unsafe public IntPtr MarshalManagedToNative(object ManagedObj)
			{
				// CONSIDER: Checking for null, checking object type
				// DOCUMENT: This function is not called if the return is null!
				// DOCUMENT: A null pointer is immediately returned to Excel, resulting in #NUM!

				// CONSIDER: Managing memory differently
				// Here we allocate and clear when the next array is returned
				// we might also return XLOPER and have xlFree called back.

				// TODO: Remove duplication - due to fixed / pointer interaction

				Reset(true);

				int rows;
				int columns; // those in the returned array
                int rowBase;
                int columnBase;
				if (rank == 1)
				{
					object[] objects = (object[])ManagedObj;

					rows = 1;
                    rowBase = 0;
					columns = objects.Length;
                    columnBase = objects.GetLowerBound(0);
				}
				else if (rank == 2)
				{
					object[,] objects = (object[,])ManagedObj;

					rows = objects.GetLength(0);
                    rowBase = objects.GetLowerBound(0);
					columns = objects.GetLength(1);
                    columnBase = objects.GetLowerBound(0);
				}
				else
				{
					throw new InvalidOperationException("Damaged XlObjectArrayMarshaler rank");
				}

				int cbNativeStrings = 0;
				int numReferenceOpers = 0;
				int numReferences = 0;

				// Allocate native space
				int cbNative =  Marshal.SizeOf(typeof(XlOper12)) +				// OPER that is returned
								Marshal.SizeOf(typeof(XlOper12)) * (rows * columns);	// Array of OPER inside the result
				pNative = Marshal.AllocCoTaskMem(cbNative);

				// Set up returned OPER
				XlOper12* pOper = (XlOper12*)pNative;
                            // Excel chokes badly on empty arrays (e.g. crash in function wizard) - rather return the default erro value, #VALUE!
                if (rows * columns == 0)
                {
                    pOper->errValue = (ushort)IntegrationMarshalHelpers.ExcelError_ExcelErrorValue;
                    pOper->xlType = XlType12.XlTypeError;
                }
                else
                {

                    pOper->xlType = XlType12.XlTypeArray;
                    pOper->arrayValue.Rows = rows;
                    pOper->arrayValue.Columns = columns;
                    pOper->arrayValue.pOpers = ((XlOper12*)pNative + 1);
                }
                // This loop won't be entered in the empty-array case (rows * columns == 0)
                for (int i = 0; i < rows * columns; i++)
				{
					// Get the right object out of the array
					object obj;
					if (rank == 1)
					{
						obj = ((object[])ManagedObj)[columnBase + i];
					}
					else
					{
						int row = i / columns;
						int column = i % columns;
						obj = ((object[,])ManagedObj)[rowBase + row, columnBase + column];
					}

					// Get the right pOper
					pOper = (XlOper12*)pNative + i + 1;

					// Set up the oper from the object
					if (obj is double)
					{
						pOper->numValue = (double)obj;
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is string)
					{
						// We count all of the string lengths, 
						string str = (string)obj;
						cbNativeStrings += (Marshal.SizeOf(typeof(XlString12)) + ((Math.Min(str.Length, XlString12.MaxLength) - 1) /* 1 char already in XlString */) * 2 /* 2 bytes per char */);
						// mark the Oper as a string, and
						// later allocate memory and return to fix pointers
						pOper->xlType = XlType12.XlTypeString;
					}
					else if (obj is DateTime)
					{
						pOper->numValue = ((DateTime)obj).ToOADate();
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (IntegrationMarshalHelpers.IsExcelErrorObject(obj))
					{
						pOper->errValue = IntegrationMarshalHelpers.ExcelErrorGetValue(obj);
						pOper->xlType = XlType12.XlTypeError;
					}
					else if (IntegrationMarshalHelpers.IsExcelMissingObject(obj))
					{
						pOper->xlType = XlType12.XlTypeMissing;
					}
					else if (IntegrationMarshalHelpers.IsExcelEmptyObject(obj))
					{
						pOper->xlType = XlType12.XlTypeEmpty;
					}
                    else if (IntegrationMarshalHelpers.IsExcelAsyncHandleNativeObject(obj))
                    {
                        IntPtr handle = IntegrationMarshalHelpers.GetExcelAsyncHandleNativeHandle(obj);
                        pOper->bigData.hData = handle;
                        pOper->bigData.cbData = IntPtr.Size;
                        pOper->xlType = XlType12.XlTypeBigData;
                    }
					else if (obj is bool)
					{
						pOper->boolValue = (bool)obj ? 1 : 0;
						pOper->xlType = XlType12.XlTypeBoolean;
					}
					else if (obj is byte)
					{
						pOper->numValue = (double)((byte)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is sbyte)
					{
						pOper->numValue = (double)((sbyte)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is short)
					{
						pOper->numValue = (double)((short)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is ushort)
					{
						pOper->numValue = (double)((ushort)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is int)
					{
						pOper->numValue = (double)((int)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is uint)
					{
						pOper->numValue = (double)((uint)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is long)
					{
						pOper->numValue = (double)((long)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is ulong)
					{
						pOper->numValue = (double)((ulong)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is decimal)
					{
						pOper->numValue = (double)((decimal)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (obj is float)
					{
						pOper->numValue = (double)((float)obj);
						pOper->xlType = XlType12.XlTypeNumber;
					}
					else if (IntegrationMarshalHelpers.IsExcelReferenceObject(obj))
					{
						pOper->xlType = XlType12.XlTypeReference;
						// First we count all of these, 
						// later allocate memory and return to fix pointers
						numReferenceOpers++;
						numReferences += IntegrationMarshalHelpers.ExcelReferenceGetRectangleCount(obj); // ((ExcelReference)obj).InnerReferences.Count;
					}
					else if (obj is object[])
					{
						XlObjectArray12MarshalerImpl m = new XlObjectArray12MarshalerImpl(1);
						nestedInstances.Add(m);
						XlOper12* pNested = (XlOper12*)m.MarshalManagedToNative(obj);
                        if (pNested->xlType == XlType12.XlTypeArray)
                        {
                            pOper->xlType = XlType12.XlTypeArray;
                            pOper->arrayValue.Rows = pNested->arrayValue.Rows;
                            pOper->arrayValue.Columns = pNested->arrayValue.Columns;
                            pOper->arrayValue.pOpers = pNested->arrayValue.pOpers;
                        }
                        else
                        {
                            // This is the case where the array passed in has 0 length.
                            // We set to an error to at least have a valid XLOPER
                            pOper->xlType = XlType12.XlTypeError;
                            pOper->errValue = IntegrationMarshalHelpers.ExcelError_ExcelErrorValue;
                        }
					}
					else if (obj is object[,])
					{
						XlObjectArray12MarshalerImpl m = new XlObjectArray12MarshalerImpl(2);
						nestedInstances.Add(m);
						XlOper12* pNested = (XlOper12*)m.MarshalManagedToNative(obj);
                        if (pNested->xlType == XlType12.XlTypeArray)
                        {
						    pOper->xlType = XlType12.XlTypeArray;
						    pOper->arrayValue.Rows = pNested->arrayValue.Rows;
						    pOper->arrayValue.Columns = pNested->arrayValue.Columns;
						    pOper->arrayValue.pOpers = pNested->arrayValue.pOpers;
                        }
                        else
                        {
                            // This is the case where the array passed in has 0,0 length.
                            // We set to an error to at least have a valid XLOPER
                            pOper->xlType = XlType12.XlTypeError;
                            pOper->errValue = IntegrationMarshalHelpers.ExcelError_ExcelErrorValue;
                        }
					}
                    else if (obj is double[])
                    {
                        double[] doubles = (double[])obj;
                        object[] objects = new object[doubles.Length];
                        Array.Copy(doubles, objects, doubles.Length);

						XlObjectArray12MarshalerImpl m = new XlObjectArray12MarshalerImpl(1);
						nestedInstances.Add(m);
						XlOper12* pNested = (XlOper12*)m.MarshalManagedToNative(objects);
                        if (pNested->xlType == XlType12.XlTypeArray)
                        {
                            pOper->xlType = XlType12.XlTypeArray;
                            pOper->arrayValue.Rows = pNested->arrayValue.Rows;
                            pOper->arrayValue.Columns = pNested->arrayValue.Columns;
                            pOper->arrayValue.pOpers = pNested->arrayValue.pOpers;
                        }
                        else
                        {
                            // This is the case where the array passed in has 0 length.
                            // We set to an error to at least have a valid XLOPER
                            pOper->xlType = XlType12.XlTypeError;
                            pOper->errValue = IntegrationMarshalHelpers.ExcelError_ExcelErrorValue;
                        }
                    }
                    else if (obj is double[,])
                    {
                        double[,] doubles = (double[,])obj;
                        object[,] objects = new object[doubles.GetLength(0), doubles.GetLength(1)];
                        Array.Copy(doubles, objects, doubles.GetLength(0) * doubles.GetLength(1));

                        XlObjectArray12MarshalerImpl m = new XlObjectArray12MarshalerImpl(2);
                        nestedInstances.Add(m);
                        XlOper12* pNested = (XlOper12*)m.MarshalManagedToNative(objects);
                        if (pNested->xlType == XlType12.XlTypeArray)
                        {
                            pOper->xlType = XlType12.XlTypeArray;
                            pOper->arrayValue.Rows = pNested->arrayValue.Rows;
                            pOper->arrayValue.Columns = pNested->arrayValue.Columns;
                            pOper->arrayValue.pOpers = pNested->arrayValue.pOpers;
                        }
                        else
                        {
                            // This is the case where the array passed in has 0,0 length.
                            // We set to an error to at least have a valid XLOPER
                            pOper->xlType = XlType12.XlTypeError;
                            pOper->errValue = IntegrationMarshalHelpers.ExcelError_ExcelErrorValue;
                        }
                    }
                    else if (obj is Missing)
					{
						pOper->xlType = XlType12.XlTypeMissing;
					}
					else if (obj == null)
					{
						// DOCUMENT: I return Empty for nulls inside the Array, 
						// which is not consistent with what happens in other settings.
						// In particular not consistent with the results of the XlObjectMarshaler
						// (which is not called when a null is returned,
						// and interpreted as ExcelErrorNum in Excel)
						// This works well for xlSet though.
						pOper->xlType = XlType12.XlTypeEmpty;
					}
					else
					{
						// Default error return
						pOper->errValue = IntegrationMarshalHelpers.ExcelError_ExcelErrorValue;
						pOper->xlType = XlType12.XlTypeError;
					}
				} // end of first pass

				// Now handle strings
				if (cbNativeStrings > 0)
				{
					// Allocate room for all the strings
					pNativeStrings = Marshal.AllocCoTaskMem(cbNativeStrings);
					// Go through the Opers and set each string
					char* pCurrent = (char*)pNativeStrings;
					for (int i = 0; i < rows * columns; i++)
					{
						// Get the corresponding oper
						pOper = (XlOper12*)pNative + i + 1;
						if (pOper->xlType == XlType12.XlTypeString)
						{
							// Get the string from the managed array
							string str;
							if (rank == 1)
							{
								str = (string)((object[])ManagedObj)[i];
							}
							else
							{
								int row = i / columns;
								int column = i % columns;
								str = (string)((object[,])ManagedObj)[rowBase + row, columnBase + column];
							}

							XlString12* pdest = (XlString12*)pCurrent;
							pOper->pstrValue = pdest;
							ushort charCount = (ushort)Math.Min(str.Length, XlString12.MaxLength);
							fixed (char* psrc = str)
							{
								char* ps = psrc;
								char* pd = pdest->Data;
								for (int k = 0; k < charCount; k++)
								{
									*(pd++) = *(ps++);
								}
							}
							pdest->Length = charCount;
							// Increment pointer within allocated memory
							pCurrent += charCount + 1;
						}
					}
				}

				// Now handle references
				if (numReferenceOpers > 0)
				{
					// Allocate room for all the references
					int cbNativeReferences = numReferenceOpers * 4 /* sizeof ushort + packing to get to field offset */
											 + numReferences * Marshal.SizeOf(typeof(XlOper12.XlRectangle12));
					pNativeReferences = Marshal.AllocCoTaskMem(cbNativeReferences);
					IntPtr pCurrent = pNativeReferences;
					// Go through the Opers and set each reference
					int refOperIndex = 0;
					for (int i = 0; i < rows * columns && refOperIndex < numReferenceOpers; i++)
					{
						// Get the corresponding oper
						pOper = (XlOper12*)pNative + i + 1;
						if (pOper->xlType == XlType12.XlTypeReference)
						{
							// Get the reference from the managed array
							object /*ExcelReference*/ r;
							if (rank == 1)
							{
								r = /*(ExcelReference)*/((object[])ManagedObj)[i];
							}
							else
							{
								int row = i / columns;
								int column = i % columns;
								r = /*(ExcelReference)*/((object[,])ManagedObj)[rowBase + row, columnBase + column];
							}

							int refCount = IntegrationMarshalHelpers.ExcelReferenceGetRectangleCount(r); // r.InnerReferences.Count
							int numBytes = 4 /* sizeof ushort + packing to get to field offset */
										   + refCount * Marshal.SizeOf(typeof(XlOper12.XlRectangle12));

							IntegrationMarshalHelpers.SetExcelReference12(pOper, (XlOper12.XlMultiRef12*)pCurrent, r);

                            // Unchecked keyword here is redundant (it's the default for C#), 
                            // but makes clear that we rely on the overflow.
                            // Also - numBytes must be int and not long, else we get numeric promotion and a mess again!
                            pCurrent = IntPtr.Size == 4 ? 
                                new IntPtr(unchecked(pCurrent.ToInt32() + (int)numBytes)) : 
                                new IntPtr(unchecked(pCurrent.ToInt64() + numBytes));
							refOperIndex++;
						}
					}
				}

				if (!isExcel12v)
				{
					// For big allocations, ensure that Excel allows us to free the memory
					if (rows * columns * 16 + cbNativeStrings + numReferences * 16 > 65535)
						pOper->xlType |= XlType12.XlBitDLLFree;

					// We are done
					return pNative;
				}
				else
				{
					// For the Excel12v call, we need to return an array
					// which will contain the pointers to the Opers.
					int cbOperPointers = columns * Marshal.SizeOf(typeof(XlOper12*));
					pOperPointers = Marshal.AllocCoTaskMem(cbOperPointers);
					XlOper12** pOpers = (XlOper12**)pOperPointers;
					for (int i = 0; i < columns; i++)
					{
						pOpers[i] = (XlOper12*)pNative + i + 1;
					}
					return pOperPointers;
				}
			}
Exemplo n.º 2
0
			public static XlObjectArray12MarshalerImpl GetInstance(int rank)
			{
				// rank must be 1 or 2
				if (rank == 1)
				{
					if (instance1 == null)
						instance1 = new XlObjectArray12MarshalerImpl(1);
					return instance1;
				}
				else if (rank == 2)
				{
					if (instance2 == null)
						instance2 = new XlObjectArray12MarshalerImpl(2);
					return instance2;
				}
				throw new ArgumentException("Invalid instance indentifiers for XlObjectArrayMarshalerImpl");
			}