📄 0,1410,22016,00.html
字号:
<HTML>
<HEAD>
<TITLE>SAFEARRAYs Made Easier</TITLE>
</HEAD>
<BODY MARGINWIDTH="5" MARGINHEIGHT="5" TOPMARGIN="0" LEFTMARGIN="0" BGCOLOR="#FFFFFF">
<A NAME="top"></A>
<table>
<TR>
<td>
<SPAN CLASS="title3"><b>SAFEARRAYs Made Easier</b></SPAN>
<BR>
<BLOCKQUOTE CLASS="abstract"><B>Abstract:</B>This document describes the VCL template classes found in safearry.h with C++ Builder 5 and demonstrates their use to make working with SafeArrays much easier.</BLOCKQUOTE><P>
<font size=3>SAFEARRAYs Made Easier</font>
<p>Working with the Win32 <i>SAFEARRAY</i> data type can be rather tedious.
This technical information document describes the VCL template classes
found in safearry.h with C++ Builder 5 and demonstrates their use to make
working with SafeArrays much easier. Each code snippet will compile as
is in a straight Win32 application.
<p><font size=+2>What Is a SAFEARRAY?</font>
<br><tt><b>typedef</b> <b>struct</b> tagSAFEARRAYBOUND</tt>
<br><tt>\{</tt>
<br><tt> ULONG cElements;</tt>
<br><tt> LONG lLbound;</tt>
<br><tt>\} SAFEARRAYBOUND;</tt>
<p><tt><b>typedef</b> <b>struct</b> tagSAFEARRAY</tt>
<br><tt>\{</tt>
<br><tt> USHORT cDims;</tt>
<br><tt> USHORT fFeatures;</tt>
<br><tt> ULONG cbElements;</tt>
<br><tt> ULONG cLocks;</tt>
<br><tt> PVOID pvData;</tt>
<br><tt> SAFEARRAYBOUND rgsabound[1];</tt>
<br><tt>\} SAFEARRAY;</tt>
<p>The SAFEARRAY data type was designed to be used in Automation to pass
multidimensional arrays to and from COM interface methods. This type is
a structure that contains boundary information as well as a reference to
the data. This allows the passing of arrays between COM Apartments and/or
processes without the need to implement a marshaler for custom COM interfaces.
The SAFEARRAY type, being automation-compatible itself, can only consist
of automation-compatible data. Following is the straight Win32 API code
required to construct, use, and destroy a SAFEARRAY.
<p><tt><font color="#009900">#include <vcl.h></font></tt>
<br><tt><font color="#009900">#include <windows.h></font></tt>
<br><tt><font color="#009900">#pragma hdrstop</font></tt>
<p><tt>//---------------------------------------------------------------------------</tt>
<p><tt><b>void</b> Fill2DSafeArray(LPSAFEARRAY lpsaArray, <b>long</b> Value);</tt>
<p><tt><font color="#009900">#pragma argsused</font></tt>
<br><tt>WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, <b>int</b> nCmdShow)</tt>
<br><tt>\{</tt>
<br><tt> // Create 2D array of long integers. Similar to...</tt>
<br><tt> // long Array[20][10];</tt>
<br><tt> SAFEARRAYBOUND sabdBounds[2] = \{ \{10, 0\}, \{20, 0\}
\};</tt>
<br><tt> LPSAFEARRAY lpsaArray = SafeArrayCreate(VT_I4, 2,
sabdBounds);</tt>
<p><tt> // Fill array with values</tt>
<br><tt> Fill2DSafeArray(lpsaArray, 5);</tt>
<p><tt> // Destroy array</tt>
<br><tt> SafeArrayDestroy(lpsaArray);</tt>
<br><tt> <b>return</b> 0;</tt>
<br><tt>\}</tt>
<br><tt>//---------------------------------------------------------------------------</tt>
<br><tt><b>void</b> Fill2DSafeArray(LPSAFEARRAY lpsaArray, <b>long</b>
Value)</tt>
<br><tt>\{</tt>
<br><tt> <b>int</b> lower0 = lpsaArray->rgsabound[0].lLbound;</tt>
<br><tt> <b>int</b> upper0 = lpsaArray->rgsabound[0].cElements
+ lower0;</tt>
<br><tt> <b>long</b>* pData = (<b>long</b>*)lpsaArray->pvData;</tt>
<br><tt> <b>for</b>(<b>int</b> i = lower0; i < upper0; i++)
\{</tt>
<br><tt> <b>int</b> lower1 = lpsaArray->rgsabound[1].lLbound;</tt>
<br><tt> <b>int</b> upper1 = lpsaArray->rgsabound[1].cElements
+ lower1;</tt>
<br><tt> <b>for</b>(<b>int</b> j = lower1;
j < upper1; j++) \{</tt>
<br><tt> *pData = Value;</tt>
<br><tt> pData++;</tt>
<br><tt> \}</tt>
<br><tt> \}</tt>
<br><tt>\}</tt>
<br><tt>//---------------------------------------------------------------------------</tt>
<p>If you've never used the SAFEARRAY type, you can see the difficulties
it can bring. First of all, us C++ programmers lose the benefit of strong
compile-time type-checking. Also, instead of simply using the index-of
operator, we must access the memory where the data is stored directly,
which is very error prone. The equivalent code in ANSI-compliant C++ for
a 2D array of long integers reducing to the following.
<p><tt><font color="#009900">#include <vcl.h></font></tt>
<br><tt><font color="#009900">#include <windows.h></font></tt>
<br><tt><font color="#009900">#pragma hdrstop</font></tt>
<p><tt>//---------------------------------------------------------------------------</tt>
<p><tt><b>void</b> Fill2DArray(<b>long</b>* pArray, <b>int</b> size1, <b>int</b>
size2, <b>long</b> Value);</tt>
<p><tt><font color="#009900">#pragma argsused</font></tt>
<br><tt>WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, <b>int</b> nCmdShow)</tt>
<br><tt>\{</tt>
<br><tt> // Create 2D array of long integers. Similar to...</tt>
<br><tt> <b>long</b> Array[20][10];</tt>
<p><tt> // Fill array with values</tt>
<br><tt> Fill2DArray(lpsaArray, 20, 10, 5);</tt>
<p><tt> <b>return</b> 0;</tt>
<br><tt>\}</tt>
<br><tt>//---------------------------------------------------------------------------</tt>
<br><tt><b>void</b> Fill2DArray(<b>long</b>* pArray, <b>int</b> size1,
<b>int</b>
size2, <b>long</b> Value)</tt>
<br><tt>\{</tt>
<br><tt> <b>for</b>(<b>int</b> i = 0; i < 20; i++) \{</tt>
<br><tt> <b>for</b>(<b>int</b> j = 0; j <
10; j++) \{</tt>
<br><tt> *pData = Value;</tt>
<br><tt> pData++;</tt>
<br><tt> \}</tt>
<br><tt>\}</tt>
<br><tt>//---------------------------------------------------------------------------</tt>
<p>Although the C++-only version is much less error prone, it does not
contain boundary information and so must be explicitly passed as arguments
to <i>Fill2DArray</i>. Also, it cannot be used for automation because it
cannot be used to pass interface pointers between apartments and/or processes.
<p>Their are several VCL class templates that aid in creating, manipulating,
and managing SafeArrays with the benefit of strong compile-time type-checking
that can be passed to or retrieved from COM interface methods that support
COM's standard marshaler. The header file, safearry.h, contains the source
for template class TSafeArray and related classes with examples of their
use. Refer to this header file to supplement this document.
<p><font size=+2>TArrayDimT and TSafeArrayT</font>
<br>TArrayDimT and TSafeArrayT are template wrapper classes for SAFEARRAYBOUND
and SAFEARRAY, respectively. Following is the declaration of these two
class templates.
<p><tt>// SAFEARRAYBOUND[] wrapper</tt>
<br><tt>//</tt>
<br><tt><b>template</b> <<b>int</b> DIM></tt>
<br><tt><b>class</b> TArrayDimT</tt>
<br><tt>\{</tt>
<br><tt><b>public</b>:</tt>
<br><tt> TArrayDimT<DIM>(<b>int</b> dim1Len);</tt>
<br><tt> TArrayDimT<DIM>(<b>int</b> dim1Len, <b>int</b> dim2Len);</tt>
<br><tt> TArrayDimT<DIM>(<b>int</b> dim1Len, <b>int</b> dim2Len,
<b>int</b>
dim3Len);</tt>
<p><tt> <b>operator</b> SAFEARRAYBOUND* ();</tt>
<p><tt> <b>void</b> set_BoundsLength(<b>int</b> index, <b>long</b>
length);</tt>
<br><tt> <b>long</b> get_BoundsLength(<b>int</b> index);</tt>
<p><tt> <b>__property</b> <b>long</b> BoundsLength[<b>int</b>
index] = \{ read = get_BoundsLength, write = set_BoundsLength \};</tt>
<p><tt><b>protected</b>:</tt>
<br><tt> SAFEARRAYBOUND m_Bounds[DIM];</tt>
<br><tt>\};</tt>
<p><tt>// SAFEARRAY* wrapper</tt>
<br><tt>//</tt>
<br><tt><b>template</b> <<b>class</b> T, VARENUM vt, <b>int</b> DIM></tt>
<br><tt><b>class</b> TSafeArrayT</tt>
<br><tt>\{</tt>
<br><tt><b>public</b>:</tt>
<br><tt> TSafeArrayT();</tt>
<br><tt> TSafeArrayT(SAFEARRAY *psa);</tt>
<br><tt> TSafeArrayT(TArrayDimT<DIM>& dim);</tt>
<br><tt> ~TSafeArrayT();</tt>
<p><tt> TSafeArrayT(<b>const</b> TSafeArrayT<T, vt, DIM>&
src);</tt>
<br><tt> TSafeArrayT<T, vt, DIM>& <b>operator</b>=(<b>const</b>
TSafeArrayT<T, vt, DIM>& src);</tt>
<p><tt> TSAAccessorT<T, DIM> <b>operator</b>[] (<b>int</b> index);</tt>
<br><tt> SAFEARRAY** <b>operator</b>&
();</tt>
<p><tt> <b>long</b> get_BoundsLength(<b>long</b>
idx) <b>const</b>;</tt>
<br><tt> VARENUM get_VarType() <b>const</b>;</tt>
<br><tt> <b>unsigned</b> get_Dimension() <b>const</b>;</tt>
<p><tt> <b>long</b> Elements();</tt>
<p><tt> <b>void</b> Attach(SAFEARRAY*
psa);</tt>
<br><tt> SAFEARRAY* Detach();</tt>
<br><tt> <b>void</b> Destroy();</tt>
<p><tt> <b>__property</b> <b>long</b> BoundsLength[<b>long</b> idx]
= \{ read=get_BoundsLength \};</tt>
<p><tt> <b>__property</b> VARENUM VarType = \{ read=get_VarType
\};</tt>
<br><tt> <b>__property</b> unsigned Dimension = \{ read=get_Dimension
\};</tt>
<p><tt><b>protected</b>:</tt>
<br><tt> SAFEARRAY *m_psa;</tt>
<p><tt><b>private</b>:</tt>
<br><tt>\};</tt>
<p>There are many ways to construct, manipulate, and destroy SafeArrays
using these classes. In addition, every type of multidimensional array
is not inherantly supported by these classes as is, so you may need to
extend them a bit. The following code constructs the same SAFEARRAY from
the preceding examples using three different means.
<p><tt>//---------------------------------------------------------------------------</tt>
<p><tt><font color="#009900">#include <vcl.h></font></tt>
<br><tt><font color="#009900">#include <windows.h></font></tt>
<br><tt><font color="#009900">#include <safearry.h></font></tt>
<br><tt><font color="#009900">#pragma hdrstop</font></tt>
<p><tt>//---------------------------------------------------------------------------</tt>
<p><tt><font color="#009900">#pragma argsused</font></tt>
<br><tt>WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, <b>int</b> nCmdShow)</tt>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -