, , SAFEARRAY, , ORPC- , . IDL:
HRESULT Sum([in] long cElems, [in, size_is(cElems)] double *prgd, [out, retval] double *pResult);
:
double rgd[1024 * 1024 * 16]; HRESULT hr = p->Sum(sizeof(rgd)/sizeof(*rgd), rgd);
ORPC- 128 . RPC- , . , 128 , . ORPC- , . , 128 RPC- ORPC. [length_is], 128 , . [in], [out]. OPRC- , . , .
(latency). ORPC- , RPC/ORPC ORPC- . , , . , , . , ; , , . , [out], , , , .
, , , . . , (enumerator), , . , :
interface IEnumDouble : Unknown { // pull a chunk of elements from the sender // HRESULT Next([in] ULONG cElems, [out, size_is(cElems), length_is(*pcFetched)] double *prgElems, [out] ULONG *pcFetched); // advance cursor past cElems elements // cElems HRESULT Skip([in] cElems); // reset cursor to first element // HRESULT Reset(void); // duplicate enumerator's current cursor // HRESULT Clone([out] IEnumDouble **pped); }
, IEnum , . , IDL:
HRESULT Sum([in] long cElems, [in, size_is(cElems)] double *prgd, [out, retval] double *pResult);
:
HRESULT Sum([in] IEnumDouble *ped, [out, retval] double *pResult);
, , , IEnumDouble::Next HRESULT (S_FALSE).
:
STDMETHODIMP MyClass::Sum(IEnumDouble *ped, double *psum) { assert(ped && psum); *psum = 0; HRESULT hr; do { // declare a buffer to receive some elements // enum { CHUNKSIZE = 2048 }; double rgd[CHUNKSIZE]; // ask data producer to send CHUNKSIZE elements // CHUNKSIZE ULONG cFetched; hr = ped->Next(CHUNKSIZE, rgd, &cFetched); // adjust cFetched to address sloppy objects // cFetched if (hr == S_OK) cFetched = CHUNKSIZE; if (SUCCEEDED(hr)) // S_OK or S_FALSE // S_OK S_FALSE // consume/use received elements // / for (ULONG n = ; < cFetched; n++) *psum += rgd[n]; } while (hr == S_OK); // S_FALSE or error terminates // S_FALSE }
, Next S_OK , , S_FALSE, . , , cFetched S_OK (S_OK , ).
IEnum , . IDL:
HRESULT GetPrimes([in] long nMin, [in] long nMax, [out] IEnumLong **ppe);
, IEnumLong:
class PrimeGenerator : public IEnumLong { LONG m_cRef; // reference count // long m_nCurrentPrime; // the cursor // long m_nMin; // minimum prime value // long m_nMax; // maximum prime value // public: PrimeGenerator(long nMin, long nMax, long nCurrentPrime) : m_cRef(0), m_nMin(nMin), m_nMax(nMax), m_nCurrentPrime(nCurrentPrime) { } // IUnknown methods // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv); STDHETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IEnumLong methods // IEnumLong STDMETHODIMP Next(ULONG, long *, ULONG *); STDMETHODIMP Skip(ULONG); STDMETHODIMP Reset(void); STDMETHODIMP Clone(IEnumLong **ppe); };
Next :
STDMETHODIMP PrimeGenerator::Next(ULONG cElems, long *prgElems, ULONG *pcFetched) { // ensure that pcFetched is valid if cElems > 1 // , pcFetched , cElems if (cElems > 1 && pcFetched == 0) return E_INVALIDARG; // fill the buffer // ULONG cFetched = 0; while (cFetched < cElems && m_nCurrentPrime <= m_nMax) { prgElems[cFetched] = GetNextPrime(m_nCurrentPrime); m_nCurrentPrime = prgElems[cFetchcd++]; } if (pcFetched) // some callers may pass NULL // NULL *pcFetched = cFetched; return cFetched == cElems ? S_OK : S_FALSE; }
, , .
Skip :
STDMETHODIMP PrimeGenerator::Skip(ULONG cElems) { ULONG cEaten = 0; while (cEaten < cElems && m_nCurrentPrime <= m_nMax) { m_nCurrentPrime = GetNextPrime(m_nCurrentPrime); cEaten++; } return cEaten == cElems ? S_OK : S_FALSE; }
Reset :
STDMETHODIMP PrimeGenerator::Reset(void) { m_nCurrentPrime = m_nMin; return S_OK; }
Clone , , :
STDMETHODIMP PrimeGenerator::Clone(IEnumLong **ppe) { assert(ppe); * = new PrimeGenerator(m_nMin, m_nMax, m_nCurrent); if (*ppe) (*ppe)->AddRef(); return S_OK; }
PrimeGenerator GetPrimes :
STDMETHODIMP MyClass::GetPrimes(long in, long nMax, IEnumLong **ppe) { assert(ppe); *ppe = new PrimeGenerator (nMin, nMax, nMin); if (*ppe) (*ppe)->AddRef(); return S_OK; }
PrimeGenerator, .