2

I am using the Skype4COM control. My program is trying to delete around 3K contacts from my contact list in Skype using a For loop, however

1) It takes a lot of time

2) it may crash, with a "MyApp has stopped working"

My guess is that somehow I need to "slow down" what I am doing.

Would I do that with Sleep();? Because I am not sure if that is also gonna "pause" the connection between Skype and my program.

To summarize: I am doing an action with a huge ammount of entries, and because of that big ammount, my program is hanging for a long time, and eventually crashes (sometimes). Is there a way to prevent that?

Skype4COM is STA by the way.

  • Thanks!
Jeff
  • 12,085
  • 12
  • 82
  • 152
  • Why would Sleep help? That just blocks the thread for a specified amount of time. Rather than proposing solutions, you need to concentrate on working out what your problem is. At the moment you don't know what is going wrong. – David Heffernan Mar 19 '11 at 19:41
  • @David "Because I am not sure if that is also gonna "pause" the connection between Skype and my program." - Thats what I thought. The problem is that for every contact I delete, my app sends a message to Skype, and Skype sends one back. My current conclusion is that one or the other is being overloaded. What would you suggest? – Jeff Mar 19 '11 at 19:45
  • How about deleting only (say) 100 contacts at a time? Since it's choking on 3000+, try backing off until you find a large number that it'll handle without barfing. – Marc B Mar 19 '11 at 19:55
  • Are these messages synchronous? – David Heffernan Mar 19 '11 at 19:59
  • 1
    From O.P: **"Skype4COM is STA by the way."** - Yes, synchronous. – Jeff Mar 19 '11 at 20:17
  • @Marc - Apparently it does not like 100 either... It's weird :S – Jeff Mar 19 '11 at 20:18

2 Answers2

6

Move the processing into a separate thread. Your problem appears to be that Windows thinks the app has stopped responding because it's not processing it's message loop.

Calling Application.ProcessMessages is the wrong solution, because it does a lot more than you might think. You can end up with problems with reentrancy, or things happening that you don't expect.

Make sure that the thread calls CoInitialize before it creates the COM object, and calls CoUnitialize when it's done. You can find examples of using COM in a thread here; the article refers to ADO, but demonstrates the use of CoInitialize/CoUninitialize.

EDIT: After the comments, I'm adding an example of receiving a custom message in a Delphi app. The thread will need access to the UM_IDDELETED constant; you can do this by (preferably) adding it to a separate unit and using that unit in both your main form's unit and the thread's unit, or simply by defining it in both units.

// uCustomMsg.pas
const
  UM_IDDELETED = WM_APP + 100;

// Form's unit
interface

uses ..., uCustomMsg;

type
  TForm1=class(TForm)
  // ...
  private
    procedure UMIDDeleted(var Msg: TMessage); message UM_IDDELETED;
  //...
  end;

implementation

procedure TForm1.UMIDDeleted(var Msg: TMessage);
var
  DeletedID: Integer;
begin
  DeletedID := Msg.WParam;
  // Remove this item from the tree
end;

// Thread unit
implementation

uses
  uCustomMsg;

// IDListIdx is an integer index into the list or array
// of IDs you're deleting.
// 
// TheFormHandle is the main form's handle you passed in
// to the thread's constructor, along with the IDList
// array or list.

procedure TYourThread.Execute;
var
  IDToDelete: Integer;  // Your ID to delete
begin
  while not Terminated and (IDListIdx < IdList.Count) do
  begin
    IDToDelete := IDList[IDListIdx];
    // ... Do whatever to delete ID
    PostMessage(TheFormHandle, UM_IDDELETED, IDToDelete, 0);
  end;
