// Leaves the link in the same state as when it started. The out param leafExprType will be Function if // the array is empty in the first bottom-level subarray: {{}, {1,2,3}}. internal static int determineIncomingArrayDepth(IMathLink ml /*, out ExpressionType leafExprType*/) { int actualDepth = 0; ILinkMark mark = ml.CreateMark(); // // Initial value just to satisfy compiler; if depth of 0 is returned, then the leafExprType will be ignored by callers. // leafExprType = ExpressionType.Function; try { int len; string head = ml.GetFunction(out len); actualDepth = 1; while (len > 0) { ExpressionType leafExprType = ml.GetNextExpressionType(); if (leafExprType == ExpressionType.Function) { head = ml.GetFunction(out len); actualDepth++; } else { break; } } // // If the last sublist is empty (len == 0), we will walk off the end of the above loop with // // leafExprType == ExpressionType.Function, which is what we want. } catch (MathLinkException) { // Do nothing but clear it. Returning 0 is enough. ml.ClearError(); } finally { ml.SeekMark(mark); ml.DestroyMark(mark); } return(actualDepth); }
/// <summary> /// Reads a Complex number from the link and returns an object of the class set as the /// <see cref="IMathLink.ComplexType">ComplexType</see>. /// </summary> /// public object GetComplex(IMathLink ml) { double re = 0.0; double im = 0.0; if (ComplexType == null) { throw new MathLinkException(MathLinkException.MLE_NO_COMPLEX); } ExpressionType type = ml.GetNextExpressionType(); switch (type) { case ExpressionType.Integer: case ExpressionType.Real: { re = ml.GetDouble(); break; } case ExpressionType.Complex: { ml.CheckFunctionWithArgCount("Complex", 2); re = ml.GetDouble(); im = ml.GetDouble(); break; } default: throw new MathLinkException(MathLinkException.MLE_BAD_COMPLEX); } return(constructComplex(re, im)); }
// Analogous to the C function of the same name created by mprep for C installable MathLink programs. // Note that the built-in DefineExternal function in Mathematica is not abort-safe, so .NET/Link // uses its own version, netlinkDefineExternal. private static void definePattern(IMathLink ml, string patt, string args, int index) { ml.PutFunction(KernelLinkImpl.PACKAGE_INTERNAL_CONTEXT + "netlinkDefineExternal", 3); ml.Put(patt); ml.Put(args); ml.Put(index); }
// Gives default types to read expressions as. Used when two conditions are met: 1) we have no .NET type info // about what we are trying to create, and (2) we have no argType info from M because this is a member of an array // (argType tells us merely that it is an array). Will return typeof(Expr) for anything that doesn't map to a .NET type. private static Type netTypeFromExpressionType(ExpressionType exprType, IMathLink ml) { switch (exprType) { case ExpressionType.Integer: return(typeof(int)); case ExpressionType.Real: return(typeof(double)); case ExpressionType.String: return(typeof(string)); case ExpressionType.Boolean: return(typeof(bool)); case ExpressionType.Symbol: case ExpressionType.Function: return(typeof(Expr)); case ExpressionType.Object: return(typeof(object)); case ExpressionType.Complex: return(ml.ComplexType != null ? ml.ComplexType : typeof(Expr)); default: // Protection in case we ever add a new value to the enum. System.Diagnostics.Debug.Fail("Unhandled ExpressionType enum value in Utils.netTypeFromExpressionType"); return(null); } }
public static void WriteEvalToTypesetExpression(IMathLink ml, object obj, int pageWidth, string graphicsFmt, bool useStdForm) { ml.PutFunction("EvaluatePacket", 1); int numArgs = 2 + (useStdForm ? 0 : 1) + (pageWidth > 0 ? 1 : 0); ml.PutFunction("EvaluateToTypeset", numArgs); ml.Put(obj); if (!useStdForm) { ml.PutSymbol("TraditionalForm"); } if (pageWidth > 0) { ml.Put(pageWidth); } ml.Put(graphicsFmt); ml.EndPacket(); }
internal static void discardNext(IKernelLink ml) { switch (ml.GetNextExpressionType()) { case ExpressionType.Integer: ml.GetInteger(); break; case ExpressionType.Real: ml.GetDouble(); break; case ExpressionType.Boolean: case ExpressionType.Symbol: ml.GetSymbol(); break; case ExpressionType.String: ml.GetString(); break; case ExpressionType.Object: ml.GetObject(); break; // We would get an exception if we called GetComplex() and no complex class was set. case ExpressionType.Complex: case ExpressionType.Function: { IMathLink loop = MathLinkFactory.CreateLoopbackLink(); try { loop.TransferExpression(ml); } finally { loop.Close(); } break; } default: System.Diagnostics.Debug.Fail("Unhandled ExpressionType enum value in Utils.discardNext()."); break; } }
public static void WriteEvalToImageExpression(IMathLink ml, object obj, int width, int height, string graphicsFmt, int dpi, bool useFE) { ml.PutFunction("EvaluatePacket", 1); int numArgs = 2 + (useFE ? 1 : 0) + (dpi > 0 ? 1 : 0) + (width > 0 || height > 0 ? 1 : 0); ml.PutFunction("EvaluateToImage", numArgs); ml.Put(obj); if (useFE) { ml.Put(true); } ml.Put(graphicsFmt); if (dpi > 0) { ml.PutFunction("Rule", 2); ml.PutSymbol("ImageResolution"); ml.Put(dpi); } if (width > 0 || height > 0) { ml.PutFunction("Rule", 2); ml.PutSymbol("ImageSize"); ml.PutFunction("List", 2); if (width > 0) { ml.Put(width); } else { ml.PutSymbol("Automatic"); } if (height > 0) { ml.Put(height); } else { ml.PutSymbol("Automatic"); } } ml.EndPacket(); }
/// <summary> /// Writes an instance of the class specified as the <see cref="IMathLink.ComplexType">ComplexType</see> on the link. /// </summary> /// public void PutComplex(IMathLink ml, object obj) { if (ComplexType == null) { throw new MathLinkException(MathLinkException.MLE_NO_COMPLEX); } double re = 0; double im = 0; try { re = getRealPart(obj); im = getImaginaryPart(obj); } catch (Exception e) { // Shouldn't get here. ml.PutSymbol("$Failed"); throw e; } ml.PutFunction("Complex", 2); // Use Put(double), because it has code to handle NaN, infinity. ml.Put(re); ml.Put(im); }
// These next methods are called by implementors of the KernelLink "evaluateTo" methods. It is useful to separate the // code to create the appropriate expression to send (which is what these methods do) and the code that runs the // reading loop. In these methods, obj must be a string or Expr. // This is ready to accommodate an evaluateToMathML() function, but I have not added such a function to KernelLink yet. public static void WriteEvalToStringExpression(IMathLink ml, Object obj, int pageWidth, string format) { ml.PutFunction("EvaluatePacket", 1); ml.PutFunction("ToString", 3); if (obj is string) { ml.PutFunction("ToExpression", 1); } ml.Put(obj); ml.PutFunction("Rule", 2); ml.PutSymbol("FormatType"); ml.PutSymbol(format); ml.PutFunction("Rule", 2); ml.PutSymbol("PageWidth"); if (pageWidth > 0) { ml.Put(pageWidth); } else { ml.PutSymbol("Infinity"); } ml.EndPacket(); }
public override void TransferExpression(IMathLink source) { impl.TransferExpression(source); }
public static Expr CreateFromLink(IMathLink ml) { return(new Expr(Wolfram.NETLink.Expr.CreateFromLink(ml))); }
public void Put(IMathLink ml) { expr.Put(ml); }
public abstract void TransferExpression(IMathLink source);
public static Wolfram.NETLink.IKernelLink CreateKernelLink(IMathLink ml) { RegisterMathLinkFactory(); return(Wolfram.NETLink.MathLinkFactory.CreateKernelLink(ml)); }
/// <summary> /// Analogous to the MLInstall function in mprep-generated C programs. /// </summary> /// <param name="ml"></param> /// <returns>Whether it succeeded or not.</returns> /// public static bool install(IMathLink ml) { // Adding nXX functions here requires also adding the symbols to the NETLink`NET.m file. try { ml.Connect(); ml.Put("Begin[\"" + KernelLinkImpl.PACKAGE_INTERNAL_CONTEXT + "\"]"); definePattern(ml, "nCall[typeName_String, obj_Symbol, callType_Integer, isByVal_, memberName_String, argCount_Integer, typesAndArgs___]", "{typeName, obj, callType, isByVal, memberName, argCount, typesAndArgs}", CALL); definePattern(ml, "nLoadType1[type_String, assemblyName_]", "{type, assemblyName}", LOADTYPE1); definePattern(ml, "nLoadType2[type_String, assemblyObj_]", "{type, assemblyObj}", LOADTYPE2); definePattern(ml, "nLoadExistingType[typeObject_?NETObjectQ]", "{typeObject}", LOADEXISTINGTYPE); definePattern(ml, "nLoadAssembly[assemblyNameOrPath_String, suppressErrors_]", "{assemblyNameOrPath, suppressErrors}", LOADASSEMBLY); definePattern(ml, "nLoadAssemblyFromDir[assemblyName_String, dir_String]", "{assemblyName, dir}", LOADASSEMBLYFROMDIR); definePattern(ml, "nGetAssemblyObject[asmName_String]", "{asmName}", GETASSEMBLYOBJ); definePattern(ml, "nGetTypeObject[aqTypeName_String]", "{aqTypeName}", GETTYPEOBJ); definePattern(ml, "nReleaseObject[instances:{__Symbol}]", "{instances}", RELEASEOBJECT); definePattern(ml, "nMakeObject[typeName_String, argType_Integer, val_]", "{typeName, argType, val}", MAKEOBJECT); definePattern(ml, "nVal[obj_?NETObjectQ]", "{obj}", VAL); definePattern(ml, "nReflectType[typeName_String]", "{typeName}", REFLECTTYPE); definePattern(ml, "nReflectAsm[asmName_String]", "{asmName}", REFLECTASM); definePattern(ml, "nSetComplex[typeName_String]", "{typeName}", SETCOMPLEX); definePattern(ml, "nSameQ[obj1_?NETObjectQ, obj2_?NETObjectQ]", "{obj1, obj2}", SAMEQ); definePattern(ml, "nInstanceOf[obj_?NETObjectQ, aqTypeName_String]", "{obj, aqTypeName}", INSTANCEOF); definePattern(ml, "nCast[obj_?NETObjectQ, aqTypeName_String]", "{obj, aqTypeName}", CAST); definePattern(ml, "nPeekTypes[]", "{}", PEEKTYPES); definePattern(ml, "nPeekObjects[]", "{}", PEEKOBJECTS); definePattern(ml, "nPeekAssemblies[]", "{}", PEEKASSEMBLIES); definePattern(ml, "nCreateDelegate[typeName_String, mFunc_String, sendTheseArgs_Integer, callsUnshare:(True | False), wrapInNETBlock:(True | False)]", "{typeName, mFunc, sendTheseArgs, callsUnshare, wrapInNETBlock}", CREATEDELEGATE); definePattern(ml, "nDefineDelegate[name_String, retTypeName_String, paramTypeNames_List]", "{name, retTypeName, paramTypeNames}", DEFINEDELEGATE); definePattern(ml, "nDlgTypeName[eventObject_?NETObjectQ, aqTypeName_String, evtName_String]", "{eventObject, aqTypeName, evtName}", DLGTYPENAME); definePattern(ml, "nAddHandler[eventObject_?NETObjectQ, aqTypeName_String, evtName_String, delegate_?NETObjectQ]", "{eventObject, aqTypeName, evtName, delegate}", ADDHANDLER); definePattern(ml, "nRemoveHandler[eventObject_?NETObjectQ, aqTypeName_String, evtName_String, delegate_?NETObjectQ]", "{eventObject, aqTypeName, evtName, delegate}", REMOVEHANDLER); definePattern(ml, "nCreateDLL1[funcName_String, dllName_String, callConv_String, retTypeName_String, argTypeNames_, areOutParams_, strFormat_String]", "{funcName, dllName, callConv, retTypeName, argTypeNames, areOutParams, strFormat}", CREATEDLL1); definePattern(ml, "nCreateDLL2[decl_String, refAsms_, lang_String]", "{decl, refAsms, lang}", CREATEDLL2); definePattern(ml, "nModal[modal:(True | False), formToActivate_?NETObjectQ]", "{modal, formToActivate}", MODAL); definePattern(ml, "nShow[formToActivate_?NETObjectQ]", "{formToActivate}", SHOW); definePattern(ml, "nShareKernel[sharing:(True | False)]", "{sharing}", SHAREKERNEL); definePattern(ml, "nAllowUIComputations[allow:(True | False)]", "{allow}", ALLOWUICOMPS); definePattern(ml, "nUILink[name_String, prot_String]", "{name, prot}", UILINK); definePattern(ml, "nIsCOMProp[obj_?NETObjectQ, memberName_String]", "{obj, memberName}", ISCOMPROP); definePattern(ml, "nCreateCOM[clsIDOrProgID_String]", "{clsIDOrProgID}", CREATECOM); definePattern(ml, "nGetActiveCOM[clsIDOrProgID_String]", "{clsIDOrProgID}", GETACTIVECOM); definePattern(ml, "nReleaseCOM[obj_?NETObjectQ]", "{obj}", RELEASECOM); definePattern(ml, "nLoadTypeLibrary[tlbPath_String, safeArrayAsArray_, assemblyFile_String]", "{tlbPath, safeArrayAsArray, assemblyFile}", LOADTYPELIBRARY); definePattern(ml, "nGetException[]", "{}", GETEXCEPTION); definePattern(ml, "nConnectToFEServer[linkName_String]", "{linkName}", CONNECTTOFE); definePattern(ml, "nDisconnectToFEServer[]", "{}", DISCONNECTTOFE); // For speed testing: definePattern(ml, "noop[]", "{}", NOOP); definePattern(ml, "noop2[argc_Integer, args___]", "{argc, args}", NOOP2); // Here we define the argTypeToInteger function by sending // MapThread[(argTypeToInteger[#1] = #2)&, {ToExpression /@ argTypePatterns, {... ARGTYPE_ constants ...}}] ml.PutFunction("MapThread", 2); ml.PutFunction("Function", 1); ml.PutFunction("Set", 2); ml.PutFunction("argTypeToInteger", 1); ml.PutFunction("Slot", 1); ml.Put(1); ml.PutFunction("Slot", 1); ml.Put(2); ml.PutFunction("List", 2); ml.PutFunction("Map", 2); ml.PutSymbol("ToExpression"); ml.Put(argTypePatterns); ml.PutFunction("List", 13); ml.Put(ARGTYPE_INTEGER); ml.Put(ARGTYPE_REAL); ml.Put(ARGTYPE_STRING); ml.Put(ARGTYPE_BOOLEAN); ml.Put(ARGTYPE_NULL); ml.Put(ARGTYPE_MISSING); ml.Put(ARGTYPE_OBJECTREF); ml.Put(ARGTYPE_VECTOR); ml.Put(ARGTYPE_MATRIX); ml.Put(ARGTYPE_TENSOR3); ml.Put(ARGTYPE_LIST); ml.Put(ARGTYPE_COMPLEX); ml.Put(ARGTYPE_OTHER); ml.Put("End[]"); ml.PutSymbol("End"); ml.Flush(); return(true); } catch (MathLinkException) { return(false); } }
/// <summary> /// Creates an IKernelLink from an <see cref="IMathLink"/>. /// </summary> /// <remarks> /// You can think of IKernelLink as a "decorator" for IMathLink. It builds on top of IMathLink by providing /// extra capabilities. If you have an IMathLink object, you can use this method to construct an /// IKernelLink implementation out of it. /// <para> /// Very few programmers will ever use this method. It is intended mainly for developers who are creating their /// own IKernelLink implementations. They only need to write the functionality of an IMathLink, and then they /// can use this method to get the extra features of an IKernelLink for free. /// </para> /// </remarks> /// <param name="ml">The IMathLink to "wrap".</param> /// <returns>The created link.</returns> /// <exception cref="MathLinkException">If the opening of the link fails.</exception> /// public static IKernelLink CreateKernelLink(IMathLink ml) { return(new WrappedKernelLink(ml)); }
internal NativeMark(IMathLink ml, IntPtr mark) { this.mark = mark; this.ml = ml; }
public WrappedKernelLink(IMathLink ml) { SetMathLink(ml); MessageArrived += new MessageHandler(interruptDetector); }
// Can read any kind of array, except for jagged arrays that are multidimensional at the beginning, like [][,] // (jagged at start like [,][] or [,...][][] is OK, but only if we know the type, not for an Array slot). Recall // that mixed array types are read backwards, so [][,] is a 2-deep array of element type [] (i.e., it is multidimensional // at the start, not the end). One more limitation: For an Array argument slot, if the incoming array is 3-deep or deeper, // it must be rectangular, not jagged. // We know the incoming expression has head List. internal static Array readArbitraryArray(IMathLink ml, Type t) { int len; if (t == typeof(Array)) { ExpressionType leafExprType; Type leafType; // For the Array type, we have no clue about how the leaf elements will be read. Thus we need to peek into // the incoming data to decide what type it is. int depth = determineIncomingArrayDepth(ml); ILinkMark mark = ml.CreateMark(); ILoopbackLink loop = null; try { if (depth == 1) { len = ml.CheckFunction("List"); if (len == 0) { throw new MathLinkException(MathLinkException.MLE_EMPTY_ARRAY); } leafExprType = ml.GetNextExpressionType(); ml.SeekMark(mark); leafType = netTypeFromExpressionType(leafExprType, ml); // Fail if data could only be read as Expr. This means that we cannot pass a list of arbitrary expressions // to an arg slot typed as Array. It would have to be typed as Expr[]. We make this choice to provide // more meaningful error reporting for the cases where the array has bogus data in it. We assume that // this convenience outweighs the very rare cases where a programmer would want to pass an array of exprs // for an Array slot (they could always create the array separately and pass it as an object reference). if (leafType == typeof(Expr)) { if (leafExprType == ExpressionType.Complex) { throw new MathLinkException(MathLinkException.MLE_NO_COMPLEX); } else { throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY); } } return((Array)ml.GetArray(leafType, 1)); } else if (depth == 2) { // The loopback link is just a utility for quickly reading expressions off the link (via TransferExpression). // Nothing is ever read back off the loopback link. loop = MathLinkFactory.CreateLoopbackLink(); // Determine if the array is rectangular or jagged. len = ml.CheckFunction("List"); bool isJagged = false; bool foundLeafType = false; // This next assignment is strictly for the compiler. The value will never be used // unless it is set to an actual value below. We have an existing function that will get // the leafExprType of the incoming array (getLeafExprType()), but we also need to check if the array // is jagged here, so we will do both tasks at once and save a little time. leafExprType = ExpressionType.Integer; int lenAtLevel2 = ml.CheckFunction("List"); if (lenAtLevel2 > 0) { leafExprType = ml.GetNextExpressionType(); foundLeafType = true; } // peel off all the elements in the first sublist. for (int j = 0; j < lenAtLevel2; j++) { loop.TransferExpression(ml); } // For each remaining sublist, check its length and peel off its members. At this point, though, we // cannot be guaranteed that all elements are lists (or, at least, guaranteed that it is an error // if they are not). They could be Null if the array is jagged: {{1, 2}, Null}. for (int i = 1; i < len; i++) { ExpressionType nextExprType = ml.GetNextExpressionType(); if (nextExprType == ExpressionType.Object) { isJagged = true; // OK to have null as an element in a jagged array. if (ml.GetObject() != null) { throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_SHAPE); } } else if (nextExprType == ExpressionType.Function) { int thisLength = ml.CheckFunction("List"); if (!foundLeafType && thisLength > 0) { leafExprType = ml.GetNextExpressionType(); foundLeafType = true; } if (thisLength != lenAtLevel2) { isJagged = true; break; } else { for (int j = 0; j < thisLength; j++) { loop.TransferExpression(ml); } } } else { throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_DEPTH); } } // If the array is empty we cannot create a .NET array for it, as there is no type info for the array we are creating. if (!foundLeafType) { throw new MathLinkException(MathLinkException.MLE_EMPTY_ARRAY); } leafType = netTypeFromExpressionType(leafExprType, ml); ml.SeekMark(mark); if (isJagged) { ml.CheckFunction("List"); Array result = Array.CreateInstance(Array.CreateInstance(leafType, 0).GetType(), len); for (int i = 0; i < len; i++) { // Have to check if elements are lists or Null. ExpressionType nextExprType = ml.GetNextExpressionType(); if (nextExprType == ExpressionType.Function) { result.SetValue(ml.GetArray(leafType, 1), i); } else { string sym = ml.GetSymbol(); if (sym != "Null") { throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_SHAPE); } result.SetValue(null, i); } } return(result); } else { return(ml.GetArray(leafType, 2)); } } else { // For an Array argument slot, we only support passing >2-deep rectangular arrays, not jagged. for (int i = 0; i < depth; i++) { ml.CheckFunction("List"); } leafExprType = ml.GetNextExpressionType(); leafType = netTypeFromExpressionType(leafExprType, ml); ml.SeekMark(mark); return(ml.GetArray(leafType, depth)); } } finally { if (loop != null) { loop.Close(); } ml.DestroyMark(mark); } } else { // We have the actual array shape encoded in the type. Either [], [,..], or array-of-arrays: [][].... int arrayRank = t.GetArrayRank(); Type elementType = t.GetElementType(); if (elementType.IsArray) { if (arrayRank > 1) { // Don't support multidimensional array at start of jagged array: [][,]. Recall that mixed array types // are read backwards, so [][,] is a 2-deep array of element type []. throw new MathLinkException(MathLinkException.MLE_MULTIDIM_ARRAY_OF_ARRAY); } len = ml.CheckFunction("List"); Array result = Array.CreateInstance(elementType, len); for (int i = 0; i < len; i++) { ExpressionType nextExprType = ml.GetNextExpressionType(); if (nextExprType == ExpressionType.Function) { result.SetValue(readArbitraryArray(ml, elementType), i); } else { string sym = ml.GetSymbol(); if (sym != "Null") { throw new MathLinkException(MathLinkException.MLE_BAD_ARRAY_SHAPE); } result.SetValue(null, i); } } return(result); } else if (elementType == typeof(Array)) { // Don't support Array[]. throw new MathLinkException(MathLinkException.MLE_ARRAY_OF_ARRAYCLASS); } else { return(ml.GetArray(elementType, arrayRank)); } } }
public void SetMathLink(IMathLink ml) { impl = ml; }
public virtual void HandlePacket(PacketType pkt) { switch (pkt) { // If you ever change the default behavior on the 4 "answer" packets to read off the link, // you'll need to add a seekMark in NativeKernelLink.waitForAnswer... case PacketType.Return: case PacketType.InputName: case PacketType.ReturnText: case PacketType.ReturnExpression: case PacketType.Menu: case PacketType.Message: break; // From here on, the cases do actual work. case PacketType.Call: { ExpressionType type = GetExpressionType(); if (type == ExpressionType.Integer) { // A normal CallPacket representing a call to .NET via nCall. callPktHandler.handleCallPacket(this); } else { // A CallPacket destined for the FE via MathLink`CallFrontEnd[] and routed through // .NET due to ShareFrontEnd[]. This would only be in a 5.1 FE, as earlier // versions do not use CallPacket and later versions would use the FE's Service Link. IMathLink feServerLink = callPktHandler.FEServerLink; if (feServerLink != null) { feServerLink.PutFunction("CallPacket", 1); feServerLink.TransferExpression(this); // FE will always reply to a CallPacket. Note that it is technically possible for // the FE to send back an EvaluatePacket, which means that we really need to run a // little loop here, not just write the result back to the kernel. But this branch // is only for a 5.1 FE, and I don't think that the 5.1 FE ever does that. TransferExpression(feServerLink); } } break; } case PacketType.Display: case PacketType.DisplayEnd: { IMathLink feServerLink = callPktHandler.FEServerLink; if (feServerLink != null) { if (accumulatingPS == null) { accumulatingPS = new System.Text.StringBuilder(34000); // 34K is large enough to hold an entire packet } accumulatingPS.Append(GetString()); if (pkt == PacketType.DisplayEnd) { // XXXPacket[stuff] ---> Cell[GraphicsData["PostScript", stuff], "Graphics"] feServerLink.PutFunction("FrontEnd`FrontEndExecute", 1); feServerLink.PutFunction("FrontEnd`NotebookWrite", 2); feServerLink.PutFunction("FrontEnd`SelectedNotebook", 0); feServerLink.PutFunction("Cell", 2); feServerLink.PutFunction("GraphicsData", 2); feServerLink.Put("PostScript"); feServerLink.Put(accumulatingPS.ToString()); feServerLink.Put("Graphics"); feServerLink.Flush(); accumulatingPS = null; } } else { Debug.WriteLine("Got PacketType.Display in handlePacket, but no FE link"); } break; } case PacketType.Input: case PacketType.InputString: { IMathLink feServerLink = callPktHandler.FEServerLink; if (feServerLink != null) { feServerLink.PutFunction(pkt == PacketType.InputString ? "InputStringPacket" : "InputPacket", 1); feServerLink.Put(GetString()); feServerLink.Flush(); NewPacket(); Put(feServerLink.GetString()); Flush(); } break; } case PacketType.Text: case PacketType.Expression: { // Print output, or message text. IMathLink feServerLink = callPktHandler.FEServerLink; if (feServerLink != null) { // XXXPacket[stuff] ---> Cell[stuff, "Print"] feServerLink.PutFunction("FrontEnd`FrontEndExecute", 1); feServerLink.PutFunction("FrontEnd`NotebookWrite", 2); feServerLink.PutFunction("FrontEnd`SelectedNotebook", 0); feServerLink.PutFunction("Cell", 2); feServerLink.TransferExpression(this); feServerLink.Put((lastPktWasMsg) ? "Message" : "Print"); feServerLink.Flush(); } else { // For one type of PacketType.Expression, no part of it has been read yet. Thus we must "open" the // packet so that later calls to newPacket() throw it away. if (pkt == PacketType.Expression) { int ignore; GetFunction(out ignore); } } break; } case PacketType.FrontEnd: { // This case is different from the others. At the point of entry, the link is at the point // _before_ the "packet" has been read. As a result, we must at least open the packet. // Note that PacketType.FrontEnd is really just a fall-through for unrecognized packets. We don't have any // checks that it is truly intended for the FE. IMathLink feServerLink = callPktHandler.FEServerLink; if (feServerLink != null) { ILinkMark mark = CreateMark(); try { // Wrap FrontEndExecute around it if not already there. int ignore; string wrapper = GetFunction(out ignore); if (wrapper != "FrontEnd`FrontEndExecute") { feServerLink.PutFunction("FrontEnd`FrontEndExecute", 1); } } finally { SeekMark(mark); DestroyMark(mark); } feServerLink.TransferExpression(this); feServerLink.Flush(); // Wait until either the fe is ready (because what we just sent causes a return value) // or kernel is ready (the computation is continuing because the kernel is not waiting // for a return value). do { System.Threading.Thread.Sleep(50); } while (!feServerLink.Ready && !Ready); if (feServerLink.Ready) { // fe link has something to return to kernel from last PacketType.FrontEnd we sent it. TransferExpression(feServerLink); Flush(); } } else { // It's OK to get here. For example, this happens if you don't share the fe, but have a // button that calls NotebookCreate[]. This isn't a very good example, because that // function expects the fe to return something, so Java will hang. you will get into // trouble if you make calls on the fe that expect a return. Everything is OK for calls // that don't expect a return, though. int ignore; GetFunction(out ignore); // Must at least open the packet, so newPacket (back in caller) will get rid of it. } break; } default: break; } lastPktWasMsg = pkt == PacketType.Message; }