Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2125 lines
48 KiB

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1989 Microsoft Corporation
Module Name:
comsrv.cxx
Abstract:
Generates com class server framework file
Notes:
History:
----------------------------------------------------------------------------*/
/****************************************************************************
* include files
***************************************************************************/
#include "becls.hxx"
#pragma hdrstop
#include "buffer.hxx"
/****************************************************************************
* local definitions
***************************************************************************/
/****************************************************************************
* externs
***************************************************************************/
extern CMD_ARG * pCommand;
#include "szbuffer.h"
CG_STATUS
CG_COM_CLASS::GenComOuterUnknown(
CCB * pCCB,
char * pDesignatedClassName )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the outer IUnknown for a COM class
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
CG_IUNKNOWN_OBJECT_INTERFACE * pIUnknown = pCCB->GetIUnknownCG();
node_object * pClass = (node_object *) GetType();
MEM_ITER Iter( (node_interface *)pIUnknown->GetType() );
// get pointers to all the methods
named_node * pQI;
named_node * pAR;
named_node * pRel;
while ( ( pQI = Iter.GetNext() )->NodeKind() != NODE_PROC )
;
while ( ( pAR = Iter.GetNext() )->NodeKind() != NODE_PROC )
;
while ( ( pRel = Iter.GetNext() )->NodeKind() != NODE_PROC )
;
pStream->NewLine();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write( "// IUnknown implementation for class: " );
pStream->Write( pName );
pStream->NewLine(2);
////////////////////////////////////////////////////////////////////////
// QueryInterface
pQI->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, pClass );
// print a (nearly) empty function body
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("return ");
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write("pUnkOuter->QueryInterface( riid, ppvObject );");
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
////////////////////////////////////////////////////////////////////////
// AddRef
pAR->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, pClass );
// print a (nearly) empty function body
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("return ");
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write("pUnkOuter->AddRef();");
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
////////////////////////////////////////////////////////////////////////
// Release
pRel->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, pClass );
// print a (nearly) empty function body
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("return ");
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write("pUnkOuter->Release();");
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::GenComInnerUnknown(
CCB * pCCB,
char * pDesignatedClassName )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the inner IUnknown for a COM class
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
CG_IUNKNOWN_OBJECT_INTERFACE * pIUnknown = pCCB->GetIUnknownCG();
node_object * pClass = (node_object *) GetType();
MEM_ITER Iter( (node_interface *)pIUnknown->GetType() );
ITERATOR I;
CSzBuffer ExpandedName;
node_object Alternate_Class = *pClass;
char * pMemberQualifier = pName;
BOOL fFirstItf = TRUE;
CG_OBJECT_INTERFACE * pIntf;
char * pItfName;
// make the class name for the inner unknown
ExpandedName.Append( pName );
ExpandedName.Append( "_Internal_Unknown" );
Alternate_Class.SetSymName( ExpandedName );
// get pointers to all the methods
named_node * pQI;
named_node * pAR;
named_node * pRel;
while ( ( pQI = Iter.GetNext() )->NodeKind() != NODE_PROC )
;
while ( ( pAR = Iter.GetNext() )->NodeKind() != NODE_PROC )
;
while ( ( pRel = Iter.GetNext() )->NodeKind() != NODE_PROC )
;
pStream->NewLine();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write( "// Internal IUnknown implementation for class: " );
pStream->Write( pName );
pStream->NewLine(2);
if ( pDesignatedClassName )
{
pMemberQualifier = pDesignatedClassName;
}
////////////////////////////////////////////////////////////////////////
// QueryInterface
pQI->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, &Alternate_Class );
// print a (nearly) empty function body
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("HRESULT hr = E_NOINTERFACE;");
pStream->NewLine(2);
pStream->Write("*ppvObject = 0;");
pStream->NewLine(2);
// get all provided interfaces,
GetListOfUniqueBaseInterfaces( I );
// now unmark them all
for ( ITERATOR_INIT(I); ITERATOR_GETNEXT( I, pIntf ); pIntf->MarkVisited(FALSE) )
;
// for now, just do a linear search; see OutInfoSearchRoutine for further scheme
for ( ITERATOR_INIT(I); ITERATOR_GETNEXT( I, pIntf ); pIntf->MarkVisited(FALSE) )
{
if ( pIntf->IsIUnknown() )
continue;
if ( pIntf->GetCGID() == ID_CG_COM_CLASS )
continue;
pItfName = pIntf->GetSymName();
if ( fFirstItf )
{
pStream->Write("if ( IsEqualGUID( riid, IID_IUnknown ) || ");
fFirstItf = FALSE;
}
else
{
pStream->Write("else if ( ");
}
pStream->Write("IsEqualGUID( riid, IID_");
pStream->Write( pItfName );
pStream->Write(" ) )");
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("*ppvObject = GET_MIDL_INTERFACE( ");
pStream->Write( pItfName );
pStream->Write( ", " );
pStream->Write( pName );
pStream->Write( ", ");
pStream->Write( pMemberQualifier );
pStream->Write( " );");
pStream->NewLine();
pStream->Write("hr = S_OK;");
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
}
pStream->Write( "if ( FAILED( hr ) )");
pStream->NewLine();
pStream->Write( " hr = GET_MIDL_CLASS( " );
pStream->Write( pName );
pStream->Write( ", " );
pStream->Write( pMemberQualifier );
pStream->Write( " )" );
pStream->NewLine();
pStream->Write( " ->QueryInterfaceExtension( riid, ppvObject );" );
pStream->NewLine();
pStream->Write( "else" );
pStream->NewLine();
pStream->Write(" AddRef();");
pStream->NewLine();
pStream->Write("return hr;");
pStream->NewLine(2);
pStream->Write( '}' );
pStream->IndentDec();
////////////////////////////////////////////////////////////////////////
// AddRef
pStream->NewLine( 2 );
pAR->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, &Alternate_Class );
// print a (nearly) empty function body
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("IncrementRefCount( ");
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write("m_ulRefCnt );");
pStream->NewLine();
pStream->Write("return ");
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write("m_ulRefCnt;");
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
static STRING_BLOCK ReleaseCommonPart =
{
"if ( ulReturned )",
" return ulReturned;",
"",
"// object refcount has dropped to 0",
"",
"//decrement the object count",
"if(DecrementRefCount(gLifetimeInfo.ulObjectRefCnt) == 0)",
"{",
" //The last object in this module has been destroyed.",
" if ( gLifetimeInfo.pfnObjectCleanUpRtn )",
" (*gLifetimeInfo.pfnObjectCleanUpRtn)();",
"}",
"",
"//decrement the module count",
"if(DecrementRefCount(gLifetimeInfo.ulModuleRefCnt) == 0)",
"{",
" //The last object in this module has been destroyed.",
" if ( gLifetimeInfo.pfnModuleCleanUpRtn )",
" (*gLifetimeInfo.pfnModuleCleanUpRtn)();",
"}",
0
};
////////////////////////////////////////////////////////////////////////
// Release
pRel->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, &Alternate_Class );
// print the function body
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("unsigned long ulReturned = DecrementRefCount( ");
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write("m_ulRefCnt );");
pStream->WriteBlock( ReleaseCommonPart );
pStream->NewLine(2);
pStream->Write("delete GET_MIDL_CLASS( ");
pStream->Write( pName );
pStream->Write( ", " );
pStream->Write( pMemberQualifier );
pStream->Write( " );" );
pStream->NewLine();
pStream->Write( "return 0;" );
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::GenComClassConstructor(
CCB * pCCB,
char * pDesignatedClassName )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the constructor for a COM class
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write("// Constructor");
pStream->NewLine();
pStream->Write("// Override InitInstance to do your own initialization");
pStream->NewLine(2);
pStream->Write( pName );
pStream->Write( "::" );
pStream->Write( pName );
pStream->Write( "( IUnknown * pUnknownOuter )" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write( "// support aggregation");
pStream->NewLine();
pStream->Write( "if ( !pUnknownOuter )");
pStream->IndentInc();
pStream->NewLine();
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write( "pUnkOuter = (IUnknown*) &");
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write( "m_UnkInner;");
pStream->IndentDec();
pStream->NewLine();
pStream->Write( "else");
pStream->IndentInc();
pStream->NewLine();
if ( pDesignatedClassName )
{
pStream->Write( pDesignatedClassName );
pStream->Write( "::" );
}
pStream->Write( "pUnkOuter = pUnknownOuter;");
pStream->IndentDec();
pStream->NewLine(2);
pStream->Write( "CONSTRUCT_INNER_UNKNOWN( ");
pStream->Write( pName );
pStream->Write( ", " );
pStream->Write( (pDesignatedClassName) ? pDesignatedClassName : pName );
pStream->Write( " );" );
pStream->NewLine(2);
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::GenComClassIUnknown(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the IUnknown for a COM class
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
pCCB->SetInterfaceCG( this );
pStream->NewLine();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write( "// IUnknown implementations for class: " );
pStream->Write( pName );
pStream->NewLine(2);
// generate the outer unknown methods that defer to the punkOuter
GenComOuterUnknown( pCCB, NULL );
// generate the inner unknown methods
GenComInnerUnknown( pCCB, NULL );
// generate the constructor
GenComClassConstructor( pCCB, NULL );
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::GenComClassFactory(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the class factory for a COM class
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
pCCB->SetInterfaceCG( this );
pStream->NewLine();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write( "// ClassFactory implementation for class: " );
pStream->Write( pName );
pStream->NewLine(2);
// make the CreateInstance routine
GenComClassFactoryCreateInstance( pCCB );
// make the tables, and construct the object and the info
GenComClassFactoryTables( pCCB );
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::GenComClassFactoryCreateInstance(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the class factory for a COM class
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
CG_OBJECT_INTERFACE * pIClassf = pCCB->GetIClassfCG();
node_interface * pIClassfNode = (node_interface*)pIClassf->GetType();
CG_OBJECT_PROC * pCreateInstance = (CG_OBJECT_PROC *) pIClassf->GetChild();
node_proc * pCreateInstNode = (node_proc*) pCreateInstance->GetType();
node_call_as * pAttr;
if ( pAttr = (node_call_as *) pCreateInstNode->GetAttribute( ATTR_CALL_AS ) )
{
pCreateInstNode = (node_proc *) pAttr->GetCallAsType();
}
// a new node_proc (on the stack)
node_proc RenamedProc( pCreateInstNode );
CSzBuffer NewName;
NewName.Append( pName );
NewName.Append( "_Factory_CreateInstance" );
RenamedProc.SetSymName( NewName );
RenamedProc.PrintType( PRT_THIS_POINTER | PRT_PROC_PROTOTYPE, pStream, NULL, pIClassfNode );
// print the function body
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write("HRESULT hr = E_OUTOFMEMORY;");
pStream->NewLine();
pStream->Write( pName );
pStream->Write(" * pInstance;");
pStream->NewLine(2);
pStream->Write("*ppvObject = 0;");
pStream->NewLine(2);
pStream->Write("pInstance = new ");
pStream->Write( pName );
pStream->Write( "( pUnkOuter );");
static STRING_BLOCK CreateInstanceCommonPart =
{
"if ( pInstance )",
" {",
" hr = pInstance->InitInstance( pUnkOuter, riid, ppvObject );",
" if ( FAILED( hr ) )",
" {",
" delete pInstance;",
" return hr;",
" }",
"",
" //increment the object count.",
" //The module count will keep this process alive until all",
" //objects in this module are released.",
" IncrementRefCount( gLifetimeInfo.ulModuleRefCnt );",
" IncrementRefCount( gLifetimeInfo.ulObjectRefCnt );",
" hr = pInstance->QueryInterface( riid, (void**)ppvObject);",
" }",
"",
"return hr;",
0
};
pStream->NewLine();
pStream->WriteBlock( CreateInstanceCommonPart );
pStream->NewLine();
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::GenComClassFactoryTables(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the class factory for a COM class
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
pStream->NewLine(2);
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write( "// important data structures for the class factory and server" );
// print the vtable
pStream->NewLine(2);
pStream->Write( "const struct Midl_Factory_Object_Vtbl " );
pStream->Write( pName );
pStream->Write( "_Factory_Object_Vtbl =" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write( "&Generic_Midl_Factory_QueryInterface," );
pStream->NewLine();
pStream->Write( "&Generic_Midl_Factory_AddRef," );
pStream->NewLine();
pStream->Write( "&Generic_Midl_Factory_Release," );
pStream->NewLine();
pStream->Write( '&' );
pStream->Write( pName );
pStream->Write( "_Factory_CreateInstance," );
pStream->NewLine();
pStream->Write( "&Generic_Midl_Factory_LockServer," );
pStream->NewLine();
pStream->Write( "};" );
pStream->IndentDec();
// print the object instance
pStream->NewLine(2);
pStream->Write( "const CMidlFactory_Object " );
pStream->Write( pName );
pStream->Write( "_Factory_Object =" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write( '&' );
pStream->Write( pName );
pStream->Write( "_Factory_Object_Vtbl," );
pStream->NewLine();
pStream->Write( "&gLifetimeInfo" );
pStream->NewLine();
pStream->Write( "};" );
pStream->IndentDec();
// print the object pointer instance
pStream->NewLine(2);
//pStream->Write( "const " );
pStream->Write( pName );
pStream->Write( "_Factory * p" );
pStream->Write( pName );
pStream->Write( "_Factory = ");
pStream->IndentInc();
pStream->IndentInc();
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '(' );
pStream->Write( pName );
pStream->Write( "_Factory *) &" );
pStream->Write( pName );
pStream->Write( "_Factory_Object;" );
pStream->IndentDec();
pStream->IndentDec();
pStream->IndentDec();
// print the factory info block
pStream->NewLine(2);
pStream->Write( "// here is the class factory info block" );
pStream->NewLine();
pStream->Write( "Midl_Class_Factory_Info " );
pStream->Write( pName );
pStream->Write( "_Factory_Info =" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
pStream->Write( '\"' );
pStream->Write( pName );
pStream->Write( "\"," );
pStream->NewLine();
pStream->Write( "&CLSID_" );
pStream->Write( pName );
pStream->Write( ',' );
pStream->NewLine();
pStream->Write( "(CGenericMidlClassFactory** )&p" );
pStream->Write( pName );
pStream->Write( "_Factory" );
pStream->NewLine();
pStream->Write( "};" );
pStream->IndentDec();
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::GenComClassServer(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the class
implementation for a COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
const char * pName = GetSymName();
CG_OBJECT_INTERFACE * pIntf;
ITERATOR I;
MIDL_TOKEN FlagToken( START_CLASS_TOKEN, pName );
pCCB->SetInterfaceCG( this );
pStream->NewLine();
pStream->EmitToken( FlagToken );
pStream->NewLine();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write( "// COM class server for class: " );
pStream->Write( pName );
pStream->NewLine();
// go through all the methods, emitting shell code
// for IUnknown, emit special code
// for con/destructors, emit special code
// go through all base interfaces, printing them and THEIR base
// interfaces, avoiding duplicates...
GetListOfUniqueBaseInterfaces( I );
// now print them all, unmarking as we go
for ( ITERATOR_INIT(I); ITERATOR_GETNEXT( I, pIntf ); pIntf->MarkVisited(FALSE) )
{
CSzBuffer NameBuffer;
char * pIntfName;
if ( pIntf->IsIUnknown() )
continue;
pIntfName = pIntf->GetInterfaceName();
NameBuffer.Append( pName );
NameBuffer.Append( "::" );
NameBuffer.Append( pIntfName );
pStream->NewLine( 2 );
pStream->EmitToken( MIDL_TOKEN( START_CLASS_METHODS_TOKEN, NameBuffer ) );
pStream->NewLine();
pStream->Write( pDelimiterString );
pStream->NewLine();
pStream->Write("// Member functions from: ");
pStream->Write( ( pIntf->GetCGID() == ID_CG_COM_CLASS ) ? "Class " : "Interface " );
pStream->Write( pIntfName );
pStream->NewLine();
pIntf->GenComClassServerMembers( pCCB );
}
pStream->NewLine( 2 );
pStream->Write( pDelimiterString );
pStream->NewLine( 2 );
pStream->EmitToken( MIDL_TOKEN( CLASS_DESTRUCTOR_TOKEN, pName ) );
pStream->NewLine();
pStream->Write("// virtual destructor");
pStream->NewLine();
pStream->Write( pName );
pStream->Write( "::~" );
pStream->Write( pName );
pStream->Write( "()" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine(2);
pStream->Write( "// TODO: fill in any destructor action" );
pStream->NewLine(2);
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine();
pStream->NewLine();
pStream->NewLine();
FlagToken.SetTokenType( END_CLASS_TOKEN );
pStream->EmitToken( FlagToken );
pStream->Write( '\n' );
return CG_OK;
}
CG_STATUS
CG_COM_CLASS::ReGenComClassServer(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for the class
implementation for a COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
RW_ISTREAM * pStream = (RW_ISTREAM *)pCCB->GetStream();
const char * pName = GetSymName();
CG_OBJECT_INTERFACE * pIntf;
ITERATOR I;
MIDL_TOKEN FoundToken;
MIDL_TOKEN FlagToken( START_CLASS_TOKEN, pName );
pCCB->SetInterfaceCG( this );
pStream->SaveToNextMidlToken( FoundToken );
if ( FoundToken.GetTokenType() != START_CLASS_TOKEN )
{
assert( !"bad token found" );
}
pStream->EmitToken( FlagToken );
pStream->NewLine();
// go through all the methods, emitting shell code
// for IUnknown, emit special code
// for con/destructors, emit special code
// go through all base interfaces, printing them and THEIR base
// interfaces, avoiding duplicates...
GetListOfUniqueBaseInterfaces( I );
// now print them all, unmarking as we go
for ( ITERATOR_INIT(I); ITERATOR_GETNEXT( I, pIntf ); pIntf->MarkVisited(FALSE) )
{
CSzBuffer NameBuffer;
char * pIntfName;
if ( pIntf->IsIUnknown() )
continue;
pStream->SaveToNextMidlToken( FoundToken );
if ( FoundToken.GetTokenType() != START_CLASS_METHODS_TOKEN )
{
assert( !"bad token found" );
}
pIntfName = pIntf->GetInterfaceName();
NameBuffer.Append( pName );
NameBuffer.Append( "::" );
NameBuffer.Append( pIntfName );
pStream->EmitToken( MIDL_TOKEN( START_CLASS_METHODS_TOKEN, NameBuffer ) );
pStream->NewLine();
pIntf->ReGenComClassServerMembers( pCCB );
}
pStream->SaveToNextMidlToken( FoundToken );
if ( FoundToken.GetTokenType() != CLASS_DESTRUCTOR_TOKEN )
{
assert( !"bad token found" );
}
pStream->EmitToken( MIDL_TOKEN( CLASS_DESTRUCTOR_TOKEN, pName ) );
pStream->NewLine();
pStream->SaveToNextMidlToken( FoundToken );
if ( FoundToken.GetTokenType() != END_CLASS_TOKEN )
{
assert( !"bad token found" );
}
FlagToken.SetTokenType( END_CLASS_TOKEN );
pStream->EmitToken( FlagToken );
pStream->Write( '\n' );
return CG_OK;
}
CG_STATUS
CG_OBJECT_INTERFACE::GenComClassServerMembers(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
CG_ITERATOR I;
CG_OBJECT_PROC * pCG;
if( !GetMembers( I ) )
{
return CG_OK;
}
while( ITERATOR_GETNEXT( I, pCG ) )
{
pCG->GenComClassMemberFunction( pCCB );
}
return CG_OK;
}
CG_STATUS
CG_OBJECT_INTERFACE::ReGenComClassServerMembers(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
CG_ITERATOR I;
CG_OBJECT_PROC * pCG;
if( !GetMembers( I ) )
{
return CG_OK;
}
while( ITERATOR_GETNEXT( I, pCG ) )
{
pCG->ReGenComClassMemberFunction( pCCB );
}
return CG_OK;
}
CG_STATUS
CG_OBJECT_PROC::GenComClassMemberFunction(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
node_proc * pTypeNode = (node_proc *) GetType();
ISTREAM * pStream = pCCB->GetStream();
node_skl * pClass = pCCB->GetInterfaceCG()->GetType();
CSzBuffer NameBuffer;
NameBuffer.Append( pClass->GetSymName() );
NameBuffer.Append( "::" );
NameBuffer.Append( pTypeNode->GetSymName() );
MIDL_TOKEN FlagToken( START_METHOD_TOKEN, NameBuffer );
pStream->NewLine();
pStream->EmitToken( FlagToken );
pStream->NewLine(2);
pTypeNode->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, pClass );
// print a (nearly) empty function body
pStream->IndentInc();
pStream->NewLine(2);
FlagToken.SetTokenType( START_METHOD_BODY_TOKEN );
pStream->EmitToken( FlagToken );
pStream->NewLine();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine(2);
pStream->Write("// uncomment the below macro if you make calls out and may get");
pStream->NewLine();
pStream->Write("// a Release() while blocked on the call.");
pStream->NewLine();
pStream->Write("// MAKES_REENTERABLE_CALLS");
pStream->NewLine(2);
pStream->Write("// TODO: Fill in this method with your code");
pStream->NewLine(2);
pStream->Write("return S_OK;");
pStream->NewLine(2);
pStream->Write( '}' );
pStream->IndentDec();
pStream->NewLine( 2 );
return CG_OK;
}
CG_STATUS
CG_OBJECT_PROC::ReGenComClassMemberFunction(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
node_proc * pTypeNode = (node_proc *) GetType();
RW_ISTREAM * pStream = (RW_ISTREAM*)pCCB->GetStream();
node_skl * pClass = pCCB->GetInterfaceCG()->GetType();
MIDL_TOKEN FoundToken;
CSzBuffer NameBuffer;
NameBuffer.Append( pClass->GetSymName() );
NameBuffer.Append( "::" );
NameBuffer.Append( pTypeNode->GetSymName() );
pStream->SaveToNextMidlToken( FoundToken );
if ( FoundToken.GetTokenType() != START_METHOD_TOKEN )
{
assert( !"bad token found" );
}
MIDL_TOKEN FlagToken( START_METHOD_TOKEN, NameBuffer );
pStream->EmitToken( FlagToken );
pStream->NewLine(2);
pTypeNode->PrintType( PRT_QUALIFIED_NAME | PRT_PROC_PROTOTYPE, pStream, NULL, pClass );
// print a (nearly) empty function body
pStream->IndentInc();
pStream->NewLine(2);
pStream->DiscardToNextMidlToken( FoundToken );
if ( FoundToken.GetTokenType() != START_METHOD_BODY_TOKEN )
{
assert( !"bad token found" );
}
FlagToken.SetTokenType( START_METHOD_BODY_TOKEN );
pStream->EmitToken( FlagToken );
pStream->IndentDec();
pStream->NewLine();
return CG_OK;
}
CG_COM_SERVER::CG_COM_SERVER(
node_com_server * pI,
ITERATOR * pBCG
)
: CG_NDR( pI, XLAT_SIZE_INFO() )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
constructor for a com server DLL or EXE base class.
Arguments:
pI - a pointer to the node in the typegraph.
Return Value:
none.
Notes:
----------------------------------------------------------------------------*/
{
pBaseCGList = pBCG;
}
CG_STATUS
CG_COM_SERVER::GenClassFactoryArray(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the data structures for the _g.cxx file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
ITERATOR * pClassList = GetClassList();
CG_COM_CLASS * pClassCG;
pStream->NewLine();
pStream->Write( "// here are the class factories all connected together" );
pStream->NewLine();
pStream->Write( "const Midl_Class_Factory_Info * Midl_Class_Factory_Array[] =" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
ITERATOR_INIT( *pClassList );
while ( ITERATOR_GETNEXT ( *pClassList, pClassCG ) )
{
pStream->NewLine();
pStream->Write( '&' );
pStream->Write( pClassCG->GetSymName() );
pStream->Write( "_Factory_Info," );
}
pStream->NewLine();
pStream->Write( "0 // terminator" );
pStream->NewLine();
pStream->Write( "};" );
pStream->IndentDec();
pStream->NewLine();
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_DLL::GenDataStructures(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the data structures for the _g.cxx file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
unsigned long ulClassCnt = ITERATOR_GETCOUNT( *GetClassList() );
pStream->NewLine();
pStream->Write( "// the number of classes provided by this DLL" );
pStream->NewLine();
pStream->Write( "const unsigned long ulClassCnt = " );
pStream->WriteNumber( "%d", ulClassCnt );
pStream->Write( ";" );
pStream->NewLine(2);
GenClassFactoryArray( pCCB );
static STRING_BLOCK DataStructs =
{
"// lifetime information for the module (dll) containing this object",
"struct MidlModuleLifetimeInfo gLifetimeInfo =",
" {",
" 0, // ulModuleRefCnt",
" NULL,",
" 0, // ulObjectRefCnt",
" NULL",
" };",
"",
"HINSTANCE hProxyDll = 0;",
0
};
pStream->NewLine();
pStream->WriteBlock( DataStructs );
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_DLL::GenEntryPts(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the DllGetClassObject and DllCanUnloadNow code for an inprocserver32.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
#if 0
ITERATOR * pClassList = GetClassList();
CG_COM_CLASS * pClassCG;
#endif
static STRING_BLOCK DGCO_header =
{
" REFCLSID rclsid,",
" REFIID riid,",
" void ** ppv )",
"{",
" HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;",
" unsigned long idx;",
"",
" // lookup customized for this DLL",
0
};
pStream->NewLine();
pStream->Write( "EXTERN_C HRESULT STDAPICALLTYPE " );
pStream->Write( pName );
pStream->Write( "_DllGetClassObject (" );
pStream->NewLine();
pStream->WriteBlock( DGCO_header );
pStream->IndentInc();
// tbd - for now, just do linear search
static STRING_BLOCK DGCO_search =
{
"for( idx = 0; idx < ulClassCnt; idx++ )",
" {",
" if ( IsEqualGUID( rclsid, *Midl_Class_Factory_Array[idx]->pFactoryID ) )",
" {",
" hr = (*Midl_Class_Factory_Array[idx]->ppFactory)->QueryInterface( riid, ppv );",
" break;",
" }",
" }",
0
};
pStream->WriteBlock( DGCO_search );
pStream->IndentDec();
static STRING_BLOCK DGCO_trailer =
{
" // fail case",
" if ( FAILED (hr) )",
" *ppv = 0;",
" return hr;",
"}",
"",
0
};
pStream->NewLine();
pStream->WriteBlock( DGCO_trailer );
static STRING_BLOCK DCUN =
{
"{",
" return (gLifetimeInfo.ulModuleRefCnt) ? S_FALSE : S_OK;",
"}",
0
};
pStream->NewLine();
pStream->Write( "EXTERN_C HRESULT STDAPICALLTYPE " );
pStream->Write( pName );
pStream->Write( "_DllCanUnloadNow()" );
pStream->NewLine();
pStream->WriteBlock( DCUN );
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_DLL::GenRegistryEntryPts(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the dllmain, RegisterServer and UnRegisterServer entry points.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
pStream->NewLine(2);
static STRING_BLOCK DllEntryPt =
{
" HINSTANCE hinstDLL,",
" DWORD fdwReason,",
" LPVOID lpvReserved)",
"{",
" if(fdwReason == DLL_PROCESS_ATTACH)",
" hProxyDll = hinstDLL;",
" return TRUE;",
"}",
0
};
pStream->NewLine();
pStream->Write( "EXTERN_C BOOL WINAPI " );
pStream->Write( pName );
pStream->Write( "_DllEntryPoint(" );
pStream->NewLine();
pStream->WriteBlock( DllEntryPt );
static STRING_BLOCK DllRegSvr =
{
"{",
" return S_OK;",
" //tbd return NdrDllRegisterServer(hProxyDll, pProxyFileList, pClsID);",
"}",
0
};
pStream->NewLine(2);
pStream->Write( "EXTERN_C HRESULT STDAPICALLTYPE " );
pStream->Write( pName );
pStream->Write( "_DllRegisterServer()" );
pStream->NewLine();
pStream->WriteBlock( DllRegSvr );
static STRING_BLOCK DllUnRegSvr =
{
"{",
" return S_OK;",
" //tbd return NdrDllUnregisterServer(hProxyDll, pProxyFileList, pClsID);",
"}",
0
};
pStream->NewLine(2);
pStream->Write( "EXTERN_C HRESULT STDAPICALLTYPE " );
pStream->Write( pName );
pStream->Write( "_DllUnregisterServer()" );
pStream->NewLine();
pStream->WriteBlock( DllRegSvr );
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_DLL::GenDllDefFile(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the def file for the InprocServer32.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
pStream->NewLine();
pStream->Write( "; to override the functionality of one of these entries, point" );
pStream->NewLine();
pStream->Write( "; the export to your routine (which may call the generated routine)" );
pStream->NewLine(2);
pStream->Write( "LIBRARY" );
pStream->NewLine( 2 );
pStream->Write( "DESCRIPTION \'" );
pStream->Write( pName );
pStream->Write( " InprocServer32 DLL\'" );
pStream->NewLine( 2 );
pStream->Write( "EXPORTS" );
pStream->IndentInc();
pStream->NewLine( 2 );
pStream->Write( "DllGetClassObject = " );
pStream->Write( pName );
pStream->Write( "_DllGetClassObject" );
pStream->NewLine();
pStream->Write( "DllCanUnloadNow = " );
pStream->Write( pName );
pStream->Write( "_DllCanUnloadNow" );
pStream->NewLine();
pStream->Write( "DllRegisterServer = " );
pStream->Write( pName );
pStream->Write( "_DllRegisterServer" );
pStream->NewLine();
pStream->Write( "DllUnregisterServer = " );
pStream->Write( pName );
pStream->Write( "_DllUnregisterServer" );
pStream->NewLine();
pStream->Write( "DllMain = " );
pStream->Write( pName );
pStream->Write( "_DllEntryPoint" );
pStream->IndentDec();
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_DLL::GenCode(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
GenDataStructures( pCCB );
GenEntryPts( pCCB );
GenRegistryEntryPts( pCCB );
pCCB->GetStream()->Write('\n');
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_EXE::GenCode(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
GenCleanupRoutines( pCCB );
GenDataStructures( pCCB );
GenIteratorClass( pCCB );
GenClassRegisterRevoke( pCCB );
GenRegistryCode( pCCB );
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_EXE::GenMain(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_EXE::GenCleanupRoutines(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the clean-up routines for the _e.cxx file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
static STRING_BLOCK CleanupRtns =
{
"///////////////////////////////////////////////////////////////",
"// cleanup-on-Release routines",
"//",
"// clean-up routine for the entire module",
"// this is called when all the objects AND all",
"// the class factories are released",
"void __stdcall ModuleUnReferenced()",
"{",
" // no factories or objects remaining, go away",
" PostQuitMessage(0);",
"}",
"",
"// clean-up routine for the objects in the module",
"// this is called when all live objects other than ",
"// the class factories are released",
"void __stdcall ObjectsUnReferenced()",
"{",
" // revoke all the registered classes",
" UnregisterAllClassFactories();",
"}",
0
};
pStream->NewLine();
pStream->WriteBlock( CleanupRtns );
pStream->NewLine(3);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_EXE::GenDataStructures(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the data structures for the _g.cxx file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
unsigned long ulClassCnt = ITERATOR_GETCOUNT( *GetClassList() );
pStream->NewLine();
pStream->Write( "// the number of classes provided by this DLL" );
pStream->NewLine();
pStream->Write( "const unsigned long ulClassCnt = " );
pStream->WriteNumber( "%d", ulClassCnt );
pStream->Write( ";" );
pStream->NewLine(2);
GenClassFactoryArray( pCCB );
static STRING_BLOCK DataStructs =
{
"// lifetime information for the module (dll) containing this object",
"struct MidlModuleLifetimeInfo gLifetimeInfo =",
" {",
" 0, // ulModuleRefCnt",
" &ModuleUnReferenced,",
" 0, // ulObjectRefCnt",
" &ObjectsUnReferenced",
" };",
0
};
pStream->NewLine();
pStream->WriteBlock( DataStructs );
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_EXE::GenIteratorClass(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the custom iterator class for the _e.cxx file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
static STRING_BLOCK IterClass =
{
"// a special iterator class over these class factories",
"class Exe_Class_Iterator : public Midl_Class_Factory_Iterator",
" {",
"public:",
" // just a convenience constructor",
" Exe_Class_Iterator()",
" : Midl_Class_Factory_Iterator(",
" Midl_Class_Factory_Array, ",
" ulClassCnt )",
" {",
" }",
"",
" void Init()",
" {",
" Midl_Class_Factory_Iterator::Init(",
" Midl_Class_Factory_Array, ",
" ulClassCnt );",
" }",
"",
" };",
0
};
pStream->NewLine();
pStream->WriteBlock( IterClass );
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_EXE::GenClassRegisterRevoke(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the clean-up routines for the _e.cxx file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
static STRING_BLOCK RegisterRevokeCode =
{
"// these are the handles returned by the CoRegisterClassObject",
"DWORD dwRegisterHandles[ulClassCnt] = {0};",
"",
"// flag to make sure we only call CoRevokeClassObject once",
"int fFactoriesRevoked = TRUE;",
"",
"// do a CoRevokeClassObject on all the live class factories",
"HRESULT __stdcall UnregisterAllClassFactories()",
"{",
" HRESULT hr;",
"",
" // if we already revoked all the objects, do nothing",
" if ( fFactoriesRevoked )",
" return S_OK;",
"",
" Exe_Class_Iterator Iter;",
" Midl_Class_Factory_Info * pCur;",
" DWORD * pdwHandle = dwRegisterHandles;",
"",
" // revoke all the class factories",
" while ( pCur = Iter.GetNext() )",
" {",
" hr = CoRevokeClassObject(*pdwHandle);",
" if ( FAILED(hr) )",
" return hr;",
" pdwHandle++;",
" }",
"",
" fFactoriesRevoked = TRUE;",
" return hr;",
"}",
"",
"// do a CoRegisterClassObject on all the class factories",
"HRESULT __stdcall RegisterAllClassFactories()",
"{",
" Exe_Class_Iterator Iter;",
" Midl_Class_Factory_Info * pCur;",
" HRESULT hr = S_OK;",
" DWORD * pdwHandle = dwRegisterHandles;",
"",
" fFactoriesRevoked = FALSE;",
"",
" // register all the valid class factories",
" while ( pCur = Iter.GetNext() )",
" {",
" hr =CoRegisterClassObject( ",
" *pCur->pFactoryID,",
" (IUnknown*)(*pCur->ppFactory),",
" CLSCTX_LOCAL_SERVER,",
" REGCLS_MULTI_SEPARATE,",
" pdwHandle);",
" if ( FAILED( hr ) )",
" return hr;",
"",
" pdwHandle++;",
" }",
"",
" return hr;",
"}",
0
};
pStream->NewLine();
pStream->WriteBlock( RegisterRevokeCode );
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER_EXE::GenRegistryCode(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the clean-up routines for the _e.cxx file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
ISTREAM * pStream = pCCB->GetStream();
char * pName = GetSymName();
static STRING_BLOCK RegistryCode =
{
"///////////////////////////////////////////////////////////////////////",
"// these routines maintain the registry information for these classes",
"//",
"// call UpdateServerRegistry to add all the classes to the registry",
"// call CleanupServerRegistry to remove the classes from the registry",
"",
"HRESULT __stdcall UpdateServerRegistry()",
"{",
" char szDllFileName[MAX_PATH];",
" HRESULT hr;",
"",
" // get the exe name",
" if ( !GetModuleFileNameA(NULL, szDllFileName, sizeof(szDllFileName)) )",
" return E_FAIL;",
"",
" Exe_Class_Iterator Iter;",
" Midl_Class_Factory_Info * pCur;",
"",
" // register all the clsid's",
" while ( pCur = Iter.GetNext() )",
" {",
" hr = NdrRegisterServerExe( szDllFileName, pCur );",
" if ( FAILED(hr) )",
" return hr;",
" }",
"",
" return S_OK;",
"}",
"",
"// remove the registry entries for the class here",
"HRESULT __stdcall CleanupServerRegistry()",
"{",
" HRESULT hr;",
"",
" Exe_Class_Iterator Iter;",
" Midl_Class_Factory_Info * pCur;",
"",
" // register all the clsid's",
" while ( pCur = Iter.GetNext() )",
" {",
" hr = NdrUnregisterServerExe( pCur );",
" if ( FAILED(hr) )",
" return hr;",
" }",
"",
" return S_OK;",
"}",
0
};
pStream->NewLine();
pStream->WriteBlock( RegistryCode );
pStream->NewLine(2);
return CG_OK;
}
CG_STATUS
CG_COM_SERVER::GenHeader(
CCB * pCCB )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the COM server file code for an interface inherited by a
COM class defined in the IDL file.
Arguments:
pCCB - a pointer to the code generation control block.
Return Value:
CG_OK if all is well, error otherwise.
Notes:
----------------------------------------------------------------------------*/
{
return CG_OK;
}