end;
Community
  • 1
  • 1
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • Believe it or not, I tried using Threads with Skype4COM before, and it did NOT like it - The app run smoothly and all, but unexpected things happend, like it would never finish and whatnot. Also, I have a visual control to display the contact list (Virtual String Tree), so wouldn't I have to use Synchronize aswell? Because thats what went wrong the last time, Synchronize made it all malfunction. – Jeff Mar 19 '11 at 20:41
  • @Jeff, no, you don't have to use Synchronize. You can post a message from the thread back to your application's window (like a numeric contact ID, or the counter for the contact that was just deleted), and your application window can receive the message and update the UI as needed. There are dozens of examples of using TThread in Delphi here at SO; a quick search should turn one up. – Ken White Mar 19 '11 at 20:44
  • @Ken - So, basically create a whole new TSkype object in my thread (as I need to do TSkype.User.Delete;)? Also, I heard some horror stories about threads and the VCL - since my current loop gets the data from my TVirtualStringTree, will I still be able to do that "safe" within my thread? – Jeff Mar 19 '11 at 20:48
  • @Jeff, yes. Each thread gets it's own TSkype object (and each has to call CoInitialize/Counitialize). You can't directly access the TVirtualStringTree (VST) from the thread, but why would you need to? Just create a list of IDs to delete, pass that to the thread's constructor, and let the thread do it's work. When it deletes each one, it passes back the ID it just deleted to your main thread via a message, and the main thread deletes it from the VST. – Ken White Mar 19 '11 at 21:09
  • @Jeff: (continued) If this won't work, your main thread can post a message to the thread (using PostThreadMessage; this is a little more complicated, though), passing the next ID to delete to the thread. The thread then sends back a message to the main thread when the ID is deleted, and the main thread updates the UI and sends the next ID to delete. – Ken White Mar 19 '11 at 21:11
  • @Ken - **"When it deletes each one, it passes back the ID it just deleted to your main thread via a message, and the main thread deletes it from the VST."** - How would I do that? I am not sure I follow that part. Would you care to explain a little bit further? Much appreciated :) – Jeff Mar 19 '11 at 21:14
  • @Jeff: When you create the thread, pass it the list of items to delete and the handle of your main window (the one with the VST). When the thread deletes a contact, it calls `PostMessage(MainWindowHandle, UM_IDDELETED, DeletedID, 0); `. The main window needs a handler for UM_IDDELETED; it reads the WParam (DeletedID) in the message handler and removes the VST node for that ID. For more info, create another question about declaring and handling custom messages in a Delphi app. There's no space here, and it's a different topic. – Ken White Mar 19 '11 at 21:25
  • @Jeff: In Delphi XE's help, see ms-help://embarcadero.rs_xe/rad/Creating_New_Message_Handlers.html For other versions, search the help for 'Message Handlers, Creating'. – Ken White Mar 19 '11 at 21:29
  • @Ken - I am also trying to add people to my VST, which was what I tried doing with a Thread before, which did not work. I dont suppose I can use your method here, since I am adding data (Strings, TDateTime, etc) to my VST? – Jeff Mar 19 '11 at 21:38
  • @Jeff, you can't update any portion of the UI from a thread. You can send information back and forth using messages, or use a critical section or other means of locking shared data to communicate. This would really be a topic for another question; there's no room in the comments to discuss these details. – Ken White Mar 19 '11 at 21:51
  • @Ken - Yes, you're right. Will try this, and if I dont succeed, I will post a question here. Would you happen to have Skype or any other IM? :) – Jeff Mar 19 '11 at 21:59
  • @Jeff, no, sorry. (And that doesn't help anyone else here to go to IM, does it?) – Ken White Mar 19 '11 at 22:00
0

if you are using a loop to delete each contact you can place a call to Application.ProcessMessages this should fix the issue

[edit] the call should be in the loop

Robert
  • 3,328
  • 2
  • 24
  • 25
  • 2
    I don't see how you have reached this conclusion based on the information provided. – David Heffernan Mar 19 '11 at 19:40
  • Thanks for your answer! Yes, I am doing it in a loop, however, Application.ProcessMessages, isn't that going to slow it down even further? – Jeff Mar 19 '11 at 19:41
  • david, i came to that conclution because windows reports it as not responding if it dosn't process events/messages after a short time i can't remember the time this has the effect of the application looking like it has crashed – Robert Mar 19 '11 at 19:45
  • jeff, it will slow it down but its a long running process and will hold up the ui from responding without it – Robert Mar 19 '11 at 19:46
  • @Jeff What's "slowing it down" got to do with anything? Programs don't usually fail because they are going too fast. And it's rich of you to complain about this considering you suggested calling Sleep, the ultimate "slow me down" function! – David Heffernan Mar 19 '11 at 19:48
  • @Robert An app that doesn't pump its message queue doesn't generally crash (I guess it could fail when it reaches the 10,000 messages in queue limit), so I'm not sure this is it. – David Heffernan Mar 19 '11 at 19:50
  • Well, wouldnt I just do ProcessMessages every once in awhile - as in, not for EVERY loop entry, just every 100th? Or would that not help? – Jeff Mar 19 '11 at 19:50
  • yes you can place the call every 100 or so and that would work – Robert Mar 19 '11 at 19:53
  • 1
    jeff i said 'this has the effect of the application looking like it has crashed'. i suspect that the application is still processing and its just the ui that it not responding – Robert Mar 19 '11 at 19:56
  • @Jeff ProcessMessages is a null operation if the queue is empty. – David Heffernan Mar 19 '11 at 20:07
  • @Robert @David - Reason I asked about ProcessMessages, was because I did it before when I processed a huge ammount of data, which slowed it down way more, and also lead to some AV's and whatnot. Been awhile since I messed with that, so don't hang me up on it. :P – Jeff Mar 19 '11 at 20:13
  • -1. Application.ProcessMessages is almost *never* the correct solution to a problem, and usually creates more problems itself. – Ken White Mar 19 '11 at 20:49