Thursday, March 19, 2020

The Dark Side of Application.ProcessMessages

The Dark Side of Application.ProcessMessages Article submitted by Marcus Junglas When programming an event handler in Delphi (like the OnClick event of a TButton), there comes the time when your application needs to be busy for a while, e.g. the code needs to write a big file or compress some data. If you do that youll notice that your application seems to be locked. Your form cannot be moved anymore and the buttons are showing no sign of life. It seems to be crashed. The reason is that a Delpi application is single threaded. The code you are writing represents just a bunch of procedures which are called by Delphis main thread whenever an event occured. The rest of the time the main thread is handling system messages and other things like form and component handling functions. So, if you dont finish your event handling by doing some lengthy work, you will prevent the application to handle those messages. A common solution for such type of problems is to call Application.ProcessMessages. Application is a global object of the TApplication class. The Application.Processmessages handles all waiting messages like window movements, button clicks and so on. It is commonly used as a simple solution to keep your application working. Unfortunately the mechanism behind ProcessMessages has its own characteristics, which might cause big confusion! What does ProcessMessages? PprocessMessages handles all waiting system messages in the applications message queue. Windows uses messages to talk to all running applications. User interaction is brought to the form via messages and ProcessMessages handles them. If the mouse is going down on a TButton, for example, ProgressMessages does all what should happen on this event like the repaint of the button to a pressed state and, of course, a call to the OnClick() handling procedure if you assigned one. Thats the problem: any call to ProcessMessages might contain a recursive call to any event handler again. Heres an example: Use the following code for a buttons OnClick even handler (work). The for-statement simulates a long processing job with some calls to ProcessMessages every now and then. This is simplified for better readability: {in MyForm:}   Ã‚  WorkLevel : integer; {OnCreate:}   Ã‚  WorkLevel : 0; procedure TForm1.WorkBtnClick(Sender: TObject) ; var   Ã‚  cycle : integer; begin   Ã‚  inc(WorkLevel) ;   Ã‚  for cycle : 1 to 5 do   Ã‚  begin   Ã‚  Ã‚  Ã‚  Memo1.Lines.Add(- Work IntToStr(WorkLevel) , Cycle IntToStr(cycle) ;   Ã‚  Ã‚  Ã‚  Application.ProcessMessages;   Ã‚  Ã‚  Ã‚  sleep(1000) ; // or some other work   Ã‚  end;   Ã‚  Memo1.Lines.Add(Work IntToStr(WorkLevel) ended.) ;   Ã‚  dec(WorkLevel) ; end; WITHOUT ProcessMessages the following lines are written to the memo, if the Button was pressed TWICE in a short time: - Work 1, Cycle 1 - Work 1, Cycle 2 - Work 1, Cycle 3 - Work 1, Cycle 4 - Work 1, Cycle 5 Work 1 ended. - Work 1, Cycle 1 - Work 1, Cycle 2 - Work 1, Cycle 3 - Work 1, Cycle 4 - Work 1, Cycle 5 Work 1 ended. While the procedure is busy, the the form does not show any reaction, but the second click was put into the message queue by Windows. Right after the OnClick has finished it will be called again. INCLUDING ProcessMessages, the output might be very different: - Work 1, Cycle 1 - Work 1, Cycle 2 - Work 1, Cycle 3 - Work 2, Cycle 1 - Work 2, Cycle 2 - Work 2, Cycle 3 - Work 2, Cycle 4 - Work 2, Cycle 5 Work 2 ended. - Work 1, Cycle 4 - Work 1, Cycle 5 Work 1 ended. This time the form seems to be working again and accepts any user interaction. So the button is pressed half way during your first worker function AGAIN, which will be handled instantly. All incoming events are handled like any other function call. In theory, during every call to ProgressMessages ANY amount of clicks and user messages might happen in place. So be careful with your code! Different example (in simple pseudo-code!): procedure OnClickFileWrite() ; var myfile : TFileStream; begin   Ã‚  myfile : TFileStream.create(myOutput.txt) ;   Ã‚  try   Ã‚  Ã‚  Ã‚  while BytesReady 0 do   Ã‚  Ã‚  Ã‚  begin   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  myfile.Write(DataBlock) ;   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  dec(BytesReady,sizeof(DataBlock)) ;   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  DataBlock[2] : #13; {test line 1}   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Application.ProcessMessages;   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  DataBlock[2] : #13; {test line 2}   Ã‚  Ã‚  Ã‚  end;   Ã‚  finally   Ã‚  Ã‚  Ã‚  myfile.free;   Ã‚  end; end; This function writes a large amount of data and tries to unlock the application by using ProcessMessages each time a block of data is written. If the user clicks on the button again, the same code will be executed while the file is still being written to. So the file cannot be opened a 2nd time and the procedure fails. Maybe your application will do some error recovery like freeing the buffers. As a possible result Datablock will be freed and the first code will suddenly raise an Access Violation when it accesses it. In this case: test line 1 will work, test line 2 will crash. The better way: To make it easy you could set the whole Form enabled : false, which blocks all user input, but does NOT show this to the user (all Buttons are not grayed). A better way would be to set all buttons to disabled, but this might be complex if you want to keep one Cancel button for example. Also you need to go through all the components to disable them and when they are enabled again, you need to check if there should be some remaining in the disabled state. You could disable a container child controls when the Enabled property changes. As the class name TNotifyEvent suggests, it should only be used for short term reactions to the event. For time consuming code the best way is IMHO to put all the slow code into an own Thread. Regarding the problems with PrecessMessages and/or the enabling and disabling of components, the usage of a second thread seems to be not too complicated at all. Remember that even simple and fast lines of code might hang for seconds, e.g. opening a file on a disc drive might have to wait until the drive spin up has finished. It doesnt look very good if your application seem to crash because the drive is too slow. Thats it. The next time you add Application.ProcessMessages, think twice ;)

Tuesday, March 3, 2020

Five Steps to Verifying Online Genealogy Sources

Five Steps to Verifying Online Genealogy Sources Many newcomers to genealogy research are thrilled when find that many of the names in their family tree are easily available online. Proud of their accomplishment, they then download all the data they can from these Internet sources, import it into their genealogy software and proudly start sharing their genealogy with others. Their research then makes its way into new genealogy databases and collections, further perpetuating the new family tree and amplifying any errors each time the source is copied. While it sounds great, there is one major problem with this scenario; namely that the family information that is freely published in many Internet databases and Web sites is often unsubstantiated and of questionable validity. While useful as a clue or a starting point for further research, the family tree data is sometimes more fiction than fact. Yet, people often treat the information they find as the gospel truth. Thats not to say that all online genealogy information is bad. Just the opposite. The Internet is a great resource for tracing family trees. The trick is to learn how to separate the good online data from the bad. Follow these five steps and you too can use Internet sources to track down reliable information about your ancestors. Step One: Search for the Source Whether its a personal Web page or a subscription genealogy database, all online data should include a list of sources. The key word here is should. You will find many resources that dont. Once you find a record of your great, great grandfather online, however, the first step is to try and locate the source of that information. Look for source citations and references- often noted as footnotes at the bottom of the page, or at the end (last page) of the publicationCheck for notes or commentsClick on the link to about this database when searching a public database (Ancestry.com, Genealogy.com and FamilySearch.com, for example, include sources for most of their databases)Email the contributor of the data, whether it be the compiler of a database or the author of a personal family tree, and politely ask for their source information. Many researchers are wary of publishing source citations online (afraid that others will steal the credit to their hard-earned research), but may be willing to share them with you privately. Step Two: Track Down the Referenced Source Unless the Web site or database includes digital images of the actual source, the next step is to track down the cited source for yourself. If the source of the information is a genealogy or history book, then you may find a library in the associated location has a copy and is willing to provide photocopies for a small fee.If the source is a microfilm record, then its a good bet that the Family History Library has it. To search the FHLs online catalog, click on Library, then Family History Library Catalog. Use place search for the town or county to bring up the librarys records for that locality. Listed records can then be borrowed and viewed through your local Family History Center.If the source is an online database or Web site, then go back to Step #1 and see if you can track down a listed source for that sites information. Step Three: Search for a Possible Source When the database, Web site or contributor doesnt provide the source, its time to turn sleuth. Ask yourself what type of record might have supplied the information you have found. If its an exact date of birth, then the source is most likely a birth certificate or tombstone inscription. If it is an approximate year of birth, then it may have come from a census record or marriage record. Even without a reference, the online data may provide enough clues to time period and/or location to help you find the source yourself. Step Four: Evaluate the Source and Information It Provides While there are a growing number of Internet databases which provide access to scanned images of original documents, the vast majority of genealogy information on the Web comes from derivative sources - records which have been derived (copied, abstracted, transcribed, or summarized) from previously existing, original sources. Understanding the difference between these different types of sources will help you best assess how to verify the information that you find. How close to the original record is your information source? If it is a photocopy, digital copy or microfilm copy of the original source, then it is likely to be a valid representation. Compiled records- including abstracts, transcriptions, indexes, and published family histories- are more likely to have missing information or transcription errors. Information from these types of derivative sources should be further traced back to the original source.Does the data come from primary information? This information, created at or close to the time of the event by someone with personal knowledge of the event (i.e. a birth date provided by the family doctor for the birth certificate), is generally more likely to be accurate. Secondary information, by contrast, is created a significant amount of time after an event occurred, or by a person who was not present at the event (i.e. a birth date listed on a death certificate by the daughter of the deceased). Primary information usually carries m ore weight than secondary information. Step Five: Resolve Conflicts Youve found a birthdate online, checked out the original source and everything looks good. Yet, the date conflicts with other sources youve found for your ancestor. Does this mean that the new data is unreliable? Not necessarily. It just means that you now need to reevaluate each piece of evidence in terms of its likelihood to be accurate, the reason it was created in the first place, and its corroboration with other evidence. How many steps is the data from the original source? A database on Ancestry.com that is derived from a published book, which itself was compiled from original records means that the database on Ancestry is two steps away from the original source. Each additional step increases the likelihood of errors.When was the event recorded? Information recorded closer to the time of the event is more likely to be accurate.Did any time elapse between the event and the creation of the record that relates its details? Family bible entries may have been made at one sitting, rather than at the time of the actual events. A tombstone may have been placed on the grave of an ancestor years after her death. A delayed birth record may have been issued dozens of years after the actual birth.Does the document appear altered in any way? Different handwriting may mean that information was added after the fact. Digital photos may have been edited. Its not a normal occurrence, but it does happen.What do others say about the source? If it is a published book or database rather than an original record, use an Internet search engine to see if anyone else has used or commented on that particular source. This is an especially good way to pinpoint sources which have a large number of errors or inconsistencies. Happy hunting!