⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch14.htm

📁 用VC开发ACTIVEX书籍和随书源码- Develops the ACTIVEX books and along with the book source code with VC
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<TT>m_cObjects</TT> is used to keep track of the number of interfaces requested from
the <TT>COBass</TT> objects. The variable <TT>m_cLocks</TT> is used to track the
number of locks issued on the COM server. When both of these variables are set to
zero, the COM server is removed from memory. <BR>
<BR>
<IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0"></P>


<BLOCKQUOTE>
	<P><B>NOTE:</B> The variables <TT>m_cLocks</TT> and <TT>m_cObjects</TT> are incremented
	and decremented through the Win32 functions <TT>InterlockedIncrement</TT> and <TT>InterlockedDecrement</TT>.
	These functions are atomic operations that add and subtract 1 from the current value
	of the variable passed to the function. These functions are designed specifically
	for multithreaded applications to prevent multiple threads from modifying a value
	simultaneously.

</BLOCKQUOTE>

<P><IMG SRC="bar.gif" WIDTH="480" HEIGHT="6" ALIGN="BOTTOM" BORDER="0">
<H2><A NAME="Heading18"></A>Implementation of the Server Access Functions</H2>
<P>Now that the COM server internals are implemented, the server access functions
must be implemented. The code for all of the server access functions is shown in
Listing 14.11.</P>
<P>Five functions must be implemented:

<UL>
	<LI><TT>DllMain</TT>: This function <I>must</I> be included for all Win32 DLLs. This
	function is the entry point for loading libraries into memory. During loading of
	the DLL, a global <TT>CServer</TT> object is created. During unloading, the <TT>CServer</TT>
	object is deleted.
	<P>
	<LI><TT>DllRegisterServer</TT>: This function is used to register the COM classes
	within the server in the Windows Registry. The <TT>CLSID</TT> for the <TT>COBass</TT>
	is registered with the CUSTOMBASS DLL as the COM server.
	<P>
	<LI><TT>DLLUnregisterServer</TT>: This function removes any COM classes registered
	by the COM server from the Windows registry.
	<P>
	<LI><TT>DllCanUnloadNow</TT>: This function checks the <TT>CServer</TT> object to
	determine whether any objects or locks remain within the server. If the respective
	counts are zero, <TT>TRUE</TT> is returned to the calling application.
	<P>
	<LI><TT>DllGetClassObject</TT>: This is the main function for accessing COM interfaces.
	If the <TT>CLSID</TT> for the <TT>CUSTOMBASS</TT> object is passed in, a class factory
	<TT>CFBASS</TT> is created. A COM interface is then requested from the <TT>CFBass</TT>
	class factory.
</UL>

