CSharp/C# >> Help on .NET Word Object Library Range Find.Execute infinite Loop

by winston.heng » Tue, 13 Feb 2007 19:22:37 GMT

Hi,

Thanks for reading this posting. I have been cracking my head on
solving the infinite loop
when i call the following section code. Any help or advise is greatly
appreciated =D

Thanks in advance.

Cheers!
Winston

//i follow the sample provided by microsoft
http://msdn2.microsoft.com/en-us/library/aa192495(office.11).aspx#wordobject_link7

Object start = 0;
Object end = oWordDoc.Characters.Count;
Object forward = true ;
Object wrap = Microsoft.Office.Interop.Word.WdFindWrap.wdFindStop;
Object oCollapse = WdCollapseDirection.wdCollapseEnd;

bool bFound = false;

Microsoft.Office.Interop.Word.Range oRng = oWordDoc.Range(ref start,
ref end);
Microsoft.Office.Interop.Word.Find oFnd = oRng.Find;

oFnd.ClearFormatting();
oFnd.Forward = true;
oFnd.Wrap = WdFindWrap.wdFindStop;
oFnd.Text = "Hello";

ExecuteFind(oFnd);

while (oFnd.Found)
{
oRng.Hyperlinks.Add(oRng, ref oURL, ref oMissing, ref oMissing,
ref oMissing,
ref oTargetFrame);

oRng.Collapse(ref oCollapse);

ExecuteFind(oFnd);
}

private Boolean ExecuteFind(Word.Find find)
{
return ExecuteFind(find, Type.Missing, Type.Missing);
}

private Boolean ExecuteFind(
Word.Find find, Object wrapFind, Object forwardFind)
{
// Simple wrapper around Find.Execute:
Object findText = Type.Missing;
Object matchCase = Type.Missing;
Object matchWholeWord = Type.Missing;
Object matchWildcards = Type.Missing;
Object matchSoundsLike = Type.Missing;
Object matchAllWordForms = Type.Missing;
Object forward = forwardFind;
Object wrap = wrapFind;
Object format = Type.Missing;
Object replaceWith = Type.Missing;
Object replace = Type.Missing;
Object matchKashida = Type.Missing;
Object matchDiacritics = Type.Missing;
Object matchAlefHamza = Type.Missing;
Object matchControl = Type.Missing;

return find.Execute(ref findText, ref matchCase,
ref matchWholeWord, ref matchWildcards, ref matchSoundsLike,
ref matchAllWordForms, ref forward, ref wrap, ref format,
ref replaceWith, ref replace, ref matchKashida,
ref matchDiacritics, ref matchAlefHamza, ref matchControl);
}


CSharp/C# >> Help on .NET Word Object Library Range Find.Execute infinite Loop

by RobinS » Wed, 14 Feb 2007 02:55:06 GMT


You could try posting this to an Office Programming group. If nobody here
has an answer, maybe somebody there would.

Robin S.
----------------------------------

Similar Threads

1. Find.Execute with Find.Format = True keeps looping - Word VBA

2. Find Loop only works on first 3 of find.execute then stops

Can anyone please tell me why this macro works on the first three occurances 
of finding strFind (of a total of 43 occurances) and then stops after the 
third occurance of finding strFind with a message:  

Code Execution has been interrupted.  
When I click Debug, this line in the code is highlighted in Yellow:
If Not Selection.Find.Found Then Exit Do 

MACRO:

Sub findandType()

Dim strFind As String
Dim strTypeTxt As String

strFind = "Site Address"
strTypeTxt = "Site City:"

Selection.HomeKey Unit:=wdStory ' move to top of document
Do ' STARTS LOOP
    With Selection.Find
        .Text = strFind
        .Replacement.Text = ""
        .Forward = True
        .Wrap = wdFindStop 'CRITICAL so not asked to continue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
If Not Selection.Find.Found Then Exit Do ' STOP IF NOT FOUND ANYMORE
    'STUFF TO DO AFTER TEXT IS FOUND
    Selection.MoveDown Unit:=wdLine, Count:=1 'move down one line
    Selection.HomeKey Unit:=wdLine                   'move to the beginning 
of the line
    Selection.TypeText Text:=strTypeTxt             'type this text
'find the next occurance of strFind
Loop
End Sub

3. Infinite Loop with a find and replace - Word VBA

4. Returning object from AsyncCallback called inside a threaded Infinite loop

Jim:

I'm not entirely sure that I understand the question.  Let me throw what I
picked up back at you, and you can maybe correct me if I'm wrong:
I assume that the code that you posted all works, except that you have a
scoping issue where you cannot inform the main form that something has been
acted upon because inside your OnReadComplete method, the main form (or the
form that you want to notify) is not in scope.  Is that correct?

Assuming that's right, you could could always make a reference to the main
form (or better yet, some kind of broker object) available to the thread
code, which would, in turn, add the reference to your state object:
(warning, this is off the cuff, might need adjustment to compile)

So, what could happen would be that you have an "observer" class that sits
between the form(s) and the state class.  The class with the thread has a
reference to it, so that it (the observer) can be added to the state class:

form(s) ------ Observer ------ State

State notifies the observer, and the observer fires an event that can be
subscribed by multiple forms or other objects.

public delegate void MessageReceivedEventHandler(object sender,
MessageReceivedEventArgs e);
public class MessageReceivedEventArgs
{
    public MessageReceivedEventArgs(string message)
    {
        this.Message = message;
    }

    public string Message; // probably make this a property, leaving it out
for brevity
}

public class SocketReadObserver
{
    public event MessageReceivedEventHandler MessageReceived;
    public void ActOn(string message)
    {
        if(this.MessageReceived != null)
            this.MessageReceived(this, new
MessageReceivedEventArgs(message);
    }
}

Now, your State class calls the SocketReadObserver's ActOnMethod.
You need to somehow have SocketReadObserver in scope.  You could use a
singleton for this, or your main form could instance one and pass to the
class that contains the thread.  Or, perhaps the object that owns the thread
also owns the observer.

The benefit of breaking it out into an observer is that any object
(including the main form) that is interested in receive events can subscribe
to the event:

public class TheThreadClass
{
    public SocketReadObserver Observer;
    public void TheInfiniteLoopMethod
    {
        //same code as before
        // except provide the listener to the state class
        handler.Observer = this.Observer;
    }
}

// state object calls Observer.ActOn(message) when the message completes

// oh, don't forget the main form code:

// main form:
// here's the code that starts the thread:
// note the observer has to be created somewhere
// in this example, the form will do it, but you might want to originate it
elsewhere
..
SocketReadObserver observer = new SocketReadObserver();
theThreadListenerObject.Observer = observer;
observer.MessageReceived += new
MessageReceivedEventHandler(this.MessageReceived);
// note, you can hook as many interested parties as you have to this
event -- system tray item, toolbar item, whatever:

public void MessageReceived(object sender, MessageReceivedEventArgs e)
{
    // important:  this event will not be called by the main thread, but if
you want to do _anything_ that changes
    // a gui control, you _must_ make it happen on the main thread.  Use
Invoke for this:
    if(this.InvokeRequired)
           this.Invoke(new
MessageReceivedEventHandler(this.MessageReceived), object[] {sender, e});
    else
    {
            // do your form stuff here
    }

}


PS depending upon what you were doing, there are probably a number of ways
that you can optimize this, I was just trying to get the idea across.

PSS: If this isn't the problem that you've had, I'm sorry for being a
windbag <g>


"Jim P." < XXXX@XXXXX.COM > wrote in message
news:uqkoNce% XXXX@XXXXX.COM ...
> I'm having trouble returning an object from an AsyncCallback called inside
a
> threaded infinite loop.
>
> I'm working on a Peer2Peer app that uses an AsyncCallback to rerieve the
> data from the remote peer. I have no problem connecting the peers and
> streaming Network Streams.  When the incoming data is finished recieving,
I
> act upon it.  This works great as long as all of the code is inside my
form.
>
> I want to build the networking code into a seperate assembly (to be used
by
> a server and client apps).  It works fine but I can't return the value
back
> to the Main Form.  How can I pass back the retrieved data through the
> following steps??  Or, any other strategies on how to tackle this problem?
>
> The Current Process
> I start the listener inside a thread and begin an infinite loop to check
for
> a client connection.  When a client connects I call a method that starts
the
> .BeginRead on the Network Stream.  The .BeginRead uses an AsyncCallback
> delegate called 'OnReadComplete' and passes a StateObject with the
connected
> socket..  Inside OnReadComplete, I transfer the callback object to a new
> StateObject.  I recieve data in 256 byte chunks until the bytes recieved
> equals 0.  Then I act on that data.
>
> Some example code:
>
> ** State Object
> ----------------
> public class StateObject
> {
>  public System.Net.Sockets.Socket socket;
>  public byte[] buffer = new byte[256];
>  public NetworkStream networkStream;
>
>  public AsyncCallback callbackRead;
> }
>
> ** Infinite loop used after starting listener
> ------------------------------------------
> // keep listening until you recieve a connection
> for (;;)
> {
>  // if client connects, accept the connection
>  // and return a new socket named socketForClient
>  // while tcpListener keeps listening
>  Socket socketForClient = tcpListener.AcceptSocket();
>  if (socketForClient.Connected)
>  {
>   StateObject handler = new StateObject();
>   handler.socket = socketForClient;
>   handler.networkStream = new NetworkStream(socketForClient);
>   handler.callbackRead = new AsyncCallback(this.OnReadComplete);
>   StartRead(handler);
>  }
> }
>
> ** StartRead
> -------------
> public void StartRead(StateObject handler)
> {
>  handler.networkStream.BeginRead(
>   handler.buffer, 0, handler.buffer.Length, handler.callbackRead,
handler);
> }
>
> ** OnReadComplete
> ----------------------
> private void OnReadComplete( IAsyncResult ar )
> {
>  // Get the socket
>  StateObject newSocket = (StateObject)ar.AsyncState;
>  Socket client = newSocket.socket;
>
>  // Get the networkStream
>  NetworkStream readStream = new NetworkStream(newSocket.socket);
>
>  int bytesRead = readStream.EndRead(ar);
>
>  // If there is data left to be retieved
>  if( bytesRead > 0 )
>  {
>   string s = System.Text.Encoding.ASCII.GetString( newSocket.buffer, 0,
> bytesRead );
>   readStream.BeginRead( newSocket.buffer, 0, newSocket.buffer.Length,
> newSocket.callbackRead, newSocket);
>   // Store message into string.
>   message += s;
>  }
>  // The incoming stream has finished
>  else
>  {
>   // Act on Incoming Message
>   actOn(message);
>
>   // Close out all objects
>   newSocket.networkStream.Close();
>   newSocket.socket.Close();
>   newSocket.networkStream = null;
>   newSocket.socket = null;
>   message = null;
>  }
> }
>
>
> Thanks,
> Jim
>
>


5. Infinite loop in _AfxRemoveDefaultButton in mfc71ud.dll - help!

6. Need help with TDrawGrid DrawCell stuck in infinite loop

I'm relatively new to Delphi and I'm having a bear of a time trying to
understand what I'm doing wrong with this DrawGrid.  I've got the following
code:

