SDK: AAHOOK_EXEC_MENU_COMMAND throws blank dialog

I'm having an issue with a Pre hook I've written for AAHOOK_EXEC_MENU_COMMAND. Specifically, I'm hooking on a native PW command (command id of IDMD_Redline). The hook works, but has the undesired effect of throwing a blank information dialog when the hook returns AAHOOK_ERROR (you hear the windows error chime, the information button shows in PWE bottom right, and clicking it shows a completely blank dialog titled "Information").

I built a clean version of the DLL with no functions other than the hook, thinking maybe another custom module was to blame, but the problem still persists. I've checked the Last error, and it is always 0. I've tried removing last errors, and still same problem. I have also tried using an Action hook and get the same result. Setting *pResult = TRUE didn't help either. At this point, I'm stumped.

Below is a simplified version built for testing that should demonstrate the problem. We're on PW V8i.

LONG AAAPIHOOK HookMenuCommand_Pre
(
LONG hookId, // i Hook Identifier
LONG hookType, // i Hook Function Type
AAPARAM aParam1, // i Parameter for Hook Function
AAPARAM aParam2, // i Parameter for Hook Function
AARESULT* pResult // o Return code of the hook function
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
TRACE (L"\nHookMenuCommand_Pre called...");
switch(aParam2)
{
case AAOPER_EXEC_MENUCMD:
TRACE (L"AAOPER_EXEC_MENUCMD...\n");
break;
default:
return AAHOOK_SUCCESS;
}
HDOCCMDPARAM hDocParam;
LPAADOC_ITEM lpDocItem;
#pragma warning( push )
#pragma warning( disable : 4312 )
LPAACMDPARAM pParam = (LPAACMDPARAM)aParam1;
#pragma warning( pop )
if (aParam2==AAOPER_EXEC_MENUCMD)
{
if (pParam->lCommandId == IDMD_REDLINE)
{
hDocParam = *((HDOCCMDPARAM*)pParam->lpParam);
lpDocItem = (LPAADOC_ITEM)aaApi_GetDocCmdParamElements(AADOCCMDPT_DOCUMENT1, hDocParam);
if (lpDocItem)
{
if(AfxMessageBox(L"Redline command intercepted.\n\nContinue?", MB_OKCANCEL)!=IDOK)
{
return AAHOOK_ERROR;
}
else return AAHOOK_SUCCESS;
}
}
}
TRACE (L"HookMenuCommand_Pre() finished...\n");
return AAHOOK_SUCCESS;
}
Parents
  • JG, do you get the OK / Cancel dialog box just before it errors?  It seems if you hit Cancel the code quits with AAHOOK_ERROR.

     

    <QUOTE>

    if (lpDocItem)
    {
    if(AfxMessageBox(L"Redline command intercepted.\n\nContinue?", MB_OKCANCEL)!=IDOK)
    {
    return AAHOOK_ERROR;
    }
    else return AAHOOK_SUCCESS;
    }
    }
    }

    </QUOTE>

  • DeanLyon:
    JG, do you get the OK / Cancel dialog box just before it errors?  It seems if you hit Cancel the code quits with AAHOOK_ERROR.

    Yes I get the popup dialog,which is what I want. I am trying to intercept the Redline command and only allow it in certain cases, based on some workflow stuff (left all that stuff out for testing). Basically what I want is the ability to cancel the command by clicking the Cancel button in the popup dialog

    For clarification, I get a blank Information dialog AFTER I click Cancel on my custom dialog. See the attached jpg to see what it looks like.

    Yaroslav Lobachevski:
    Jeff, you tell PW that an error has occured, but you do not set the error code. That is why the dialog is blank. In order to eat the command you should return AAHOOK_SUCCESS, to process the command - AAHOOK_CALL_DEFAULT.

    I've written several other Pre hooks that can return AAHOOK_ERROR, which is used as a means to prevent the action from executing, and I've never had to set/unset error codes before, and they don't give me a blank dialog afterward.

    Is this a requirement of AAHOOK_EXEC_MENU_COMMAND? if that is what is required, how would you go about this? What we are trying to do is get a confirmation from a user that they really want to run the Redline command under certain circumstances (the processing of those circumstances I've left out for simplicity here), and if they click Cancel, that gives them the way out of the command. Once they click Cancel, that should be the end of it; the command won't run and no other dialogs should appear.

    Please note that I post here on a voluntary basis and am not a Bentley employee. 

Reply
  • DeanLyon:
    JG, do you get the OK / Cancel dialog box just before it errors?  It seems if you hit Cancel the code quits with AAHOOK_ERROR.

    Yes I get the popup dialog,which is what I want. I am trying to intercept the Redline command and only allow it in certain cases, based on some workflow stuff (left all that stuff out for testing). Basically what I want is the ability to cancel the command by clicking the Cancel button in the popup dialog

    For clarification, I get a blank Information dialog AFTER I click Cancel on my custom dialog. See the attached jpg to see what it looks like.

    Yaroslav Lobachevski:
    Jeff, you tell PW that an error has occured, but you do not set the error code. That is why the dialog is blank. In order to eat the command you should return AAHOOK_SUCCESS, to process the command - AAHOOK_CALL_DEFAULT.

    I've written several other Pre hooks that can return AAHOOK_ERROR, which is used as a means to prevent the action from executing, and I've never had to set/unset error codes before, and they don't give me a blank dialog afterward.

    Is this a requirement of AAHOOK_EXEC_MENU_COMMAND? if that is what is required, how would you go about this? What we are trying to do is get a confirmation from a user that they really want to run the Redline command under certain circumstances (the processing of those circumstances I've left out for simplicity here), and if they click Cancel, that gives them the way out of the command. Once they click Cancel, that should be the end of it; the command won't run and no other dialogs should appear.

    Please note that I post here on a voluntary basis and am not a Bentley employee. 

Children
  • If you are trying to prevent the command under certain circumstances, then you may want to use an AA_ACTIONHOOK instead of a pre-hook.  It will give you much more control and allow you to prevent the action from happening without erroring.  With AA_ACTIONHOOK the error and success messages work a little differnetly and you have some options with allowing subsequent triggers to fire.
  • The point is when you return AAHOOK_ERROR in pre or action hook the API function returns failure code. Try it yourself, hook some function, call it and return AAHOOK_ERROR. In menu command executor case there is a handler, which checks if the command was successful. If not it shows the error dialog. However there is no error set. That why it is blank. I don't think it is a bug, because if a function failed without no reason there is something wrong about it.

    If your case I would rewrite action hook and return AAHOOK_SUCCESS to suppress the command, but AAHOOK_CALL_NEXT_IN_CHAIN to allow it. Of course you will get post hook even if the command was suppressed, but the function will return success code. You can read more about hooks in SDK ProjectWise Developer's Guide.

  • Action hook was the trick. Although I had tried that, I was still returning AAHOOK_ERROR instead of AAHOOK_SUCCESS to kill it.

    I knew that one, I really did...  *heading back to the dunce's corner*

    Please note that I post here on a voluntary basis and am not a Bentley employee. 

  • It appears that for a prehook for AAHOOK_EXEC_MENU_COMMAND, you need to set the value of pResult as well as setting the last error if you return AAHOOK_ERROR.  Something like this:

    *pResult = AAERR_USERERROR_FIRST+3;

    aaApi_SetLastError (*pResult, L"Your error message.", L"Details about the error.");

    return AAHOOK_ERROR;

    This doesn't appear to be true for Prehooks for most AAHOOK* types.  In fact, at least from the ones I've tried, setting the value of pResult and setting the last error is just ignored, but the action is prevented.  So, it appears that sometimes setting pResult is required (along with the last error), and sometimes it isn't.

    I'll see if I can find out more about the details as the SDK help isn't clear on this point.

    In the mean time, I think the solution offered and the one used - i.e. use an action hook instead, appears to be a good solution.