AfterScroll access violation

bmayfield

Member²
We are DOA2006 and Delphi 2006.

We have a need to perform a TOracleQuery after the user switches from one record in the dbgrid to another. The user is using the down arrow or clicking on the navigator bar to switch records. We get a access violation in the AfterScroll event to fill some tEdit fields. Basically there is a 6 digit code that we look up the description for in a table and display it outside the dbgrid along with other dbedit fields.

We put a ShowMessage in the AfterScroll event and it fires many times before the screen even displays and after the dbgrid and dbedit fields display. What event can we put our code in where the event only gets called once after the user moves to a different row and we know we can access the data (field values)? The note in AfterFetchRecord syas the record is not available yet and it says to use the NewValue of the fields instead. This is not an update application. If this is not the event we can use can you suggest which event we can do this?

procedure fillSicMrDesc;
var
bindcode : String;
lenBindcode : Integer;
Begin
lenBindCode := -1;
CMPA0017frm.oqGetSicMrDesc.Close;
bindcode := CMPA0017frm.odsDol_Employers.FieldByName('SIC_MR').Text;
lenBindcode := length(bindcode);
if lenBindcode = 0 then
begin
CMPA0017frm.edtSicMrDesc.Text := '';
exit;
end;
CMPA0017frm.oqGetSicMrDesc.SetVariable('BINDCODE', bindcode);

try
CMPA0017frm.oqGetSicMrDesc.Execute;
except
on E:EDatabaseError do
begin
ShowMessage(E.Message);
ShowMessage('oqGetSicMrDesc Query produced no results');
Exit;
end
end;

CMPA0017frm.edtSicMrDesc.Text := CMPA0017frm.oqGetSicMrDesc.GetVariable('BINDDESC');
end;

Thanks in advance.

Bruce
 
The AfterScroll event is the correct event for this. Make sure that you do not perform any actions that cause a new AfterScroll event of the same dataset. If this is required, you need to add a flag variable that indicates that the new AfterScroll event is triggered from a previous AfterScroll event.
 
The afterscroll event only fires when query enter or query execute methods are invoked and not if the navigator bar or dbgrid record indicator is moved by clicking on the next row in the grid itself. OnClick fires when next or previous buttons are depressed but is not related to the actions taken in the dbgrid. The dbgrid intercepts up and down arrows and the when you click on the record indicator in the dbgrid, all of these actions do not fire either the afterscroll or onclick events.

When we tried to use oncellclick and onkeydown events of the dbgrid, these events fired before the contents of the record were instantiated.

Are we missing something? As soon as the new row is fetched and displayed in the grid, we need to insert code in a event to populate Tedit fields. It seems like afterfetchrecord event should work but help says "Note that you cannot access the field values in this event, because the record is not yet available. If you need to know the field values of the currently fetched record, use the NewValue of the fields instead."

We need a event after the fetch of the next record that does give us access to the field values because the record is available. So there is no event that will satisfy this need?

Again, thanks in advance.
 
The afterscroll event only fires when query enter or query execute methods are invoked and not if the navigator bar or dbgrid record indicator is moved by clicking on the next row in the grid itself.
Are you sure? According to the documentation is will fire whenever the current record changes. A little test with the DeptEmp demo project confirms this.
 
Our mistake, we still do not see a event that will fire where the next record data is available for us to plug into a query that won't get access violations in the afterScroll event. Here is the sequence of events.

Before the form displays afterscroll fires with dataset state = browsing.

Form activate puts dataset in nbEnterQBE mode.

Afterscroll fires again with dataset state browsing. We do not know what causes this event to fire again. There is a master detail arrangement with another dbgrid but do not know if that is relevant.

Afterscroll fires again with dataset state = New record inserting.

We enter data in the dbgrid and nbEnterQBE.

Afterscroll fires again with dataset state = browsing.

The dbgrids are populated now.

Afterscroll fires again with dataset state = browsing. This is where we want to populate the descriptions from data in the dbedit fields associated with the same ods as the dbgrid from lookup tables in the database by doing a TOracle Queries. But we don't know this is this the time to execute the ToracleQuery and the new record data we moved to is not available yet according to the documentation even if we knew which instance of the event to do the TOracleQuery in.

If we click on the next row down in the dbgrid, Afterscroll fires again with dataset state = browsing.

So we do not know how to code for the new AfterScroll event that is triggered from a previous AfterScroll event since it fires so many times from the descriptions provided above.

Additionally, if user wants to go in nbEnterQBE mode again in the same session, Afterscroll fires again with dataset state = browsing. The dbgrid is cleared. Afterscroll fires again with dataset state = browsing. Afterscroll fires again with dataset state = New record inserting. We enter new data in the dbgrid, nbEnterQBE, Afterscroll fires again with dataset state = browsing. The dbgrids are filled and Afterscroll fires again with dataset state = browsing.

We can't count the number of times the Afterscroll event is entered nor can we assocate with what is happening with the dataset state.

Hopefully, we are providing enough information so you can assist.

Thanks in advance.

Bruce
 
procedure TCMPA0017frm.odsDol_EmployersAfterScroll(DataSet: TDataSet);
begin
if CMPA0017frm.odsDol_Employers.QBEMode = False then
fillOrgTypeCdDesc;
end;

