Creating A Component (Recap) : Interface and Process Boundary

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 5

Creating a Component (Recap)

• Define the interfaces for the component and assign them


IIDs
• Define a class implementing the interfaces of the
Local/Remote Transparency component and assign it a CLSID
• Define the class factory which implements at least the
IClassFactory interface for creating the component
• Create a DLL and export the function
DLLGetClassObject which provides the class factory
interface
• Register the component with the Windows Registry
• The DLL is an in-proc server for the component

Check the registry


Client: usage sequence (Recap)
for the server
Servers in EXEs
Client COM Library DLL • Every EXE runs in a different process
Calls CoGetClassObject CoGetClassObject
CoGetClassObject DllGetClassObject
DllGetClassObject • Every process has a separate address space
creates Process 1
returns IClassFactory CFactory Process 1 address space
0x00001234
Calls CreateInstance pFoo 0x0000ABBA
pIClassFactory IClassFactory
IClassFactory pFoo

creates
returns ISprite Process 2
Sprite
Process 2 address space 0x0BAD0ADD
pISprite uses ISprite ISprite
ISprite
pFoo 0x0000ABBA
pFoo

• DLL is called an in-process (in-proc) server Interface and Process boundary


• EXE is an out-of-process (out-of-proc) server
called local server • For an interface to cross a process boundary
• Out-of-process server may reside on a following conditions should be satisfied
different machine, in which case it is called – a process needs to be able to call a function in
another process
remote server
– process should be able to pass data to another
• Interface is an array of function pointers process
which the client should be able to access – client should not care whether it is accessing
– easy with an in-proc server sharing the same in-proc or out-of-proc components
address space

1
Local Procedure Call (LPC) Marshaling
• LPCs are for communication between • Marshaling is, passing of parameters from
different processes on the same machine the address space of the client to the address
– single machine, inter-process communication space of the component
technique based on remote procedure call (RPC) • Local Server
• Implemented by the operating system – data in one process needs to be copied to the
– OS knows the physical addresses of the address space of the other process
corresponding logical address for each process • Remote Server
• OS can call functions in any process – data has to be put in a standard format to
account for difference between machine

IMarshal Proxy / Stub


• IMarshal is an interface used by COM to • The client should communicate with in-proc,
marshal and unmarshal the parameters local and remote server in the same way
before and after calling the functions • Proxy is a DLL to which the client talks
• COM queries the component for – it mimics the component
IMarshal as part of the creation strategy – does the marshaling and LPC calls for the client
• A standard IMarshal implementation is • Stub is the DLL which the component uses
provided by the COM library – unmarshals the data sent from the client
• A custom version of IMarshal could be – marshals the data to be sent to the client
implemented for optimising performance

EXE DLL

Client Component
Component
Interface Description Language
• IDL richly describes the interface and data
in-proc service shared by the client and the component
EXE EXE
• From Open Software Foundation’s (OSF)
process boundary

Distributed Computing Environment (DCE)


Client Component • COM use a subset of IDL with several non-
standard extensions to describe interfaces
DLL Proxy Stub DLL
Proxy Stub • IDL syntax resembles C++ and is easy to use
than directly writing code for proxy and stub
out-of-proc service

2
import " unknwn.idl" ; includes definitions from other IDL file
[
// Interface ISprite attribute list uuid(B0A0A1E2 -00EC- 11d2- 9B2C-00C04FCCA483),
[ version(1.0),
object, interface is a COM interface helpstring("Sprite1.0 For LocalServer")
uuid(B0A0A1E0 -00EC- 11d2- 9B2C-00C04FCCA483), interface IID ]
helpstring("ISprite interface"),
pointer_default(unique) how to treat pointers library SpriteTypeLibrary
] {
importlib("stdole32.tlb") ;
// Interface ISprite description MIDL requires COM interface
interface ISprite : IUnknown functions to return HRESULT // Sprite implementation
{ [
HRESULT Load( [in] char* fileName ) = 0; uuid(B0A0A1E1 -00EC- 11d2- 9B2C-00C04FCCA483), class CLSID
HRESULT SetPose( [in] int pose ) = 0; helpstring("Sprite Class For Local Server")
HRESULT SetPosition ( [in] int x, [in] int y) = 0; ]
coclass Sprite class Sprite implements the
HRESULT Draw( [in] HWND win ) = 0; { ISprite interface
}; [default ] interface ISprite;
};
[in] parameter goes from the client to the component, stub does not send information back };
All this goes into a file sprite.idl
[out] parameter goes from the component to the client , proxy does not need to marshal

midl /h sprite.h /iid guid.c /proxy proxy.c


MIDL /dlldata dlldata .c sprite. idl

• Compiles the IDL file to generate code for the Will generate,
DLL that implements proxy and stub sprite.h , guid.c, proxy.c and dlldata .c
midl sprite.idl
Generates, You provide,
sprite.h defines interfaces described in the IDL file proxy.def exporting functions for the proxy/stub DLL
sprite_i.c defines the GUIDs used in the IDL file sprite. cpp implementing the component for the
sprite_p.c implements the proxy and stub for interfaces component’s server
described in the IDL file client. cpp implementing the client
dlldata .c implements the DLL that contain the proxy and
stub code

