Jump to content
Morten Skovrup

TActionMainMenuBar (indirectly) kills Application

Recommended Posts

Hi,

I have an application that fails on some Chinese systems. When I say fail, I mean that the program simply stops running - no warning, error or anything - main Window just disappears.
I'm btw. using MadExcept and it never even gets triggered - the program just disappears...

 

The reason is that the translation tool "YouDao" (http://dict.youdao.com/?keyfrom=cidian) is active. YouDao works by translating everything that's beneath your cursor when you move around on the screen (i.e. it probably tries to get hold of a handle of the control below the cursor and reads its text/caption property and then translates).

 

It turns out that whenever the cursor hovers above an item in a TActionMainMenuBar (main item will do - for example "File" menu), the Delphi program fails when YouDao tries to get the text of the TActionMainMenuBar.

A simple application with a TActionManager a TActionMainMenuBar and just one action will reproduce the error when YouDao is installed (actually the Delphi IDE fails the exact same way - the menu in Delphi IDE is a TActionMainMenuBar).

 

And yes, it will solve all problems if users turn off YouDao, but YouDao is quite popular in China, so that's really not an option ;-).

 

ebugging gives the following result:
---------------------------
Debugger Exception Notification
---------------------------
Project TestActionMainMenu.exe raised exception class $C0000005 with message 'access violation at 0x0046cb93: read of address 0x00000005'.

 

And pressing "Break" leads to line 6062 in System.Classes (first line after begin):

function TCollectionItem.GetIndex: Integer;
begin
  if FCollection <> nil then
    Result := FCollection.FItems.IndexOf(Self) else
    Result := -1;
end;

 

So I assume that the object holding a TCollectionItem at this point has a dangling pointer...

Pressing F9 just get the following (and thereafter entering loop to above place in code until pressing <Ctrl+F2>):


---------------------------
Debugger Fault Notification
---------------------------
Project C:\Projects\Win32\Debug\TestActionMainMenu.exe faulted with message: 'system exception (code 0xc000041d) at 0x004ded2f'. Process Stopped. Use Step or Run to continue.
---------------------------

 

I've tried to put a breakpoint that leads to the error, but I haven't been able to find which Delphi method gets called when YouDao tries to read the TActionMainMenuBar item...

 

One more hint (I don't know if it's useful at all): when I do remote debugging (using PAServer), then program does not fail - it seems like the remote debugger prevents YouDao from reading the text in the TActionMainMenuBar (this was my first try). But when the Delphi IDE is installed on the local machine, then debugging gives the above result.


So my question is:
a) Has anybody experienced anything similar and could give a hint on how to search for a place to fix the issue in TActionMainMenuBar? Or just a hint for a better debugging strategy...
b) Alternatively suggest a replacement for TActionMainMenuBar (preferably something that looks like a standard menu)

 

Thanks,
Morten

Share this post


Link to post
Guest

@Morten Skovrup This problem is hard to diagnose and debug, i don't have an answer but may be i can shed some light on few things that might help you.

Disappearing running app silently, there only few scenarios for this and it might be traceable
1) Stack overflow, this is unlikely in your case but still worth investigation, there is two types of stack overflow exception one that triggered by touching the guarded pages at the end of the stack, and this one is recoverable, and the other one that doesn't touch these pages and go lower than them, this one will handled aggressively by the OS and Windows in most cases will kill the application silently, so check if you have recursive functions with huge local vars.
2) Do you use an EXE packers/protector ?, these protector will be so aggressive when detect external interaction and will self terminate silently, this is relevant as most live translation software will inject a DLL or start remote thread..., simply put they are doing stuff that irritate the protector.
3) Even if you don't have protected application, sometimes due the lack of valid signature, some antivirus software will be triggered on some event looks like random or just happen on specific chain of API calls combine that with translation software injecting some stuff and you will have AV that kill on the mood.
4) Can you build the smallest empty project and reproduce that behaviour ? may be with only TActionMainMenuBar !
5) The raised exception at GetIndex is not very useful without the stack dump to see how that had happen, eg, if youdao did inject a thread and for some reason GetIndex is not been called the main thread, or if TActionMainMenuBar is the culprit to begin with.
6) EurekaLog might be able to capture the stack or give you more detailed information, and for better report try to enable its memory manager, watch for it as it is slow, but you should not care about the speed before finding the AV.

And good luck.

Share this post


Link to post

@Kas Ob. Thanks a lot! - It helped narrow down the bug (looking in Call Stack helped - not sure why I didn't do that before...):

 

The error comes from Vcl.ABAccessibility.TActionBarAccessibility.accHitTest. I'm not sure why it's called when YouDao is enabled - else it doesn't get called.

 

In TActionBarAccessibility.accHitTest the following code generates the error (my comment) :

 

function TActionBarAccessibility.accHitTest(xLeft: Integer; yTop: Integer; out pvarChild: OleVariant): HResult;
var
  Pt: TPoint;
  Control: TControl;
begin
  VariantInit(pvarChild);
  TVarData(pvarChild).VType := VT_I4;
  Control := nil;
  Result := S_FALSE;
  if FActionClient is TActionBarItem then
  begin
    Pt := FActionClient.ActionBar.ScreenToClient(Point(xLeft, yTop));
    Control := FActionClient.ActionBar;
    if Control <> nil then
    begin
      pvarChild := TCustomActionControl(Control).ActionClient.Index + 1; //This line fails - TCustomActionControl(Control).ActionClient is not assigned!
      Result := S_OK;
    end;

 

If the "if Control <> nil then" line is replaced by:

 

if (Control <> nil) and (not (Control is TCustomActionMainMenuBar)) then

 

Then the error is gone 🙂 Again thanks a lot (and I'll make sure to create a bug-report in QualityCentral)

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×