Hi,
I have needed the same functionality and this is what I have ended up with - though it doesn’t work that well yet, as the Simulator.Readystate is not necessarily fired the first time you run a simulation (atleast with MoveAlongPath).
I use the Datarecorders event, as it is more reliable than the ProgrampointChanged event, since if the simulation is a full speed, the virtual controller sometimes go past certain lines, that it can execute really quickly.
First event saves the module to a file, and afterwards reads into a streamreader where I add each line to a list.
void Simulator_StateChanged(object sender, EventArgs e)
{
if (Simulator.State == SimulationState.Ready)
{
SimulationState state = Simulator.State;
module = task0.GetModule(task0.ProgramPointer.Module);
module.SaveToFile("C:");
lines.Clear();
using(StreamReader sr = new StreamReader("C:" + module.ToString() + “.mod”))
{
string line;
while ((line = sr.ReadLine()) != null)
{
lines.Add(line);
}
}
}
}
The second event is the Datarecorders tick event - this is a bit more reliable than Programpointer changed event.
In this, I get the motionPointer, as this was what I needed, but I guess you should be able to use programpointer aswell.
given the row line (begin), I can then extract the line from my list that included the module.
void DataRecorder_Tick(object sender, DataRecorderTickEventArgs e)
{
ProgramPosition pos = task0.MotionPointer;
int begin = pos.Range.Begin.Row;
int end = pos.Range.End.Row;
string module = pos.Module;
if (begin != temp && begin != 0 && lines.Count() > 1 && begin < lines.Count())
{
temp = begin; // to avoid same lines multiply times.
Logger.AddMessage(new LogMessage(lines[begin-1], LogMessageSeverity.Warning));
}
}
Some of this code is snippets that I copy/pasted and modified here in the post, so there might be a few errors/typos.
Hopefully you can get something working 
Regards, Lars