procedure fillOrgTypeCdDesc;
var
holdchar : AnsiString;
begin
holdchar := CMPA0017frm.dbeOrgTypeCdPvtMr.Field.Value;
if not AnsiContainsText('CIPO', holdchar) then
CMPA0017frm.edtOrgTypeCdPvtMr.Text := 'Unknown';
if CMPA0017frm.dbeOrgTypeCdPvtMr.Field.Value = 'C' then
CMPA0017frm.edtOrgTypeCdPvtMr.Text := 'Corporation';
if CMPA0017frm.dbeOrgTypeCdPvtMr.Field.Value = 'I' then
CMPA0017frm.edtOrgTypeCdPvtMr.Text := 'Individual Proprietership';
if CMPA0017frm.dbeOrgTypeCdPvtMr.Field.Value = 'P' then
CMPA0017frm.edtOrgTypeCdPvtMr.Text := 'Partnership';
if CMPA0017frm.dbeOrgTypeCdPvtMr.Field.Value = 'O' then
CMPA0017frm.edtOrgTypeCdPvtMr.Text := 'Other Organization Type';
end;

It doesn't matter much what you put in the afterscroll event you get this:

Call Stack Information:
------------------------------------------------------------------------------------------------
|Address |Module |Unit |Class |Procedure/Method |Line |
------------------------------------------------------------------------------------------------
|*Exception Thread: ID=2640; Priority=0; Class=; [Main] |
|----------------------------------------------------------------------------------------------|
|02AA5BDD|CMPA0017.bpl |Cmpa0017frmu.pas|TCMPA0017frm |odsDol_EmployersAfterScroll | |
|52342AA9|dbrtl100.bpl |Db.pas |TDataSet |DoAfterScroll | |
|52342A4A|dbrtl100.bpl |Db.pas |TDataSet |DoAfterOpen | |
|5233F0D9|dbrtl100.bpl |Db.pas |TDataSet |OpenCursorComplete | |
|5233F088|dbrtl100.bpl |Db.pas |TDataSet |OpenCursorComplete | |
|5233EFFF|dbrtl100.bpl |Db.pas |TDataSet |SetActive | |
|004A7928|doa40d2006.bpl|Oracledata.pas |TOracleDataSet|TrimString | |
|004B5BA5|doa40d2006.bpl|Oracledata.pas |TOracleDataSet|Loaded | |
|51F50AE4|rtl100.bpl |Classes | |NotifyGlobalLoading |2681[3] |
|51F50AC0|rtl100.bpl |Classes | |NotifyGlobalLoading |2678[0] |
|51F50C65|rtl100.bpl |Classes | |InitInheritedComponent |2719[7] |
|51F50BF4|rtl100.bpl |Classes | |InitInheritedComponent |2712[0] |
|5206FD49|vcl100.bpl |Forms |TCustomForm |Create |2666[8] |
|51F4F8E4|rtl100.bpl |Classes |TRegGroup |Registered |1974[0] |
|51F4FDB3|rtl100.bpl |Classes |TRegGroups |Registered |2180[3] |
|7C9010ED|ntdll.dll | | |RtlLeaveCriticalSection | |
|51F4FE24|rtl100.bpl |Classes |TRegGroups |Unlock |2198[0] |
|51F4FE20|rtl100.bpl |Classes |TRegGroups |Unlock |2198[0] |
|51F5024B|rtl100.bpl |Classes | |RegisterClass |2344[10] |
|51F501EC|rtl100.bpl |Classes | |RegisterClass |2334[0] |
|02AA7172|CMPA0017.bpl |Cmpa0017frmu.pas| |initialization | |

Exception:
--------------------------------------------------------------------------------------------------------------
2.1 Date : Tue, 1 Apr 2008 15:14:21 -0500
2.2 Address : 02A91B8E
2.3 Module Name : CMPA0020.bpl
2.4 Module Version: 1.0.0.0
2.5 Type : EAccessViolation
2.6 Message : Access violation at address 02A91B8E in module 'CMPA0020.bpl'. Read of address 00000030.
2.7 ID : CC3C
2.8 Count : 1
2.9 Status : New

Assembler Information:
-----------------------------------------------------------------------
; Cmpa0017frmu.TCMPA0017frm.odsDol_EmployersAfterScroll
; ------------------------------------------------------
02AA5BDC add cl, byte ptr [ebx+$39880]
02AA5BE2 add [eax+$255B8], al
02AA5BE8 add [eax], al
02AA5BEA jnz Cmpa0017frmu.TCMPA0017frm.odsDol_EmployersAfterScroll
02AA5BEC call -$00002E05
02AA5BF1 ret
 
Just to follow up on this we can execute code in the afterscroll event if it is in a try/except block with no exception handler. This makes no sense that it would work with try/except and get access violations without try/except.

The final resolution to the problem was to create sql statements, that use decode, functions or joins to list of value tables to populate the grids so as to avoid executing sql statements in the afterscroll event.

Any description field could then reference a column in the grid and when the grid scrolls or row changes in the grid then the description changes as well.
 
Back
Top