<H3><A NAME="Heading19"></A>Listing 14.11 <SPACER TYPE="HORIZONTAL" SIZE="10">CUSTOMBASS.CPP--Server
Access Function Implementation</H3>
<P><FONT COLOR="#0066FF"><TT>#include &lt;ole2.h&gt;<BR>
#include &lt;initguid.h&gt;<BR>
#include &quot;..\ifish\ifish.h&quot;<BR>
#include &quot;..\ifish\ibass.h&quot;<BR>
#include &quot;custombassid.h&quot;<BR>
#include &quot;comutil.h&quot;<BR>
#define _DLLEXPORT_<BR>
#include &quot;custombass.h&quot;<BR>
#include &quot;server.h&quot;<BR>
#include &quot;factory.h&quot;<BR>
<BR>
// We encapsulate the control of this<BR>
// COM server (eg, lock and object<BR>
// counting) in a server control C++ object.<BR>
// Here is it's pointer. <BR>
CServer* g_pServer = NULL; <BR>
BOOL WINAPI DllMain(<BR>
HINSTANCE hDllInst,<BR>
DWORD fdwReason,<BR>
LPVOID lpvReserved)<BR>
{<BR>
BOOL bResult = TRUE; <BR>
// Dispatch this main call based on the reason it was called.<BR>
switch (fdwReason)<BR>
{<BR>
case DLL_PROCESS_ATTACH:<BR>
// The DLL is being loaded for the first time<BR>
// by a given process.<BR>
// Perform per-process initialization here.<BR>
// If the initialization<BR>
// is successful, return TRUE;<BR>
// if unsuccessful, return FALSE.<BR>
bResult = FALSE;<BR>
// Instantiate the CServer utility class.<BR>
g_pServer = new CServer;<BR>
if (NULL != g_pServer)<BR>
{<BR>
// Remember the DLL Instance handle.<BR>
g_pServer-&gt;m_hDllInst = hDllInst;<BR>
bResult = TRUE;<BR>
}<BR>
break; <BR>
case DLL_PROCESS_DETACH:<BR>
// The DLL is being unloaded by<BR>
// a given process. Do any<BR>
// per-process clean up here,<BR>
// such as undoing what was done in<BR>
// DLL_PROCESS_ATTACH. <BR>
// The return value is ignored.<BR>
DELETE_POINTER(g_pServer);<BR>
break; <BR>
case DLL_THREAD_ATTACH:<BR>
// A thread is being created in a process<BR>
// that has already loaded<BR>
// this DLL. Perform any per-thread<BR>
// initialization here. The<BR>
// return value is ignored.<BR>
break; <BR>
case DLL_THREAD_DETACH:<BR>
// A thread is exiting cleanly in a<BR>
// process that has already<BR>
// loaded this DLL. Perform any<BR>
// per-thread clean up here. The<BR>
// return value is ignored.<BR>
break; <BR>
default:<BR>
break;<BR>
} <BR>
return (bResult);<BR>
} <BR>
STDAPI DllGetClassObject(<BR>
REFCLSID rclsid,<BR>
REFIID riid,<BR>
PPVOID ppv)<BR>
{<BR>
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;<BR>
IUnknown* pCob = NULL; <BR>
if (CLSID_CustomBass == rclsid)<BR>
{<BR>
LOG(&quot;S: DllGetClassObject: Requesting COBass.&quot;);<BR>
hr = E_OUTOFMEMORY;<BR>
pCob = new CFBass(NULL, g_pServer);<BR>
} <BR>
if (NULL != pCob)<BR>
{<BR>
g_pServer-&gt;ObjectsUp();<BR>
hr = pCob-&gt;QueryInterface(riid, ppv);<BR>
if (FAILED(hr))<BR>
{<BR>
g_pServer-&gt;ObjectsDown();<BR>
DELETE_POINTER(pCob);<BR>
}<BR>
} <BR>
return hr;<BR>
} <BR>
STDAPI DllCanUnloadNow(void)<BR>
{<BR>
HRESULT hr; <BR>
LOGF2(&quot;S: DllCanUnloadNow. cObjects=%i,<BR>
cLocks=%i.&quot;, g_pServer-&gt;m_cObjects, g_pServer-&gt;m_cLocks); <BR>
// We return S_OK of there are<BR>
//no longer any living objects AND<BR>
// there are no outstanding client locks on this server.<BR>
hr = (0L==g_pServer-&gt;m_cObjects &amp;&amp;<BR>
0L==g_pServer-&gt;m_cLocks) ? S_OK : S_FALSE; <BR>
return hr;<BR>
} <BR>
STDAPI DllRegisterServer(void)<BR>
{<BR>
HRESULT hr = NOERROR;<BR>
TCHAR szID[GUID_SIZE+1];<BR>
TCHAR szCLSID[GUID_SIZE+1];<BR>
TCHAR szModulePath[MAX_PATH]; <BR>
// Obtain the path to this module's<BR>
// executable file for later use.<BR>
GetModuleFileName(<BR>
g_pServer-&gt;m_hDllInst,<BR>
szModulePath,<BR>
sizeof(szModulePath)/sizeof(TCHAR)); <BR>
// Create some base key strings.<BR>
StringFromGUID2(CLSID_CustomBass, szID, GUID_SIZE);<BR>
lstrcpy(szCLSID, TEXT(&quot;CLSID\\&quot;));<BR>
lstrcat(szCLSID, szID); <BR>
// Create entries under CLSID.<BR>
SetRegKeyValue(<BR>
szCLSID,<BR>
NULL,<BR>
TEXT(&quot;CustomBass Class&quot;));<BR>
<BR>
SetRegKeyValue(<BR>
szCLSID,<BR>
TEXT(&quot;InprocServer32&quot;),<BR>
szModulePath); <BR>
return hr;<BR>
} <BR>
STDAPI DllUnregisterServer(void)<BR>
{<BR>
HRESULT hr = NOERROR;<BR>
TCHAR szID[GUID_SIZE+1];<BR>
TCHAR szCLSID[GUID_SIZE+1];<BR>
TCHAR szTemp[GUID_SIZE+1]; <BR>
//Create some base key strings.<BR>
StringFromGUID2(CLSID_CustomBass, szID, GUID_SIZE);<BR>
lstrcpy(szCLSID, TEXT(&quot;CLSID\\&quot;));<BR>
lstrcat(szCLSID, szID); <BR>
wsprintf(szTemp, TEXT(&quot;%s\\%s&quot;), <BR>
szCLSID, TEXT(&quot;InprocServer32&quot;));<BR>
RegDeleteKey(HKEY_CLASSES_ROOT, szTemp); <BR>
RegDeleteKey(HKEY_CLASSES_ROOT, szCLSID); <BR>
return hr;<BR>
}<BR>
BOOL SetRegKeyValue(<BR>
LPTSTR pszKey,<BR>
LPTSTR pszSubkey,<BR>
LPTSTR pszValue)<BR>
{<BR>
BOOL bOk = FALSE;<BR>
LONG ec;<BR>
HKEY hKey;<BR>
TCHAR szKey[MAX_STRING_LENGTH]; <BR>
lstrcpy(szKey, pszKey); <BR>
if (NULL != pszSubkey)<BR>
{<BR>
lstrcat(szKey, TEXT(&quot;\\&quot;));<BR>
lstrcat(szKey, pszSubkey);<BR>
} <BR>
ec = RegCreateKeyEx(<BR>
HKEY_CLASSES_ROOT,<BR>
szKey,<BR>
0,<BR>
NULL,<BR>
REG_OPTION_NON_VOLATILE,<BR>
KEY_ALL_ACCESS,<BR>
NULL,<BR>
&amp;hKey,<BR>
NULL); <BR>
if (NULL != pszValue &amp;&amp; ERROR_SUCCESS == ec)<BR>
{<BR>
ec = RegSetValueEx(<BR>
hKey,<BR>
NULL,<BR>
0,<BR>
REG_SZ,<BR>
(BYTE *)pszValue,<BR>
(lstrlen(pszValue)+1)*sizeof(TCHAR));<BR>
if (ERROR_SUCCESS == ec)<BR>
bOk = TRUE;<BR>
RegCloseKey(hKey);<BR>
}<BR>
return bOk; <BR>
}</TT></FONT></P>
<H2><A NAME="Heading20"></A>Compiling and Testing the COM Server</H2>
<P>Now that the COM server is complete, it is time to compile and test the server.
Compiling the server is a trivial task. Simply select the command <U>B</U>uild CUSTOMBASS.DLL
from the <U>B</U>uild menu. This command will build the entire project.</P>
<P>After the server is built, it needs to be registered in the Windows Registry.
You can accomplish this by selecting the command <U>R</U>egister Control from the
<U>T</U>ools menu. <U>R</U>egister Control will invoke the application <TT>regsvr32.exe</TT>,
which will then call the function <TT>DllRegisterServer</TT> in CUSTOMBASS.DLL.</P>
<P>After registration is complete, the server is ready for use. In <A HREF="ch12.htm">Chapter
12</A>, a COM test application was created for testing the <TT>IFish</TT> and <TT>IBass</TT>
interfaces. This application can be used to test the <TT>IFish</TT> and <TT>IBass</TT>
interfaces built in CUSTOMBASS. To test CUSTOMBASS, change the <TT>CLSID</TT> referenced
from <TT>CLSID_Bass</TT> to <TT>CLSID_CustomBass</TT>. When the COM test application
is run, the new server will be used for accessing the <TT>IFish</TT> and <TT>IBass</TT>
interfaces.
<H2><A NAME="Heading21"></A>From Here...</H2>
<P>Creating your own COM classes without using a framework requires more programming
than when using a framework. However, no excessive baggage from the framework is
carried within the COM server, and several implementation strategies can be used
during implementation. For an in-depth look at using a lightweight COM framework,
refer to Chapter 13, which illustrates the development of COM Objects using the ActiveX
Template Library. The ATL framework is composed of lightweight templates for designing
and implementing COM Objects. Conversely, in <A HREF="ch12.htm">Chapter 12</A>, COM
Objects are developed using the MFC application framework. The MFC framework is feature
rich but can be overkill for COM Objects that do not need to support a user interface.

</p>

<p><hr></p>
<center>
<p><font size=-2>
&copy; 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a
Simon and Schuster Company.</font></p>
</center>


</BODY>

</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -