Source code of Windows XP (NT5)
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.

1736 lines
40 KiB

  1. // avifps.cpp - proxy and stub code for IAVIFile & IAVIStream
  2. //
  3. //
  4. // Copyright (c) 1993 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // History:
  7. // Created by DavidMay 6/19/93
  8. //
  9. //
  10. // What's in this file:
  11. //
  12. // Code to enable "standard marshalling" of the IAVIFile and IAVIStream
  13. // interfaces, consisting of the following classes:
  14. //
  15. // CPSFactory, derived from IPSFactory:
  16. // Proxy/stub factory, called from DllGetClassObject to create
  17. // the other classes.
  18. //
  19. // CPrxAVIStream, derived from IAVIStream:
  20. // This class serves as a stand-in for the interface in the app that's
  21. // calling it. Uses RPC to communicate with....
  22. //
  23. // CStubAVIStream, derived from IRpcStubBuffer:
  24. // This class in the called app receives requests from the proxy
  25. // and forwards them to the actual implementation of the IAVIStream.
  26. //
  27. // CPrxAVIFile & CStubAVIFile, just like the stream versions.
  28. //
  29. //
  30. // Also included:
  31. // The function TaskHasExistingProxies can be used by an application
  32. // before exiting to check whether any of its objects are being used
  33. // by other applications. This is done by keeping track of what active
  34. // stubs exist within a given task context.
  35. //
  36. #include <win32.h>
  37. #pragma warning(disable:4355)
  38. #include "avifile.h"
  39. #include "avifps.h"
  40. #include "debug.h"
  41. #ifndef WIN32
  42. typedef POINT POINTS;
  43. #endif
  44. // when thunking between 16-bit ansi and 32-bit unicode apps, the
  45. // AVISTREAMINFO and AVIFILEINFO structures are different. What is transmitted
  46. // is a common format that includes space for both unicode and ansi strings.
  47. // ansi apps will not send or use the unicode strings. unicode apps will send
  48. // both.
  49. typedef struct _PS_STREAMINFO {
  50. DWORD fccType;
  51. DWORD fccHandler;
  52. DWORD dwFlags; /* Contains AVITF_* flags */
  53. DWORD dwCaps;
  54. WORD wPriority;
  55. WORD wLanguage;
  56. DWORD dwScale;
  57. DWORD dwRate; /* dwRate / dwScale == samples/second */
  58. DWORD dwStart;
  59. DWORD dwLength; /* In units above... */
  60. DWORD dwInitialFrames;
  61. DWORD dwSuggestedBufferSize;
  62. DWORD dwQuality;
  63. DWORD dwSampleSize;
  64. POINTS ptFrameTopLeft;
  65. POINTS ptFrameBottomRight;
  66. DWORD dwEditCount;
  67. DWORD dwFormatChangeCount;
  68. char szName[64];
  69. DWORD bHasUnicode;
  70. WCHAR szUnicodeName[64];
  71. } PS_STREAMINFO, FAR * LPPS_STREAMINFO;
  72. typedef struct _PS_FILEINFO {
  73. DWORD dwMaxBytesPerSec; // max. transfer rate
  74. DWORD dwFlags; // the ever-present flags
  75. DWORD dwCaps;
  76. DWORD dwStreams;
  77. DWORD dwSuggestedBufferSize;
  78. DWORD dwWidth;
  79. DWORD dwHeight;
  80. DWORD dwScale;
  81. DWORD dwRate; /* dwRate / dwScale == samples/second */
  82. DWORD dwLength;
  83. DWORD dwEditCount;
  84. char szFileType[64]; // descriptive string for file type?
  85. DWORD bHasUnicode;
  86. WCHAR szUnicodeType[64];
  87. } PS_FILEINFO, FAR * LPPS_FILEINFO;
  88. #ifndef WIN32
  89. //
  90. // These constants are defined in the 32-bit UUID.LIB, but not
  91. // in any 16-bit LIB. They are stolen here from the .IDL files
  92. // in the TYPES project.
  93. //
  94. extern "C" {
  95. const IID IID_IRpcStubBuffer = {0xD5F56AFC,0x593b,0x101A,{0xB5,0x69,0x08,0x00,0x2B,0x2D,0xBF,0x7A}};
  96. const IID IID_IRpcProxyBuffer = {0xD5F56A34,0x593b,0x101A,{0xB5,0x69,0x08,0x00,0x2B,0x2D,0xBF,0x7A}};
  97. const IID IID_IPSFactoryBuffer = {0xD5F569D0,0x593b,0x101A,{0xB5,0x69,0x08,0x00,0x2B,0x2D,0xBF,0x7A}};
  98. }
  99. #endif
  100. // functions for proxy/stub usage tracking; see end of this file.
  101. void UnregisterStubUsage(void);
  102. void RegisterStubUsage(void);
  103. extern "C" BOOL FAR TaskHasExistingProxies(void);
  104. #if 0 // this function is actually in classobj.cpp,
  105. // but if this were a separate proxy/stub DLL, it would look like this.
  106. STDAPI DllGetClassObject(const CLSID FAR& rclsid,
  107. const IID FAR& riid,
  108. void FAR* FAR* ppv)
  109. {
  110. HRESULT hresult;
  111. DPF("DllGetClassObject\n");
  112. if (rclsid == CLSID_AVIStreamPS) {
  113. return (*ppv = (LPVOID)new CPSFactory()) != NULL
  114. ? NOERROR : ResultFromScode(E_OUTOFMEMORY);
  115. } else {
  116. return ResultFromScode(E_UNEXPECTED);
  117. }
  118. }
  119. #endif
  120. /*
  121. * IMPLEMENTATION of CPSFactory
  122. *
  123. *
  124. * Note: This Factory supports proxies and stubs for two separate
  125. * interfaces, IID_IAVIFile and IID_IAVIStream.
  126. */
  127. CPSFactory::CPSFactory(void)
  128. {
  129. m_refs = 1;
  130. }
  131. // controlling unknown for PSFactory
  132. STDMETHODIMP CPSFactory::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  133. {
  134. if (iid == IID_IUnknown || iid == IID_IPSFactoryBuffer)
  135. {
  136. *ppv = this;
  137. ++m_refs;
  138. return NOERROR;
  139. }
  140. else
  141. {
  142. *ppv = NULL;
  143. return ResultFromScode(E_NOINTERFACE);
  144. }
  145. }
  146. STDMETHODIMP_(ULONG) CPSFactory::AddRef(void)
  147. {
  148. return ++m_refs;
  149. }
  150. STDMETHODIMP_(ULONG) CPSFactory::Release(void)
  151. {
  152. if (--m_refs == 0)
  153. {
  154. delete this;
  155. return 0;
  156. }
  157. return m_refs;
  158. }
  159. // create proxy for given interface
  160. STDMETHODIMP CPSFactory::CreateProxy(IUnknown FAR* pUnkOuter, REFIID iid,
  161. IRpcProxyBuffer FAR* FAR* ppProxy, void FAR* FAR* ppv)
  162. {
  163. IRpcProxyBuffer FAR* pProxy;
  164. HRESULT hresult;
  165. *ppProxy = NULL;
  166. *ppv = NULL;
  167. if (pUnkOuter == NULL)
  168. return ResultFromScode(E_INVALIDARG);
  169. if (iid == IID_IAVIStream) {
  170. if ((pProxy = CPrxAVIStream::Create(pUnkOuter)) == NULL)
  171. return ResultFromScode(E_OUTOFMEMORY);
  172. } else if (iid == IID_IAVIFile) {
  173. if ((pProxy = CPrxAVIFile::Create(pUnkOuter)) == NULL)
  174. return ResultFromScode(E_OUTOFMEMORY);
  175. } else
  176. return ResultFromScode(E_NOINTERFACE);
  177. hresult = pProxy->QueryInterface(iid, ppv);
  178. if (hresult == NOERROR)
  179. *ppProxy = pProxy; // transfer ref to caller
  180. else
  181. pProxy->Release(); // free proxy just created
  182. return hresult;
  183. }
  184. // create stub for given interface
  185. STDMETHODIMP CPSFactory::CreateStub(REFIID iid, IUnknown FAR* pUnkServer, IRpcStubBuffer FAR* FAR* ppStub)
  186. {
  187. if (iid == IID_IAVIStream) {
  188. return CStubAVIStream::Create(pUnkServer, ppStub);
  189. } else if (iid == IID_IAVIFile) {
  190. return CStubAVIFile::Create(pUnkServer, ppStub);
  191. } else
  192. return ResultFromScode(E_NOINTERFACE);
  193. }
  194. /*
  195. * IMPLEMENTATION of CPrxAVIStream
  196. *
  197. */
  198. // create unconnected CPrxAVIStream; return controlling IProxy/IUnknokwn FAR*
  199. IRpcProxyBuffer FAR* CPrxAVIStream::Create(IUnknown FAR* pUnkOuter)
  200. {
  201. CPrxAVIStream FAR* pPrxAVIStream;
  202. if ((pPrxAVIStream = new CPrxAVIStream(pUnkOuter)) == NULL)
  203. return NULL;
  204. return &pPrxAVIStream->m_Proxy;
  205. }
  206. CPrxAVIStream::CPrxAVIStream(IUnknown FAR* pUnkOuter) : m_Proxy(this)
  207. {
  208. // NOTE: could assert here since we should always be aggregated
  209. if (pUnkOuter == NULL)
  210. pUnkOuter = &m_Proxy;
  211. m_refs = 1;
  212. m_pUnkOuter = pUnkOuter;
  213. m_pRpcChannelBuffer = NULL;
  214. m_sh.fccType = 0;
  215. DPF("PrxStream %lx: Usage++=%lx\n", (DWORD) (LPVOID) this, 1L);
  216. }
  217. CPrxAVIStream::~CPrxAVIStream(void)
  218. {
  219. m_Proxy.Disconnect();
  220. }
  221. // Methods for controlling unknown
  222. STDMETHODIMP CPrxAVIStream::CProxyImpl::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  223. {
  224. if (iid == IID_IUnknown || iid == IID_IRpcProxyBuffer)
  225. *ppv = (void FAR *)this;
  226. else if (iid == IID_IAVIStream)
  227. *ppv = (void FAR *)m_pPrxAVIStream;
  228. else {
  229. *ppv = NULL;
  230. return ResultFromScode(E_NOINTERFACE);
  231. }
  232. // simplest way to be correct: always addref the pointer we will return;
  233. // easy since all interfaces here are derived from IUnknown.
  234. ((IUnknown FAR*) *ppv)->AddRef();
  235. return NOERROR;
  236. }
  237. STDMETHODIMP_(ULONG) CPrxAVIStream::CProxyImpl::AddRef(void)
  238. {
  239. return ++m_pPrxAVIStream->m_refs;
  240. }
  241. STDMETHODIMP_(ULONG) CPrxAVIStream::CProxyImpl::Release(void)
  242. {
  243. if (--m_pPrxAVIStream->m_refs == 0)
  244. {
  245. delete m_pPrxAVIStream;
  246. return 0;
  247. }
  248. return m_pPrxAVIStream->m_refs;
  249. }
  250. // connect proxy to channel given
  251. STDMETHODIMP CPrxAVIStream::CProxyImpl::Connect(IRpcChannelBuffer FAR* pRpcChannelBuffer)
  252. {
  253. if (m_pPrxAVIStream->m_pRpcChannelBuffer != NULL)
  254. return ResultFromScode(E_UNEXPECTED);
  255. if (pRpcChannelBuffer == NULL)
  256. return ResultFromScode(E_INVALIDARG);
  257. (m_pPrxAVIStream->m_pRpcChannelBuffer = pRpcChannelBuffer)->AddRef();
  258. return NOERROR;
  259. }
  260. // disconnect proxy from any current channel
  261. STDMETHODIMP_(void) CPrxAVIStream::CProxyImpl::Disconnect(void)
  262. {
  263. if (m_pPrxAVIStream->m_pRpcChannelBuffer)
  264. {
  265. m_pPrxAVIStream->m_pRpcChannelBuffer->Release();
  266. m_pPrxAVIStream->m_pRpcChannelBuffer = NULL;
  267. }
  268. }
  269. // IUnknown methods for external interface(s); always delegate
  270. STDMETHODIMP CPrxAVIStream::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  271. {
  272. return m_pUnkOuter->QueryInterface(iid, ppv);
  273. }
  274. STDMETHODIMP_(ULONG) CPrxAVIStream::AddRef(void)
  275. {
  276. DPF("PrxStream %lx: Usage++=%lx\n", (DWORD) (LPVOID) this, m_refs + 1);
  277. return m_pUnkOuter->AddRef();
  278. }
  279. STDMETHODIMP_(ULONG) CPrxAVIStream::Release(void)
  280. {
  281. DPF("PrxStream %lx: Usage--=%lx\n", (DWORD) (LPVOID) this, m_refs - 1);
  282. return m_pUnkOuter->Release();
  283. }
  284. // IAVIStream interface methods
  285. STDMETHODIMP CPrxAVIStream::Create(LONG lParam1, LONG lParam2)
  286. {
  287. return ResultFromScode(E_NOTIMPL);
  288. }
  289. #ifdef WIN32
  290. STDMETHODIMP CPrxAVIStream::Info(AVISTREAMINFOW FAR * psi, LONG lSize)
  291. #else
  292. STDMETHODIMP CPrxAVIStream::Info(AVISTREAMINFO FAR * psi, LONG lSize)
  293. #endif
  294. {
  295. HRESULT hrMarshal;
  296. HRESULT hrMethod = NOERROR;
  297. IRpcChannelBuffer FAR* pChannel = m_pRpcChannelBuffer;
  298. RPCOLEMESSAGE Message;
  299. _fmemset(&Message, 0, sizeof(Message));
  300. if (pChannel == NULL)
  301. return ResultFromScode(RPC_E_CONNECTION_TERMINATED);
  302. //
  303. // NOTE: We take advantage here of the fact that we assume the
  304. // stream is read-only and not being changed on the other end!
  305. //
  306. // To avoid some intertask calls, we assume that the result
  307. // of the Info() method will not change.
  308. //
  309. if (m_sh.fccType == 0) {
  310. // we might be talking to 16 or 32-bit stub, so we need to
  311. // exchange a common (superset) format and pick out the bits we need.
  312. // format in: lSize
  313. // format out: PS_STREAMINFO, hrMethod
  314. Message.cbBuffer = sizeof(lSize);
  315. Message.iMethod = IAVISTREAM_Info;
  316. if ((hrMarshal = pChannel->GetBuffer(&Message, IID_IAVIStream)) != NOERROR)
  317. goto ErrExit;
  318. ((DWORD FAR *)Message.Buffer)[0] = sizeof(PS_STREAMINFO);
  319. if ((hrMarshal = pChannel->SendReceive(&Message,(ULONG*) &hrMethod)) != NOERROR) {
  320. ;
  321. ErrExit:
  322. return PropagateResult(hrMarshal, RPC_E_CLIENT_CANTMARSHAL_DATA);
  323. }
  324. hrMethod = ((HRESULT FAR *)Message.Buffer)[0];
  325. PS_STREAMINFO FAR * psinfo = (PS_STREAMINFO FAR *)
  326. ((LPBYTE)Message.Buffer + sizeof(HRESULT));
  327. // get the bits we want
  328. m_sh.fccType = psinfo->fccType;
  329. m_sh.fccHandler = psinfo->fccHandler;
  330. m_sh.dwFlags = psinfo->dwFlags; /* Contains AVITF_* flags */
  331. m_sh.dwCaps = psinfo->dwCaps;
  332. m_sh.wPriority = psinfo->wPriority;
  333. m_sh.wLanguage = psinfo->wLanguage;
  334. m_sh.dwScale = psinfo->dwScale;
  335. m_sh.dwRate = psinfo->dwRate; /* dwRate / dwScale == samples/second */
  336. m_sh.dwStart = psinfo->dwStart;
  337. m_sh.dwLength = psinfo->dwLength; /* In units above... */
  338. m_sh.dwInitialFrames = psinfo->dwInitialFrames;
  339. m_sh.dwSuggestedBufferSize = psinfo->dwSuggestedBufferSize;
  340. m_sh.dwQuality = psinfo->dwQuality;
  341. m_sh.dwSampleSize = psinfo->dwSampleSize;
  342. // RECTs are different sizes, so use POINTS (WORD point)
  343. m_sh.rcFrame.top = psinfo->ptFrameTopLeft.y;
  344. m_sh.rcFrame.left = psinfo->ptFrameTopLeft.x;
  345. m_sh.rcFrame.bottom = psinfo->ptFrameBottomRight.y;
  346. m_sh.rcFrame.right = psinfo->ptFrameBottomRight.x;
  347. m_sh.dwEditCount = psinfo->dwEditCount;
  348. m_sh.dwFormatChangeCount = psinfo->dwFormatChangeCount;
  349. #ifdef WIN32
  350. // use unicode if we've been sent it
  351. if (psinfo->bHasUnicode) {
  352. _fmemcpy(m_sh.szName, psinfo->szUnicodeName, sizeof(m_sh.szName));
  353. } else {
  354. // need ansi->unicode thunk
  355. MultiByteToWideChar(
  356. CP_ACP, 0,
  357. psinfo->szName,
  358. -1,
  359. m_sh.szName,
  360. NUMELMS(m_sh.szName));
  361. }
  362. #else
  363. // we only use the ansi which is always sent
  364. _fmemcpy(m_sh.szName, psinfo->szName, sizeof(m_sh.szName));
  365. #endif
  366. pChannel->FreeBuffer(&Message);
  367. }
  368. _fmemcpy(psi, &m_sh, min((int) lSize, sizeof(m_sh)));
  369. return hrMethod;
  370. }
  371. STDMETHODIMP_(LONG) CPrxAVIStream::FindSample(LONG lPos, LONG lFlags)
  372. {
  373. HRESULT hrMarshal;
  374. HRESULT hrMethod;
  375. IRpcChannelBuffer FAR* pChannel = m_pRpcChannelBuffer;
  376. LONG lResult;
  377. if (pChannel == NULL)
  378. return -1; // !!! ResultFromScode(RPC_E_CONNECTION_TERMINATED);
  379. RPCOLEMESSAGE Message;
  380. _fmemset(&Message, 0, sizeof(Message));
  381. // format in: lPos, lFlags
  382. // format out: hrMethod, lResult
  383. Message.cbBuffer = sizeof(lPos) + sizeof(lFlags);
  384. Message.iMethod = IAVISTREAM_FindSample;
  385. if ((hrMarshal = pChannel->GetBuffer(&Message, IID_IAVIStream)) != NOERROR)
  386. goto ErrExit;
  387. ((DWORD FAR *)Message.Buffer)[0] = lPos;
  388. ((DWORD FAR *)Message.Buffer)[1] = lFlags;
  389. if ((hrMarshal = pChannel->SendReceive(&Message, (ULONG*) &hrMethod)) != NOERROR) {
  390. goto ErrExit;
  391. }
  392. hrMethod = ((HRESULT FAR *)Message.Buffer)[0];
  393. lResult = ((LONG FAR *)Message.Buffer)[1];
  394. pChannel->FreeBuffer(&Message);
  395. DPF("Proxy: FindSample (%ld) returns (%ld)\n", lPos, lResult);
  396. return lResult; // !!! hrMethod;
  397. ErrExit:
  398. DPF("Proxy: FindSample returning error...\n");
  399. return -1; // !!! PropagateResult(hrMarshal, RPC_E_CLIENT_CANTMARSHAL_DATA);
  400. }
  401. STDMETHODIMP CPrxAVIStream::ReadFormat(LONG lPos, LPVOID lpFormat, LONG FAR *lpcbFormat)
  402. {
  403. HRESULT hrMarshal;
  404. HRESULT hrMethod;
  405. IRpcChannelBuffer FAR* pChannel = m_pRpcChannelBuffer;
  406. if (pChannel == NULL)
  407. return ResultFromScode(RPC_E_CONNECTION_TERMINATED);
  408. // check that size is 0 if pointer is null
  409. if (lpFormat == NULL) {
  410. *lpcbFormat = 0;
  411. }
  412. // format in: dw, *lpcbFormat
  413. // format out: hrMethod, *lpcbFormat, format data
  414. RPCOLEMESSAGE Message;
  415. _fmemset(&Message, 0, sizeof(Message));
  416. Message.cbBuffer = sizeof(lPos) + sizeof(*lpcbFormat);
  417. Message.iMethod = IAVISTREAM_ReadFormat;
  418. if ((hrMarshal = pChannel->GetBuffer(&Message, IID_IAVIStream)) != NOERROR)
  419. goto ErrExit;
  420. ((DWORD FAR *)Message.Buffer)[0] = lPos;
  421. ((DWORD FAR *)Message.Buffer)[1] = lpFormat ? *lpcbFormat : 0;
  422. if ((hrMarshal = pChannel->SendReceive(&Message, (ULONG*) &hrMethod)) != NOERROR) {
  423. goto ErrExit;
  424. }
  425. hrMethod = ((HRESULT FAR *)Message.Buffer)[0];
  426. if (lpFormat && *lpcbFormat)
  427. hmemcpy(lpFormat, (LPBYTE) Message.Buffer + 2*sizeof(DWORD),
  428. min(*lpcbFormat, (long) ((DWORD FAR *) Message.Buffer)[1]));
  429. // write the size last, so we don't copy more than user's buffer
  430. *lpcbFormat = ((DWORD FAR *)Message.Buffer)[1];
  431. pChannel->FreeBuffer(&Message);
  432. return hrMethod;
  433. ErrExit:
  434. return PropagateResult(hrMarshal, RPC_E_CLIENT_CANTMARSHAL_DATA);
  435. }
  436. STDMETHODIMP CPrxAVIStream::Read(
  437. LONG lStart,
  438. LONG lSamples,
  439. LPVOID lpBuffer,
  440. LONG cbBuffer,
  441. LONG FAR * plBytes,
  442. LONG FAR * plSamples)
  443. {
  444. HRESULT hrMarshal;
  445. HRESULT hrMethod;
  446. IRpcChannelBuffer FAR* pChannel = m_pRpcChannelBuffer;
  447. LONG lTemp;
  448. if (pChannel == NULL)
  449. return ResultFromScode(RPC_E_CONNECTION_TERMINATED);
  450. if (lpBuffer == NULL)
  451. cbBuffer = 0;
  452. // format on input: lPos, lLength, cb
  453. // format on output: hresult, samples, cb, frame
  454. RPCOLEMESSAGE Message;
  455. _fmemset(&Message, 0, sizeof(Message));
  456. Message.cbBuffer = sizeof(lStart) + sizeof(lSamples) + sizeof(cbBuffer);
  457. Message.iMethod = IAVISTREAM_Read;
  458. if ((hrMarshal = pChannel->GetBuffer(&Message, IID_IAVIStream)) != NOERROR)
  459. goto ErrExit;
  460. ((DWORD FAR *)Message.Buffer)[0] = lStart;
  461. ((DWORD FAR *)Message.Buffer)[1] = lSamples;
  462. ((DWORD FAR *)Message.Buffer)[2] = lpBuffer ? cbBuffer : 0;
  463. if ((hrMarshal = pChannel->SendReceive(&Message, (ULONG*) &hrMethod)) != NOERROR) {
  464. goto ErrExit;
  465. }
  466. hrMethod = ((HRESULT FAR *)Message.Buffer)[0];
  467. lTemp = ((DWORD FAR *)Message.Buffer)[1];
  468. if (plBytes)
  469. *plBytes = lTemp;
  470. if (plSamples)
  471. *plSamples = ((DWORD FAR *)Message.Buffer)[2];
  472. if (lpBuffer && lTemp)
  473. hmemcpy(lpBuffer, (LPBYTE) Message.Buffer + 3*sizeof(DWORD), lTemp);
  474. pChannel->FreeBuffer(&Message);
  475. return hrMethod;
  476. ErrExit:
  477. return PropagateResult(hrMarshal, RPC_E_CLIENT_CANTMARSHAL_DATA);
  478. }
  479. //
  480. // All of the writing-related messages are not remoted....
  481. //
  482. STDMETHODIMP CPrxAVIStream::SetFormat(LONG lPos,LPVOID lpFormat,LONG cbFormat)
  483. {
  484. return ResultFromScode(E_NOTIMPL);
  485. }
  486. STDMETHODIMP CPrxAVIStream::Write(LONG lStart,
  487. LONG lSamples,
  488. LPVOID lpData,
  489. LONG cbData,
  490. DWORD dwFlags,
  491. LONG FAR *plSampWritten,
  492. LONG FAR *plBytesWritten)
  493. {
  494. return ResultFromScode(E_NOTIMPL);
  495. }
  496. STDMETHODIMP CPrxAVIStream::Delete(LONG lStart,LONG lSamples)
  497. {
  498. return ResultFromScode(E_NOTIMPL);
  499. }
  500. STDMETHODIMP CPrxAVIStream::ReadData(DWORD ckid, LPVOID lp, LONG FAR *lpcb)
  501. {
  502. // !!! This should really be remoted!
  503. return ResultFromScode(E_NOTIMPL);
  504. }
  505. STDMETHODIMP CPrxAVIStream::WriteData(DWORD ckid, LPVOID lp, LONG cb)
  506. {
  507. return ResultFromScode(E_NOTIMPL);
  508. }
  509. #ifdef WIN32
  510. STDMETHODIMP CPrxAVIStream::SetInfo(AVISTREAMINFOW FAR *lpInfo, LONG cbInfo)
  511. {
  512. return ResultFromScode(E_NOTIMPL);
  513. }
  514. #else
  515. STDMETHODIMP CPrxAVIStream::Reserved1(void)
  516. {
  517. return ResultFromScode(E_NOTIMPL);
  518. }
  519. STDMETHODIMP CPrxAVIStream::Reserved2(void)
  520. {
  521. return ResultFromScode(E_NOTIMPL);
  522. }
  523. STDMETHODIMP CPrxAVIStream::Reserved3(void)
  524. {
  525. return ResultFromScode(E_NOTIMPL);
  526. }
  527. STDMETHODIMP CPrxAVIStream::Reserved4(void)
  528. {
  529. return ResultFromScode(E_NOTIMPL);
  530. }
  531. STDMETHODIMP CPrxAVIStream::Reserved5(void)
  532. {
  533. return ResultFromScode(E_NOTIMPL);
  534. }
  535. #endif
  536. /*
  537. * IMPLEMENTATION of CStubAVIStream
  538. *
  539. */
  540. // create connected interface stub
  541. HRESULT CStubAVIStream::Create(IUnknown FAR* pUnkObject, IRpcStubBuffer FAR* FAR* ppStub)
  542. {
  543. CStubAVIStream FAR* pStubAVIStream;
  544. *ppStub = NULL;
  545. if ((pStubAVIStream = new CStubAVIStream()) == NULL)
  546. return ResultFromScode(E_OUTOFMEMORY);
  547. HRESULT hresult;
  548. if ((hresult = pStubAVIStream->Connect(pUnkObject)) != NOERROR)
  549. {
  550. pStubAVIStream->Release();
  551. return hresult;
  552. }
  553. *ppStub = pStubAVIStream;
  554. return NOERROR;
  555. }
  556. CStubAVIStream::CStubAVIStream(void)
  557. {
  558. m_refs = 1; /// !!! ??? 0
  559. DPF("StubStream %lx: Usage++=%lx (C)\n", (DWORD) (LPVOID) this, 1L);
  560. m_pAVIStream = NULL;
  561. RegisterStubUsage();
  562. }
  563. CStubAVIStream::~CStubAVIStream(void)
  564. {
  565. UnregisterStubUsage();
  566. Disconnect();
  567. }
  568. // controling unknown methods for interface stub
  569. STDMETHODIMP CStubAVIStream::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  570. {
  571. if (iid == IID_IUnknown || iid == IID_IRpcStubBuffer)
  572. {
  573. *ppv = this;
  574. DPF("StubStream %lx: Usage++=%lx (QI)\n", (DWORD) (LPVOID) this, m_refs + 1);
  575. ++m_refs;
  576. return NOERROR;
  577. }
  578. else
  579. {
  580. *ppv = NULL;
  581. return ResultFromScode(E_NOINTERFACE);
  582. }
  583. }
  584. STDMETHODIMP_(ULONG) CStubAVIStream::AddRef(void)
  585. {
  586. DPF("StubStream %lx: Usage++=%lx\n", (DWORD) (LPVOID) this, m_refs + 1);
  587. return ++m_refs;
  588. }
  589. STDMETHODIMP_(ULONG) CStubAVIStream::Release(void)
  590. {
  591. DPF("StubStream %lx: Usage--=%lx\n", (DWORD) (LPVOID) this, m_refs - 1);
  592. if (--m_refs == 0)
  593. {
  594. if (m_pAVIStream) {
  595. DPF("Releasing stream in funny place!\n");
  596. m_pAVIStream->Release();
  597. m_pAVIStream = NULL;
  598. }
  599. delete this;
  600. return 0;
  601. }
  602. return m_refs;
  603. }
  604. // connect interface stub to server object
  605. STDMETHODIMP CStubAVIStream::Connect(IUnknown FAR* pUnkObj)
  606. {
  607. HRESULT hr;
  608. if (m_pAVIStream)
  609. // call Disconnect first
  610. return ResultFromScode(E_UNEXPECTED);
  611. if (pUnkObj == NULL)
  612. return ResultFromScode(E_INVALIDARG);
  613. // NOTE: QI ensures out param is zero if error
  614. hr = pUnkObj->QueryInterface(IID_IAVIStream, (LPVOID FAR*)&m_pAVIStream);
  615. DPF("CStubAVIStream::Connect: Result = %lx, stream = %lx\n", (DWORD) (LPVOID) hr, (DWORD) m_pAVIStream);
  616. return hr;
  617. }
  618. // disconnect interface stub from server objec
  619. STDMETHODIMP_(void) CStubAVIStream::Disconnect(void)
  620. {
  621. DPF("CStubAVIStream::Disconnect\n");
  622. if (m_pAVIStream) {
  623. DPF("Disconnect: Releasing stream\n");
  624. m_pAVIStream->Release();
  625. m_pAVIStream = NULL;
  626. }
  627. }
  628. // remove method call
  629. STDMETHODIMP CStubAVIStream::Invoke
  630. (RPCOLEMESSAGE FAR *pMessage, IRpcChannelBuffer FAR *pChannel)
  631. {
  632. HRESULT hresult;
  633. HRESULT hrMethod;
  634. DPF("!AVISTREAM: Invoke: ");
  635. if (!m_pAVIStream) {
  636. DPF("!No stream!\n");
  637. return ResultFromScode(RPC_E_UNEXPECTED);
  638. }
  639. #if 0
  640. if (iid != IID_IAVIStream) {
  641. DPF("!Wrong interface\n");
  642. return ResultFromScode(RPC_E_UNEXPECTED);
  643. }
  644. #endif
  645. switch (pMessage->iMethod)
  646. {
  647. case IAVISTREAM_Info:
  648. // format on input: lSize
  649. // format on output: hresult, PS_STREAMINFO
  650. {
  651. DWORD lSize;
  652. #ifdef WIN32
  653. AVISTREAMINFOW si;
  654. #else
  655. AVISTREAMINFO si;
  656. #endif
  657. DPF("!Info\n");
  658. // need to send a common ansi/unicode version with both strings
  659. PS_STREAMINFO psinfo;
  660. hrMethod = m_pAVIStream->Info(&si, sizeof(si));
  661. // copy all members
  662. psinfo.fccType = si.fccType;
  663. psinfo.fccHandler = si.fccHandler;
  664. psinfo.dwFlags = si.dwFlags; /* Contains AVITF_* flags */
  665. psinfo.dwCaps = si.dwCaps;
  666. psinfo.wPriority = si.wPriority;
  667. psinfo.wLanguage = si.wLanguage;
  668. psinfo.dwScale = si.dwScale;
  669. psinfo.dwRate = si.dwRate; /* dwRate / dwScale == samples/second */
  670. psinfo.dwStart = si.dwStart;
  671. psinfo.dwLength = si.dwLength; /* In units above... */
  672. psinfo.dwInitialFrames = si.dwInitialFrames;
  673. psinfo.dwSuggestedBufferSize = si.dwSuggestedBufferSize;
  674. psinfo.dwQuality = si.dwQuality;
  675. psinfo.dwSampleSize = si.dwSampleSize;
  676. psinfo.dwEditCount = si.dwEditCount;
  677. psinfo.dwFormatChangeCount = si.dwFormatChangeCount;
  678. // RECT is different size, so use POINTS
  679. psinfo.ptFrameTopLeft.x = (short) si.rcFrame.left;
  680. psinfo.ptFrameTopLeft.y = (short) si.rcFrame.top;
  681. psinfo.ptFrameBottomRight.x = (short) si.rcFrame.right;
  682. psinfo.ptFrameBottomRight.y = (short) si.rcFrame.bottom;
  683. #ifdef WIN32
  684. // send both UNICODE and ansi
  685. hmemcpy(psinfo.szUnicodeName, si.szName, sizeof(psinfo.szUnicodeName));
  686. psinfo.bHasUnicode = TRUE;
  687. WideCharToMultiByte(CP_ACP, 0,
  688. si.szName,
  689. -1,
  690. psinfo.szName,
  691. NUMELMS(psinfo.szName),
  692. NULL, NULL);
  693. #else
  694. // just send ansi version for 16-bit stub
  695. psinfo.bHasUnicode = FALSE;
  696. hmemcpy(psinfo.szName, si.szName, sizeof(si.szName));
  697. #endif
  698. lSize = ((DWORD FAR *)pMessage->Buffer)[0];
  699. pMessage->cbBuffer = lSize + sizeof(hrMethod);
  700. if ((hresult = pChannel->GetBuffer(pMessage, IID_IAVIStream)) != NOERROR)
  701. return PropagateResult(hresult, RPC_E_SERVER_CANTUNMARSHAL_DATA);
  702. ((HRESULT FAR *)pMessage->Buffer)[0] = hrMethod;
  703. hmemcpy((LPBYTE) pMessage->Buffer + sizeof(hrMethod),
  704. &psinfo,
  705. lSize);
  706. return NOERROR;
  707. }
  708. case IAVISTREAM_FindSample:
  709. // format on input: lPos, lFlags
  710. // format on output: hResult, lResult
  711. {
  712. LONG lPos, lFlags, lResult;
  713. lPos = ((DWORD FAR *)pMessage->Buffer)[0];
  714. lFlags = ((DWORD FAR *)pMessage->Buffer)[1];
  715. DPF("!FindSample (%ld)\n", lPos);
  716. lResult = m_pAVIStream->FindSample(lPos, lFlags);
  717. hrMethod = 0; // !!!
  718. pMessage->cbBuffer = sizeof(lResult) + sizeof(hrMethod);
  719. if ((hresult = pChannel->GetBuffer(pMessage, IID_IAVIStream)) != NOERROR)
  720. return PropagateResult(hresult, RPC_E_SERVER_CANTUNMARSHAL_DATA);
  721. ((HRESULT FAR *)pMessage->Buffer)[0] = hrMethod;
  722. ((DWORD FAR *)pMessage->Buffer)[1] = lResult;
  723. return NOERROR;
  724. }
  725. case IAVISTREAM_ReadFormat:
  726. // format on input: lPos, cbFormat
  727. // format on output: hresult, cbFormat, format
  728. {
  729. LONG cbIn;
  730. LONG cb;
  731. DWORD lPos;
  732. LPVOID lp;
  733. lPos = ((DWORD FAR *)pMessage->Buffer)[0];
  734. cb = cbIn = ((DWORD FAR *)pMessage->Buffer)[1];
  735. DPF("!ReadFormat (%ld)\n", lPos);
  736. pMessage->cbBuffer = sizeof(cbIn) + cbIn + sizeof(hrMethod);
  737. if ((hresult = pChannel->GetBuffer(pMessage, IID_IAVIStream)) != NOERROR)
  738. return PropagateResult(hresult, RPC_E_SERVER_CANTUNMARSHAL_DATA);
  739. lp = cbIn ? (LPBYTE) pMessage->Buffer + 2 * sizeof(DWORD) : NULL;
  740. hrMethod = m_pAVIStream->ReadFormat(lPos, lp, &cb);
  741. ((HRESULT FAR *)pMessage->Buffer)[0] = hrMethod;
  742. ((DWORD FAR *)pMessage->Buffer)[1] = cb;
  743. pMessage->cbBuffer = sizeof(cbIn) + sizeof(hrMethod) +
  744. ((cb && cbIn) ? cb : 0);
  745. return NOERROR;
  746. }
  747. case IAVISTREAM_Read:
  748. // format on input: lPos, lSamples, cb
  749. // format on output: hresult, samples, cb, frame
  750. {
  751. LONG cb;
  752. LONG lPos, lSamples;
  753. LPVOID lp;
  754. lPos = ((DWORD FAR *)pMessage->Buffer)[0];
  755. lSamples = ((DWORD FAR *)pMessage->Buffer)[1];
  756. cb = ((DWORD FAR *)pMessage->Buffer)[2];
  757. DPF("!Read (%ld, %ld) ", lPos, lSamples);
  758. pMessage->cbBuffer = 3 * sizeof(DWORD) + cb;
  759. if ((hresult = pChannel->GetBuffer(pMessage, IID_IAVIStream)) != NOERROR)
  760. return PropagateResult(hresult, RPC_E_SERVER_CANTUNMARSHAL_DATA);
  761. lp = cb ? (LPBYTE) pMessage->Buffer + 3 * sizeof(DWORD) : NULL;
  762. DPF("! %ld bytes ");
  763. hrMethod = m_pAVIStream->Read(lPos, lSamples, lp, cb, &cb, &lSamples);
  764. DPF("! -> %ld bytes\n");
  765. ((HRESULT FAR *)pMessage->Buffer)[0] = hrMethod;
  766. ((DWORD FAR *)pMessage->Buffer)[1] = cb;
  767. ((DWORD FAR *)pMessage->Buffer)[2] = lSamples;
  768. return NOERROR;
  769. }
  770. default:
  771. // unknown method
  772. DPF("!Unknown method (%d)\n", pMessage->iMethod);
  773. return ResultFromScode(RPC_E_UNEXPECTED);
  774. }
  775. }
  776. // return TRUE if we support given interface
  777. STDMETHODIMP_(IRpcStubBuffer FAR *) CStubAVIStream::IsIIDSupported(REFIID iid)
  778. {
  779. // if we are connected, we have already checked for this interface;
  780. // if we are not connected, it doesn't matter.
  781. return iid == IID_IAVIStream ? (IRpcStubBuffer *) this : 0;
  782. }
  783. // returns number of refs we have to object
  784. STDMETHODIMP_(ULONG) CStubAVIStream::CountRefs(void)
  785. {
  786. // return 1 if connected; 0 if not.
  787. return m_pAVIStream != NULL;
  788. }
  789. STDMETHODIMP CStubAVIStream::DebugServerQueryInterface(LPVOID FAR *ppv)
  790. {
  791. *ppv = m_pAVIStream;
  792. if (!m_pAVIStream) {
  793. DPF("!No stream!\n");
  794. return ResultFromScode(E_UNEXPECTED);
  795. }
  796. return NOERROR;
  797. }
  798. STDMETHODIMP_(void) CStubAVIStream::DebugServerRelease(LPVOID pv)
  799. {
  800. }
  801. /*
  802. * IMPLEMENTATION of CPrxAVIFile
  803. *
  804. */
  805. // create unconnected CPrxAVIFile; return controlling IProxy/IUnknokwn FAR*
  806. IRpcProxyBuffer FAR* CPrxAVIFile::Create(IUnknown FAR* pUnkOuter)
  807. {
  808. CPrxAVIFile FAR* pPrxAVIFile;
  809. if ((pPrxAVIFile = new CPrxAVIFile(pUnkOuter)) == NULL)
  810. return NULL;
  811. return &pPrxAVIFile->m_Proxy;
  812. }
  813. CPrxAVIFile::CPrxAVIFile(IUnknown FAR* pUnkOuter) : m_Proxy(this)
  814. {
  815. // NOTE: could assert here since we should always be aggregated
  816. if (pUnkOuter == NULL)
  817. pUnkOuter = &m_Proxy;
  818. m_refs = 1;
  819. m_pUnkOuter = pUnkOuter;
  820. m_pRpcChannelBuffer = NULL;
  821. m_fi.dwStreams = 0;
  822. }
  823. CPrxAVIFile::~CPrxAVIFile(void)
  824. {
  825. m_Proxy.Disconnect();
  826. }
  827. // Methods for controlling unknown
  828. STDMETHODIMP CPrxAVIFile::CProxyImpl::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  829. {
  830. if (iid == IID_IUnknown || iid == IID_IRpcProxyBuffer)
  831. *ppv = (void FAR *)this;
  832. else if (iid == IID_IAVIFile)
  833. *ppv = (void FAR *)m_pPrxAVIFile;
  834. else
  835. {
  836. *ppv = NULL;
  837. return ResultFromScode(E_NOINTERFACE);
  838. }
  839. // simplest way to be correct: always addref the pointer we will return;
  840. // easy since all interfaces here are derived from IUnknown.
  841. ((IUnknown FAR*) *ppv)->AddRef();
  842. return NOERROR;
  843. }
  844. STDMETHODIMP_(ULONG) CPrxAVIFile::CProxyImpl::AddRef(void)
  845. {
  846. return ++m_pPrxAVIFile->m_refs;
  847. }
  848. STDMETHODIMP_(ULONG) CPrxAVIFile::CProxyImpl::Release(void)
  849. {
  850. if (--m_pPrxAVIFile->m_refs == 0)
  851. {
  852. delete m_pPrxAVIFile;
  853. return 0;
  854. }
  855. return m_pPrxAVIFile->m_refs;
  856. }
  857. // connect proxy to channel given
  858. STDMETHODIMP CPrxAVIFile::CProxyImpl::Connect(IRpcChannelBuffer FAR* pChannelChannelBuffer)
  859. {
  860. if (m_pPrxAVIFile->m_pRpcChannelBuffer != NULL)
  861. return ResultFromScode(E_UNEXPECTED);
  862. if (pChannelChannelBuffer == NULL)
  863. return ResultFromScode(E_INVALIDARG);
  864. (m_pPrxAVIFile->m_pRpcChannelBuffer = pChannelChannelBuffer)->AddRef();
  865. return NOERROR;
  866. }
  867. // disconnect proxy from any current channel
  868. STDMETHODIMP_(void) CPrxAVIFile::CProxyImpl::Disconnect(void)
  869. {
  870. if (m_pPrxAVIFile->m_pRpcChannelBuffer)
  871. {
  872. m_pPrxAVIFile->m_pRpcChannelBuffer->Release();
  873. m_pPrxAVIFile->m_pRpcChannelBuffer = NULL;
  874. }
  875. }
  876. // IUnknown methods for external interface(s); always delegate
  877. STDMETHODIMP CPrxAVIFile::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  878. {
  879. return m_pUnkOuter->QueryInterface(iid, ppv);
  880. }
  881. STDMETHODIMP_(ULONG) CPrxAVIFile::AddRef(void)
  882. {
  883. return m_pUnkOuter->AddRef();
  884. }
  885. STDMETHODIMP_(ULONG) CPrxAVIFile::Release(void)
  886. {
  887. return m_pUnkOuter->Release();
  888. }
  889. // IAVIFile interface methods
  890. #ifdef WIN32
  891. STDMETHODIMP CPrxAVIFile::Info(AVIFILEINFOW FAR * psi, LONG lSize)
  892. #else
  893. STDMETHODIMP CPrxAVIFile::Info(AVIFILEINFO FAR * psi, LONG lSize)
  894. #endif
  895. {
  896. HRESULT hrMarshal;
  897. HRESULT hrMethod = NOERROR;
  898. IRpcChannelBuffer FAR* pChannel = m_pRpcChannelBuffer;
  899. if (pChannel == NULL)
  900. return ResultFromScode(RPC_E_CONNECTION_TERMINATED);
  901. if (m_fi.dwStreams == 0) {
  902. RPCOLEMESSAGE Message;
  903. _fmemset(&Message, 0, sizeof(Message));
  904. // format in: lSize
  905. // format out: hrMethod, PS_FILEINFO
  906. Message.cbBuffer = sizeof(lSize);
  907. Message.iMethod = IAVIFILE_Info;
  908. if ((hrMarshal = pChannel->GetBuffer(&Message, IID_IAVIFile)) != NOERROR)
  909. goto ErrExit;
  910. ((DWORD FAR *)Message.Buffer)[0] = sizeof(PS_FILEINFO);
  911. if ((hrMarshal = pChannel->SendReceive(&Message, (ULONG*) &hrMethod)) != NOERROR) {
  912. ;
  913. ErrExit:
  914. return PropagateResult(hrMarshal, RPC_E_CLIENT_CANTMARSHAL_DATA);
  915. }
  916. hrMethod = ((HRESULT FAR *)Message.Buffer)[0];
  917. PS_FILEINFO FAR * psinfo = (PS_FILEINFO FAR *)
  918. ((LPBYTE)Message.Buffer + sizeof(HRESULT));
  919. // get the bits we want
  920. m_fi.dwMaxBytesPerSec = psinfo->dwMaxBytesPerSec; // max. transfer rate
  921. m_fi.dwFlags = psinfo->dwFlags; // the ever-present flags
  922. m_fi.dwCaps = psinfo->dwCaps;
  923. m_fi.dwStreams = psinfo->dwStreams;
  924. m_fi.dwSuggestedBufferSize = psinfo->dwSuggestedBufferSize;
  925. m_fi.dwWidth = psinfo->dwWidth;
  926. m_fi.dwHeight = psinfo->dwHeight;
  927. m_fi.dwScale = psinfo->dwScale;
  928. m_fi.dwRate = psinfo->dwRate; /* dwRate / dwScale == samples/second */
  929. m_fi.dwLength = psinfo->dwLength;
  930. m_fi.dwEditCount = psinfo->dwEditCount;
  931. #ifdef WIN32
  932. // use unicode if we've been sent it
  933. if (psinfo->bHasUnicode) {
  934. _fmemcpy(m_fi.szFileType,
  935. psinfo->szUnicodeType, sizeof(m_fi.szFileType));
  936. } else {
  937. // need ansi->unicode thunk
  938. MultiByteToWideChar(
  939. CP_ACP, 0,
  940. psinfo->szFileType,
  941. -1,
  942. m_fi.szFileType,
  943. NUMELMS(m_fi.szFileType));
  944. }
  945. #else
  946. // we only use the ansi which is always sent
  947. _fmemcpy(m_fi.szFileType, psinfo->szFileType, sizeof(m_fi.szFileType));
  948. #endif
  949. pChannel->FreeBuffer(&Message);
  950. }
  951. _fmemcpy(psi, &m_fi, min((int) lSize, sizeof(m_fi)));
  952. return hrMethod;
  953. }
  954. #ifndef WIN32
  955. STDMETHODIMP CPrxAVIFile::Open(LPCTSTR szFile, UINT mode)
  956. {
  957. return ResultFromScode(E_NOTIMPL);
  958. }
  959. #endif
  960. STDMETHODIMP CPrxAVIFile::GetStream(PAVISTREAM FAR * ppStream,
  961. DWORD fccType,
  962. LONG lParam)
  963. {
  964. HRESULT hrMarshal;
  965. HRESULT hrMethod = NOERROR;
  966. IRpcChannelBuffer FAR* pChannel = m_pRpcChannelBuffer;
  967. if (pChannel == NULL)
  968. return ResultFromScode(RPC_E_CONNECTION_TERMINATED);
  969. RPCOLEMESSAGE Message;
  970. _fmemset(&Message, 0, sizeof(Message));
  971. // format in: fccType lParam
  972. // format out: returned interface (marshalled)
  973. Message.cbBuffer = sizeof(fccType) + sizeof(lParam);
  974. Message.iMethod = IAVIFILE_GetStream;
  975. if ((hrMarshal = pChannel->GetBuffer(&Message, IID_IAVIFile)) != NOERROR)
  976. goto ErrExit;
  977. ((DWORD FAR *)Message.Buffer)[0] = fccType;
  978. ((DWORD FAR *)Message.Buffer)[1] = lParam;
  979. if ((hrMarshal = pChannel->SendReceive(&Message, (ULONG*) &hrMethod)) != NOERROR) {
  980. ;
  981. ErrExit:
  982. return PropagateResult(hrMarshal, RPC_E_CLIENT_CANTMARSHAL_DATA);
  983. }
  984. hrMethod = ((HRESULT FAR *)Message.Buffer)[0];
  985. if (hrMethod == NOERROR) {
  986. HGLOBAL h;
  987. LPSTREAM pstm;
  988. h = GlobalAlloc(GHND, Message.cbBuffer - sizeof(hrMethod));
  989. hmemcpy(GlobalLock(h),
  990. (LPBYTE) Message.Buffer + sizeof(hrMethod),
  991. Message.cbBuffer - sizeof(hrMethod));
  992. CreateStreamOnHGlobal(h, FALSE, &pstm);
  993. CoUnmarshalInterface(pstm, IID_IAVIStream, (LPVOID FAR *) ppStream);
  994. pstm->Release();
  995. pChannel->FreeBuffer(&Message);
  996. }
  997. return hrMethod;
  998. }
  999. STDMETHODIMP CPrxAVIFile::CreateStream(
  1000. PAVISTREAM FAR * ppStream,
  1001. #ifdef WIN32
  1002. AVISTREAMINFOW FAR * psi)
  1003. #else
  1004. AVISTREAMINFO FAR * psi)
  1005. #endif
  1006. {
  1007. return ResultFromScode(E_NOTIMPL);
  1008. }
  1009. #ifndef WIN32
  1010. STDMETHODIMP CPrxAVIFile::Save(
  1011. LPCTSTR szFile,
  1012. AVICOMPRESSOPTIONS FAR *lpOptions,
  1013. AVISAVECALLBACK lpfnCallback)
  1014. {
  1015. return ResultFromScode(E_NOTIMPL);
  1016. }
  1017. #endif
  1018. STDMETHODIMP CPrxAVIFile::ReadData(DWORD ckid, LPVOID lp, LONG FAR *lpcb)
  1019. {
  1020. return ResultFromScode(E_NOTIMPL);
  1021. }
  1022. STDMETHODIMP CPrxAVIFile::WriteData(DWORD ckid, LPVOID lp, LONG cb)
  1023. {
  1024. return ResultFromScode(E_NOTIMPL);
  1025. }
  1026. STDMETHODIMP CPrxAVIFile::EndRecord()
  1027. {
  1028. return ResultFromScode(E_NOTIMPL);
  1029. }
  1030. #ifdef WIN32
  1031. STDMETHODIMP CPrxAVIFile::DeleteStream(DWORD fccType, LONG lParam)
  1032. {
  1033. return ResultFromScode(AVIERR_UNSUPPORTED);
  1034. }
  1035. #else
  1036. STDMETHODIMP CPrxAVIFile::Reserved1(void)
  1037. {
  1038. return ResultFromScode(E_NOTIMPL);
  1039. }
  1040. STDMETHODIMP CPrxAVIFile::Reserved2(void)
  1041. {
  1042. return ResultFromScode(E_NOTIMPL);
  1043. }
  1044. STDMETHODIMP CPrxAVIFile::Reserved3(void)
  1045. {
  1046. return ResultFromScode(E_NOTIMPL);
  1047. }
  1048. STDMETHODIMP CPrxAVIFile::Reserved4(void)
  1049. {
  1050. return ResultFromScode(E_NOTIMPL);
  1051. }
  1052. STDMETHODIMP CPrxAVIFile::Reserved5(void)
  1053. {
  1054. return ResultFromScode(E_NOTIMPL);
  1055. }
  1056. #endif
  1057. /*
  1058. * IMPLEMENTATION of CStubAVIFile
  1059. *
  1060. */
  1061. // create connected interface stub
  1062. HRESULT CStubAVIFile::Create(IUnknown FAR* pUnkObject, IRpcStubBuffer FAR* FAR* ppStub)
  1063. {
  1064. CStubAVIFile FAR* pStubAVIFile;
  1065. *ppStub = NULL;
  1066. if ((pStubAVIFile = new CStubAVIFile()) == NULL)
  1067. return ResultFromScode(E_OUTOFMEMORY);
  1068. HRESULT hresult;
  1069. if ((hresult = pStubAVIFile->Connect(pUnkObject)) != NOERROR)
  1070. {
  1071. pStubAVIFile->Release();
  1072. return hresult;
  1073. }
  1074. *ppStub = pStubAVIFile;
  1075. return NOERROR;
  1076. }
  1077. CStubAVIFile::CStubAVIFile(void)
  1078. {
  1079. m_refs = 1;
  1080. m_pAVIFile = NULL;
  1081. RegisterStubUsage();
  1082. }
  1083. CStubAVIFile::~CStubAVIFile(void)
  1084. {
  1085. UnregisterStubUsage();
  1086. Disconnect();
  1087. }
  1088. // controling unknown methods for interface stub
  1089. STDMETHODIMP CStubAVIFile::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  1090. {
  1091. if (iid == IID_IUnknown || iid == IID_IRpcStubBuffer)
  1092. {
  1093. *ppv = this;
  1094. ++m_refs;
  1095. return NOERROR;
  1096. }
  1097. else
  1098. {
  1099. *ppv = NULL;
  1100. return ResultFromScode(E_NOINTERFACE);
  1101. }
  1102. }
  1103. STDMETHODIMP_(ULONG) CStubAVIFile::AddRef(void)
  1104. {
  1105. return ++m_refs;
  1106. }
  1107. STDMETHODIMP_(ULONG) CStubAVIFile::Release(void)
  1108. {
  1109. if (--m_refs == 0)
  1110. {
  1111. delete this;
  1112. return 0;
  1113. }
  1114. return m_refs;
  1115. }
  1116. // connect interface stub to server object
  1117. STDMETHODIMP CStubAVIFile::Connect(IUnknown FAR* pUnkObj)
  1118. {
  1119. if (m_pAVIFile)
  1120. // call Disconnect first
  1121. return ResultFromScode(E_UNEXPECTED);
  1122. if (pUnkObj == NULL)
  1123. return ResultFromScode(E_INVALIDARG);
  1124. // NOTE: QI ensures out param is zero if error
  1125. return pUnkObj->QueryInterface(IID_IAVIFile, (LPVOID FAR*)&m_pAVIFile);
  1126. }
  1127. // disconnect interface stub from server objec
  1128. STDMETHODIMP_(void) CStubAVIFile::Disconnect(void)
  1129. {
  1130. if (m_pAVIFile) {
  1131. m_pAVIFile->Release();
  1132. m_pAVIFile = NULL;
  1133. }
  1134. }
  1135. // remove method call
  1136. STDMETHODIMP CStubAVIFile::Invoke
  1137. (RPCOLEMESSAGE FAR *pMessage, IRpcChannelBuffer FAR *pChannel)
  1138. {
  1139. HRESULT hresult;
  1140. HRESULT hrMethod;
  1141. if (!m_pAVIFile)
  1142. return ResultFromScode(RPC_E_UNEXPECTED);
  1143. #if 0
  1144. if (iid != IID_IAVIFile)
  1145. return ResultFromScode(RPC_E_UNEXPECTED);
  1146. #endif
  1147. switch (pMessage->iMethod)
  1148. {
  1149. case IAVIFILE_Info:
  1150. // format on input: lSize
  1151. // format on output: hresult, AVIFILEINFO
  1152. {
  1153. DWORD lSize;
  1154. #ifdef WIN32
  1155. AVIFILEINFOW si;
  1156. #else
  1157. AVIFILEINFO si;
  1158. #endif
  1159. PS_FILEINFO psinfo;
  1160. hrMethod = m_pAVIFile->Info(&si, sizeof(si));
  1161. // copy all members
  1162. psinfo.dwMaxBytesPerSec = si.dwMaxBytesPerSec;
  1163. psinfo.dwFlags = si.dwFlags;
  1164. psinfo.dwCaps = si.dwCaps;
  1165. psinfo.dwStreams = si.dwStreams;
  1166. psinfo.dwSuggestedBufferSize = si.dwSuggestedBufferSize;
  1167. psinfo.dwWidth = si.dwWidth;
  1168. psinfo.dwHeight = si.dwHeight;
  1169. psinfo.dwScale = si.dwScale;
  1170. psinfo.dwRate = si.dwRate;
  1171. psinfo.dwLength = si.dwLength;
  1172. psinfo.dwEditCount = si.dwEditCount;
  1173. #ifdef WIN32
  1174. // send both UNICODE and ansi
  1175. hmemcpy(psinfo.szUnicodeType, si.szFileType, NUMELMS(psinfo.szFileType));
  1176. psinfo.bHasUnicode = TRUE;
  1177. WideCharToMultiByte(CP_ACP, 0,
  1178. si.szFileType,
  1179. -1,
  1180. psinfo.szFileType,
  1181. NUMELMS(psinfo.szFileType),
  1182. NULL, NULL);
  1183. #else
  1184. // just send ansi version for 16-bit stub
  1185. psinfo.bHasUnicode = FALSE;
  1186. hmemcpy(psinfo.szFileType, si.szFileType, sizeof(si.szFileType));
  1187. #endif
  1188. lSize = ((DWORD FAR *)pMessage->Buffer)[0];
  1189. pMessage->cbBuffer = lSize + sizeof(hrMethod);
  1190. if ((hresult = pChannel->GetBuffer(pMessage, IID_IAVIStream)) != NOERROR)
  1191. return PropagateResult(hresult, RPC_E_SERVER_CANTUNMARSHAL_DATA);
  1192. ((HRESULT FAR *)pMessage->Buffer)[0] = hrMethod;
  1193. hmemcpy((LPBYTE) pMessage->Buffer + sizeof(hrMethod),
  1194. &psinfo,
  1195. lSize);
  1196. return NOERROR;
  1197. }
  1198. case IAVIFILE_GetStream:
  1199. // format on input: fccType, lParam
  1200. // format on output: marshalled IAVIStream pointer
  1201. {
  1202. DWORD lParam, fccType;
  1203. PAVISTREAM ps;
  1204. HGLOBAL h;
  1205. DWORD dwDestCtx = 0;
  1206. LPVOID pvDestCtx = NULL;
  1207. DWORD cb;
  1208. LPSTREAM pstm;
  1209. fccType = ((DWORD FAR *)pMessage->Buffer)[0];
  1210. lParam = ((DWORD FAR *)pMessage->Buffer)[1];
  1211. hrMethod = m_pAVIFile->GetStream(&ps, fccType, lParam);
  1212. if (hrMethod == NOERROR) {
  1213. pChannel->GetDestCtx(&dwDestCtx, &pvDestCtx);
  1214. #ifdef WIN32
  1215. cb = 0;
  1216. CoGetMarshalSizeMax(&cb, IID_IAVIStream, ps,
  1217. dwDestCtx, pvDestCtx, MSHLFLAGS_NORMAL);
  1218. #else
  1219. cb = 800; // !!!!!!!
  1220. #endif
  1221. h = GlobalAlloc(GHND, cb);
  1222. CreateStreamOnHGlobal(h, FALSE, &pstm);
  1223. CoMarshalInterface(pstm, IID_IAVIStream, ps,
  1224. dwDestCtx, pvDestCtx, MSHLFLAGS_NORMAL);
  1225. pstm->Release();
  1226. } else
  1227. cb = 0;
  1228. pMessage->cbBuffer = cb + sizeof(hrMethod);
  1229. if ((hresult = pChannel->GetBuffer(pMessage, IID_IAVIStream)) != NOERROR)
  1230. return PropagateResult(hresult, RPC_E_SERVER_CANTUNMARSHAL_DATA);
  1231. ((HRESULT FAR *)pMessage->Buffer)[0] = hrMethod;
  1232. if (cb) {
  1233. hmemcpy((LPBYTE) pMessage->Buffer + sizeof(hrMethod),
  1234. GlobalLock(h), cb);
  1235. GlobalFree(h);
  1236. }
  1237. return NOERROR;
  1238. }
  1239. default:
  1240. // unknown method
  1241. return ResultFromScode(RPC_E_UNEXPECTED);
  1242. }
  1243. }
  1244. // return TRUE if we support given interface
  1245. STDMETHODIMP_(IRpcStubBuffer FAR *) CStubAVIFile::IsIIDSupported(REFIID iid)
  1246. {
  1247. // if we are connected, we have already checked for this interface;
  1248. // if we are not connected, it doesn't matter.
  1249. return iid == IID_IAVIFile ? (IRpcStubBuffer *) this : 0;
  1250. }
  1251. // returns number of refs we have to object
  1252. STDMETHODIMP_(ULONG) CStubAVIFile::CountRefs(void)
  1253. {
  1254. // return 1 if connected; 0 if not.
  1255. return m_pAVIFile != NULL;
  1256. }
  1257. STDMETHODIMP CStubAVIFile::DebugServerQueryInterface(LPVOID FAR *ppv)
  1258. {
  1259. *ppv = m_pAVIFile;
  1260. if (!m_pAVIFile) {
  1261. DPF("!No File!\n");
  1262. return ResultFromScode(E_UNEXPECTED);
  1263. }
  1264. return NOERROR;
  1265. }
  1266. STDMETHODIMP_(void) CStubAVIFile::DebugServerRelease(LPVOID pv)
  1267. {
  1268. }
  1269. //
  1270. // The following functions exist to allow an application to determine
  1271. // if another application is using any of its objects.
  1272. //
  1273. // !!!!!! I don't know if this really works.
  1274. //
  1275. #define MAXTASKCACHE 64
  1276. HTASK ahtaskUsed[MAXTASKCACHE];
  1277. int aiRefCount[MAXTASKCACHE];
  1278. void RegisterStubUsage(void)
  1279. {
  1280. HTASK htask = GetCurrentTask();
  1281. int i;
  1282. for (i = 0; i < MAXTASKCACHE; i++) {
  1283. if (ahtaskUsed[i] == htask) {
  1284. ++aiRefCount[i];
  1285. return;
  1286. }
  1287. }
  1288. for (i = 0; i < MAXTASKCACHE; i++) {
  1289. if (ahtaskUsed[i] == NULL) {
  1290. ahtaskUsed[i] = htask;
  1291. aiRefCount[i] = 1;
  1292. return;
  1293. }
  1294. }
  1295. DPF("Ack: Proxy cache full!\n");
  1296. }
  1297. void UnregisterStubUsage(void)
  1298. {
  1299. HTASK htask = GetCurrentTask();
  1300. int i;
  1301. for (i = 0; i < MAXTASKCACHE; i++) {
  1302. if (ahtaskUsed[i] == htask) {
  1303. if (--aiRefCount[i] <= 0) {
  1304. ahtaskUsed[i] = NULL;
  1305. aiRefCount[i] = 0;
  1306. }
  1307. return;
  1308. }
  1309. }
  1310. DPF("Ack: Proxy not in cache!\n");
  1311. }
  1312. BOOL FAR TaskHasExistingProxies(void)
  1313. {
  1314. HTASK htask = GetCurrentTask();
  1315. int i;
  1316. for (i = 0; i < MAXTASKCACHE; i++) {
  1317. if (ahtaskUsed[i] == htask) {
  1318. return TRUE;
  1319. }
  1320. }
  1321. return FALSE;
  1322. }
  1323.