; proxy.def file

LIBRARY proxy.dll
DESCRIPTION ’Proxy/Stub DLL' Registering the Proxy/Stub
EXPORTS
DllGetClassObject @1 PRIVATE
• Define REGISTER_PROXY_DLL for
DllCanUnloadNow @2 PRIVATE compiling files proxy.c and dlldata.c
GetProxyDllInfo @3 PRIVATE
DllRegisterServer @4 PRIVATE – code for registering proxy/stub is generated
DllUnegisterServer @5 PRIVATE
• Proxy is registered using
guids.c regsvr32 /s proxy.dll
sprite.idl midl.exe proxy.c Compiler
and
• Makes an entry into the registry indicating
dlldata.c Linker – ISprite is served by a proxy/stub
sprite.h
Building the Proxy DLL proxy.dll
– in-proc server is proxy.dll

3
Local Server implementation CoRegisterClassObject
CoCreateInstance->CoGetClassObject- >->DllGetClassObject
= IClassFactory pointer for creating components using
• CoRegisterClassObject is used by
in-proc server the local server to register class factories
• Local server is an EXE
STDAPI CoRegisterClassObject(
– cannot export functions
REFCLSID clsid , // Component class id.
– has to have a main
IUnknown* iUnknown, // Factory interface
• COM maintains a private table of registered DWORD dwClsContext, // Server context
class factories DWORD flags, // connection type
• CoGetClassObject first checks the LPDWORD ppv ); // return registration id.

private table and then checks the Registry

void main(int argc, char* argv [])


{
HRESULT hr;
Initialize COM for free-threading • No export functions DllGetClassObject,
hr = CoInitializeEx (NULL, COINIT_MULTITHREADED) ;
if (FAILED(hr)) return; // cannot initialize COM DllCanUnloadNow, DllRegisterServer
DWORD dwRegister;
Register the Class Factory DllUnegisterServer
IClassFactory * pIFactory = new CFactory;
• Define _WIN32_DCOM while compiling
hr = ::CoRegisterClassObject(CLSID_Sprite,
static_cast<IUnknown*>(pIFactory), sprite.cpp if you have to use
inproc-server for itself CLSCTX_SERVER , REGCLS_MULTIPLEUSE,
&dwRegister); can server multiple clients CoInitializeEx for free-threading
if (FAILED(hr)) return; // Cannot register factory
guids.c
char choice; Compiler
while (cin >> choice) { Wait for user input to shutdown the server sprite.cpp
and
if (choice == 'q') break;
} sprite.h Linker
Unregister the Class Factory
::CoRevokeClassObject(dwRegister);
pIFactory->Release();
• Run sprite.exe to sprite.exe

CoUninitialize(); start the server


}

Client Going Remote


int main()
{ • No changes are required in the client or the
CoInitialize(NULL);
local server to distribute them on two
ISprite* pISprite = NULL;
HRESULT hr = :: CoCreateInstance ( CLSID_Sprite, NULL,
CLSCTX_ALL ,
separate machines connected by a network
Any server
IID_ ISprite,
(void**)&pISprite ); • Operating system support for Distributed
if (SUCCEEDED(hr)) { COM (DCOM ) is required
// Use the sprite
– Windows NT 4.0, Windows 95 with DCOM
pISprite ->Release();
}
Compile and link with guids.c
• There should be an entry in the registry
CoUninitialize();
return 0; indicating that the server is remote
}

4
DCOMCNFG.EXE Registry entry
• A DCOM configuration tool allows to set
HKEY_CLASSES_ROOT\
various parameters of the application CLSID\

– set application parameters to indicate whether it


runs locally or remotely
– set the name of the server which will run the
application, in case it runs remotely HKEY_CLASSES_ROOT\
AppID\

• DCOMCNFG.EXE makes the appropriate


changes in the registry

How does it work ? CoCreateInstanceEx


• Client can specify in the program that it wants
• DCOM enhances the COM library
to access a remote server
implementation of
CoGetClassObject • Retreive multiple interfaces to the component
HRESULT __stdcall CoCreateInstanceEx (
• CoGetClassObject does the following
const CLSID& clsid, //Component class id.
– locates the CLSID in the registry IUnknown* iUnknown, //for aggregation
– checks whether it has an AppID DWORD dwClsContext, //Server context
– locates the AppId entry and checks for the CONSERVERINFO* pServerInfo , //Server info
RemoteServerName ULONG cmq , //count of interfaces requested
– attempts to run the server remotely MULTI_QI* pResults); //interfaces returned

MULTI_QI Summary
• Structure defined by DCOM to query for • IDL helps a lot in creating out-of-proc
several interfaces in one call components
typedef struct _MULTI_QI { • DCOM helps in converting local servers to
const IID* pIID, //interface id.
remote servers just by making changes in
IUnknown* pItf , //interface requested
the Registry
HRESULT hr //QueryInterface return value
} MULTI_QI;
• Remote proxy provides implementation for
an interface IMultiQI which has a
funtion QueryMultipleInterfaces

You might also like