There are two macros defined in ..\2008\inc\arxentrypoint.h that
automagically registers commands in AcRxArxApp::On_kInitAppMsg.
I've been going through arxentrypoint.h, trying to understand how this code
works but there's one question I can't find and answer to.
I'm hoping that someone here might know the answer.
This is what I DO understand from the code in arxentrypoint.h:
A struct is defined that has all the info needed to register a command:
{code}
struct _ARXCOMMAND_ENTRY {
const ACHAR *pszCmdGroupName ;
const ACHAR *pszCmdGlobalName ;
const ACHAR *pszCmdLocalName ;
Adesk::Int32 commandFlags ;
AcRxFunctionPtr pCmdFct ;
AcEdUIContext *pUIContext ;
UINT localNameID ;
} ;
{code}
Three data sections are defined in the obj file:
{code}
#pragma section("ARXCOMMAND$__a", read, shared)
#pragma section("ARXCOMMAND$__z", read, shared)
#pragma section("ARXCOMMAND$__m", read, shared)
{code}
__pArxCmdMapEntryFirst is allocated to section ARXCOMMAND$__a
and __pArxCmdMapEntryLast is allocated to section ARXCOMMAND$__z:
{code}
extern "C" {
__declspec(selectany) __declspec(allocate("ARXCOMMAND$__a"))
_ARXCOMMAND_ENTRY* __pArxCmdMapEntryFirst =NULL ;
__declspec(selectany) __declspec(allocate("ARXCOMMAND$__z"))
_ARXCOMMAND_ENTRY* __pArxCmdMapEntryLast =NULL ;
}
{code}
Macros that export pointers to _ARXCOMMAND_ENTRY objects are defined:
{code}
#ifdef _WIN64
#define ACED_ARXCOMMAND_ENTRY_PRAGMA(group,globCmd)
__pragma(comment(linker, "/include:__pArxCmdMap_" #group #globCmd)) ;
#else
#define ACED_ARXCOMMAND_ENTRY_PRAGMA(group,globCmd)
__pragma(comment(linker, "/include:___pArxCmdMap_" #group #globCmd)) ;
#endif
{code}
Two macros that create an instance of _ARXCOMMAND_ENTRY, and then allocate a
pointer to the object within the ARXCOMMAND$__m section are defined:
{code}
#define ACED_ARXCOMMAND_ENTRY_AUTO(classname, group, globCmd, locCmd,
cmdFlags, UIContext) \
__declspec(selectany) _ARXCOMMAND_ENTRY __ArxCmdMap_##group##globCmd =
{ _RXST(#group), _RXST(#globCmd), _RXST(#locCmd), cmdFlags,
classname::##group ##globCmd, UIContext, -1 } ; \
extern "C" __declspec(allocate("ARXCOMMAND$__m")) __declspec(selectany)
_ARXCOMMAND_ENTRY* const __pArxCmdMap_##group##globCmd =
&__ArxCmdMap_##group##globCmd ; \
ACED_ARXCOMMAND_ENTRY_PRAGMA(group, globCmd)
#define ACED_ARXCOMMAND_ENTRYBYID_AUTO(classname, group, globCmd, locCmdId,
cmdFlags, UIContext) \
__declspec(selectany) _ARXCOMMAND_ENTRY __ArxCmdMap_##group##globCmd =
{ _RXST(#group), _RXST(#globCmd), NULL, cmdFlags, classname::##group
##globCmd, UIContext, locCmdId } ; \
extern "C" __declspec(allocate("ARXCOMMAND$__m")) __declspec(selectany)
_ARXCOMMAND_ENTRY* const __pArxCmdMap_##group##globCmd =
&__ArxCmdMap_##group##globCmd ; \
ACED_ARXCOMMAND_ENTRY_PRAGMA(group, globCmd)
{code}
When the arx application is loaded, interate through the pointers to
_ARXCOMMAND_ENTRY objects and register each command using
AcEdCommandStack::addCommand:
{code}
virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {
AcRx::AppRetCode retCode =AcRxDbxApp::On_kInitAppMsg (pkt) ;
_ARXCOMMAND_ENTRY **ppArxCmdMapEntryFirst =&__pArxCmdMapEntryFirst + 1 ;
_ARXCOMMAND_ENTRY **ppArxCmdMapEntryLast =&__pArxCmdMapEntryLast ;
ACHAR buffer [133] ;
for ( _ARXCOMMAND_ENTRY **ppEntry =ppArxCmdMapEntryFirst ; ppEntry <
ppArxCmdMapEntryLast ; ppEntry++ ) {
if ( *ppEntry != NULL ) {
if ( (*ppEntry)->pszCmdLocalName == NULL )
::LoadString (m_hdllInstance, (*ppEntry)->localNameID, buffer,
132) ;
acedRegCmds->addCommand (
(*ppEntry)->pszCmdGroupName,
(*ppEntry)->pszCmdGlobalName,
(*ppEntry)->pszCmdLocalName == NULL ? buffer :
(*ppEntry)->pszCmdLocalName,
(*ppEntry)->commandFlags,
(*ppEntry)->pCmdFct,
(*ppEntry)->pUIContext,
-1,
((*ppEntry)->commandFlags & ACRX_CMD_SESSION) ? NULL :
m_hdllInstance,
NULL
) ;
}
}
return (retCode) ;
}
{code}
This all seems very straight forward.
There's just one thing that I don't understand.
How does &__pArxCmdMapEntryFirst + 1 and &__pArxCmdMapEntryLast point to the
first and last _ARXCOMMAND_ENTRY*?
I would think that #pragma section would place sections in an obj file one
after the next in the order they appear,
so if the sections were instead defined as:
{code}
#pragma section("ARXCOMMAND$__a", read, shared)
#pragma section("ARXCOMMAND$__m", read, shared)
#pragma section("ARXCOMMAND$__z", read, shared)
{code}
then &__pArxCmdMapEntryFirst + 1 would point to the first _ARXCOMMAND_ENTRY*
in section ARXCOMMAND$__m
and &__pArxCmdMapEntryLast would be the first address after section
ARXCOMMAND$__m
But the sections are actually defined as:
{code}
#pragma section("ARXCOMMAND$__a", read, shared)
#pragma section("ARXCOMMAND$__z", read, shared)
#pragma section("ARXCOMMAND$__m", read, shared)
{code}
which would make &__pArxCmdMapEntryFirst + 1 point to &__pArxCmdMapEntryLast
and &__pArxCmdMapEntryLast point to the address before the first
_ARXCOMMAND_ENTRY* in section ARXCOMMAND$__m
I'm confused...