  TResultsGrid = class(TDrawGrid)
    ResultsSet: TResultsSet;
  private
    fTypeList,
    fNameList: TStringList;
    fSavedFile: string;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState:
TGridDrawState); override;
    procedure AssignColTypes(TypeList: TStringList);
    procedure AssignColNames(NameList: TStringList);
    procedure Save;
    procedure SaveAs;
    procedure Print;
  end;


procedure TResultsGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState:
TGridDrawState);
begin
  if ARow = 0 then
    self.Canvas.TextOut(ARect.Left, ARect.Top, fNameList.Strings[ACol])
  else
    self.Canvas.TextOut(ARect.Left, ARect.Top, ResultsSet.GetRow(ARow -
1).Strings[ACol]);
end;


For some reason I'm getting an EStringListError with message 'List index out
of bounds[2]', but when I set a break point within the DrawCell procedure
the value of ARow and ACol are always zero.  I'm dynamically creating the
drawgrid with the code below:

        fResultsSet[fGrids - 1] := TResultsGrid.Create (ResultsScrollBox);
        fResultsSet[fGrids - 1].Parent := ResultsScrollBox;
        fResultsSet[fGrids - 1].Options :=
[goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine,goRangeSelect,goColSi
zing];
        fResultsSet[fGrids - 1].Height := ResultsTab.Height;
        fResultsSet[fGrids - 1].Align := alClient;


            ColTypes.Insert(0, 'integer');
            fResultsSet[fGrids - 1].AssignColTypes (ColTypes);

            ColNames.Insert(0, '');
            fResultsSet[fGrids - 1].AssignColNames (ColNames);

            fResultsSet[fGrids - 1].ResultsSet := ResultsSet;

            fResultsSet[fGrids - 1].ColCount := Columns + 1;
            fResultsSet[fGrids - 1].RowCount := ResultsSet.Count + 1;

            if fResultsSet[fGrids - 1].RowCount < 2 then
fResultsSet[fGrids - 1].RowCount := 2;
            fResultsSet[fGrids - 1].FixedRows := 1;


Any ideas will be helpfull...

Thanks,

-Charles


7. loop thru a STL list causes an infinite loop

8. Range.Find.Execute generates a DocumentChange event