public override PacketType NextPacket() { // Code here is not just a simple call to impl.nextPacket(). For a KernelLink, nextPacket() returns a // wider set of packet constants than the MathLink C API itself. We want nextPacket() to work on the // non-packet types of heads the kernel and FE send back and forth. // Because for some branches below we seek back to the start before returning, it is not guaranteed // that when nextPacket() returns, the current packet has been "opened". Thus it is not safe to write // a J/Link program that loops calling nextPacket()/newPacket(). You need to call handlePacket() after // nextPacket() to ensure that newPacket() will throw away the curent "packet". // createMark will fail on an unconnected link, and the user might call this // before any reading that would connect the link. if (!linkConnected) { Connect(); linkConnected = true; } PacketType pkt; ILinkMark mark = CreateMark(); try { pkt = impl.NextPacket(); } catch (MathLinkException e) { if (e.ErrCode == 23 /* MLEUNKNOWNPACKET */) { ClearError(); SeekMark(mark); int argCount; string f = GetFunction(out argCount); if (f == "ExpressionPacket") { pkt = PacketType.Expression; } else if (f == "BoxData") { // Probably more than just BoxData will need to join this group. I thought that kernel // always sent cell contents (e.g. Print output) wrapped in ExpressionPacket, but not so. // "Un-wrapped" BoxData is also possible, perhaps others. We need to treat this case // specially, since there is no packet wrapper. SeekMark(mark); pkt = PacketType.Expression; } else { // Note that all other non-recognized functions get labelled as PacketType.FrontEnd. I could perhaps be // more discriminating, but then I risk not recognizing a legitimate communication // intended for the front end. This means that PacketType.FrontEnd is not a specific indication that // a front-end-related packet is on the link. Because there is no diagnostic packet head, // we need to seek back to before the function was read. That way, when programs call // methods to read the "contents" of the packet, they will in fact get the whole thing. SeekMark(mark); pkt = PacketType.FrontEnd; } } else { // The other MathLink error from MLNextPacket is MLENEXTPACKET, which is a common one saying // that you have called MLNextPacket when more data is in the current packet. throw e; } } finally { DestroyMark(mark); } return(pkt); }