Leaked source code of windows server 2003
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.

727 lines
22 KiB

  1. /*****************************************************************************
  2. *
  3. * DICal.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Functions that manage axis ramps and calibration.
  10. *
  11. * Structure names begin with "Joy" for historical reasons.
  12. *
  13. * Contents:
  14. *
  15. * CCal_CookRange
  16. * CCal_RecalcRange
  17. *
  18. *****************************************************************************/
  19. #include "dinputpr.h"
  20. /*****************************************************************************
  21. *
  22. * The sqiffle for this file.
  23. *
  24. *****************************************************************************/
  25. #define sqfl sqflCal
  26. /*****************************************************************************
  27. *
  28. * @doc INTERNAL
  29. *
  30. * @func LONG | CCal_MulDiv |
  31. *
  32. * High-speed MulDiv for Intel x86 boxes. Otherwise, uses
  33. * the standard MulDiv. The values involved are always
  34. * nonnegative.
  35. *
  36. * @parm LONG | lA |
  37. *
  38. * Multiplicand.
  39. *
  40. * @parm LONG | lB |
  41. *
  42. * Multiplier.
  43. *
  44. * @parm LONG | lC |
  45. *
  46. * Denominator.
  47. *
  48. * @returns
  49. *
  50. * lA * lB / lC, with 64-bit intermediate precision.
  51. *
  52. *****************************************************************************/
  53. #if defined(_X86_)
  54. #pragma warning(disable:4035) /* no return value (duh) */
  55. __declspec(naked) LONG EXTERNAL
  56. CCal_MulDiv(LONG lA, LONG lB, LONG lC)
  57. {
  58. lA; lB; lC;
  59. _asm {
  60. mov eax, [esp+4]
  61. mul dword ptr [esp+8]
  62. div dword ptr [esp+12]
  63. ret 12
  64. }
  65. }
  66. #pragma warning(default:4035)
  67. #endif
  68. /*****************************************************************************
  69. *
  70. * @doc INTERNAL
  71. *
  72. * @method void | CCal | CookAxisPOV |
  73. *
  74. * Cook a piece of POV data into one of five defined data.
  75. *
  76. * @cwrap PJOYRANGECONVERT | this
  77. *
  78. * @parm INOUT PLONG | pl |
  79. *
  80. * On entry, contains the raw value. On exit, contains the
  81. * cooked value. (Or the raw value if the axis is raw.)
  82. *
  83. * @returns
  84. *
  85. * None.
  86. *
  87. *****************************************************************************/
  88. #ifdef WINNT
  89. void CookAxisPOV( PJOYRANGECONVERT this, LONG UNALIGNED *pl )
  90. {
  91. LONG l;
  92. /*
  93. * figure out which direction this value indicates...
  94. */
  95. if( (*pl > this->lMinPOV[JOY_POVVAL_FORWARD])
  96. &&(*pl < this->lMaxPOV[JOY_POVVAL_FORWARD]) )
  97. {
  98. l = JOY_POVFORWARD;
  99. }
  100. else if( (*pl > this->lMinPOV[JOY_POVVAL_BACKWARD])
  101. &&(*pl < this->lMaxPOV[JOY_POVVAL_BACKWARD]) )
  102. {
  103. l = JOY_POVBACKWARD;
  104. }
  105. else if( (*pl > this->lMinPOV[JOY_POVVAL_LEFT])
  106. &&(*pl < this->lMaxPOV[JOY_POVVAL_LEFT]) )
  107. {
  108. l = JOY_POVLEFT;
  109. }
  110. else if( (*pl > this->lMinPOV[JOY_POVVAL_RIGHT])
  111. &&(*pl < this->lMaxPOV[JOY_POVVAL_RIGHT]) )
  112. {
  113. l = JOY_POVRIGHT;
  114. }
  115. else
  116. {
  117. l = JOY_POVCENTERED;
  118. }
  119. #if 0
  120. {
  121. TCHAR buf[100];
  122. wsprintf(buf, TEXT("calibrated pov: %d\r\n"), l);
  123. OutputDebugString(buf);
  124. }
  125. #endif
  126. *pl = l;
  127. }
  128. #endif
  129. /*****************************************************************************
  130. *
  131. * @doc INTERNAL
  132. *
  133. * @method void | CCal | CookRange |
  134. *
  135. * Cook a piece of phys data into a range.
  136. *
  137. * @cwrap PJOYRANGECONVERT | this
  138. *
  139. * @parm INOUT PLONG | pl |
  140. *
  141. * On entry, contains the raw value. On exit, contains the
  142. * cooked value. (Or the raw value if the axis is raw.)
  143. *
  144. * @returns
  145. *
  146. * None.
  147. *
  148. *****************************************************************************/
  149. void EXTERNAL
  150. CCal_CookRange(PJOYRANGECONVERT this, LONG UNALIGNED *pl)
  151. {
  152. if (this->fRaw) {
  153. /*
  154. * Nothing to do!
  155. */
  156. } else {
  157. #ifdef WINNT
  158. if( this->fPolledPOV ) {
  159. CookAxisPOV( this, pl );
  160. } else
  161. #endif
  162. {
  163. LONG lRc = 0;
  164. LONG l;
  165. PCJOYRAMP prmp;
  166. l = *pl;
  167. /*
  168. * Choose the low or high ramp, depending on which side we're in.
  169. *
  170. * This comparison could've been against Dmax or Dmin or Pc.
  171. * We must use Dmax because we jiggered up the rmpHigh so
  172. * that it rounds properly, so we can't use the flat part
  173. * below rmpHigh.x because it's at the wrong level.
  174. */
  175. if (l < this->rmpHigh.x) {
  176. prmp = &this->rmpLow;
  177. } else {
  178. prmp = &this->rmpHigh;
  179. }
  180. if (l <= prmp->x) {
  181. lRc = 0;
  182. } else {
  183. l -= prmp->x;
  184. if ((DWORD)l < prmp->dx) {
  185. /*
  186. * Note that prmp->dx cannot be zero because it
  187. * is greater than something!
  188. */
  189. lRc = CCal_MulDiv((DWORD)l, prmp->dy, prmp->dx);
  190. } else {
  191. lRc = prmp->dy;
  192. }
  193. }
  194. lRc += prmp->y;
  195. if( this->dwCPointsNum > 2 )
  196. {
  197. LONG l2 = *pl;
  198. BOOL fCooked = FALSE;
  199. DWORD i;
  200. if( l2 < this->rmpLow.x || l2 > (this->rmpHigh.x + (LONG)this->rmpHigh.dx) || //in Saturation Zone
  201. ( l2 > (this->rmpLow.x + (LONG)this->rmpLow.dx) && l2 < this->rmpHigh.x ) //in Dead Zone
  202. ) {
  203. //RPF( "Raw: %d Cooked: %ld in Saturation or Dead Zone." );
  204. goto _exitcp;
  205. }
  206. for(i=0; i<this->dwCPointsNum-1; i++) {
  207. if( l2 >= this->cp[i].lP && l2 < this->cp[i+1].lP ) {
  208. l2 -= this->cp[i].lP;
  209. if( this->cp[i+1].dwLog > this->cp[i].dwLog ) {
  210. lRc = CCal_MulDiv((DWORD)l2,
  211. this->cp[i+1].dwLog - this->cp[i].dwLog,
  212. this->cp[i+1].lP - this->cp[i].lP);
  213. } else {
  214. lRc = -1 * CCal_MulDiv((DWORD)l2,
  215. this->cp[i].dwLog - this->cp[i+1].dwLog,
  216. this->cp[i+1].lP - this->cp[i].lP);
  217. }
  218. lRc += this->cp[i].dwLog;
  219. AssertF(lRc >= 0);
  220. AssertF(this->lMax >= this->lMin);
  221. lRc = CCal_MulDiv((DWORD)lRc,
  222. this->lMax - this->lMin + 1,
  223. RANGEDIVISIONS);
  224. lRc += this->lMin;
  225. fCooked = TRUE;
  226. #if 0
  227. RPF( "Raw: %d Cooked: %ld Area %d: (%d - %d) -> (%d - %d)",
  228. *pl, lRc, i, this->cp[i].lP, this->cp[i+1].lP,
  229. this->cp[i].dwLog, this->cp[i+1].dwLog );
  230. #endif
  231. break;
  232. }
  233. }
  234. _exitcp:
  235. ;
  236. }
  237. *pl = lRc;
  238. }
  239. }
  240. }
  241. /*****************************************************************************
  242. *
  243. * @doc INTERNAL
  244. *
  245. * @method void | CCal | RecalcRange |
  246. *
  247. * Compute all the values that derive from the user's
  248. * range settings.
  249. *
  250. * Be careful not to create values that will cause us to
  251. * divide by zero later. Fortunately,
  252. * <f CCal_CookRange> never divides by zero due to the
  253. * clever way it was written.
  254. *
  255. * @cwrap PJOYRANGECONVERT | this
  256. *
  257. * @returns
  258. *
  259. * None.
  260. *
  261. *****************************************************************************/
  262. void EXTERNAL
  263. CCal_RecalcRange(PJOYRANGECONVERT this)
  264. {
  265. int dx;
  266. DWORD dwSat;
  267. AssertF(this->dwDz <= RANGEDIVISIONS);
  268. AssertF(this->dwSat <= RANGEDIVISIONS);
  269. AssertF(this->lMin <= this->lC);
  270. AssertF(this->lC <= this->lMax);
  271. dwSat = max(this->dwSat, this->dwDz);
  272. /* Smin - Bottom of saturation range */
  273. dx = CCal_MulDiv(this->dwPc - this->dwPmin, dwSat, RANGEDIVISIONS);
  274. this->rmpLow.x = this->dwPc - dx;
  275. /* Dmin - Bottom of dead zone */
  276. dx = CCal_MulDiv(this->dwPc - this->dwPmin, this->dwDz, RANGEDIVISIONS);
  277. this->rmpLow.dx = (this->dwPc - dx) - this->rmpLow.x;
  278. /*
  279. * Establish the vertical extent of the low end of the ramp.
  280. */
  281. this->rmpLow.y = this->lMin;
  282. this->rmpLow.dy = this->lC - this->lMin;
  283. /* Dmax - Top of the dead zone */
  284. dx = CCal_MulDiv(this->dwPmax - this->dwPc, this->dwDz, RANGEDIVISIONS);
  285. if (this->dwPmax > this->dwPc+1){
  286. this->rmpHigh.x = this->dwPc + dx + 1;
  287. } else {
  288. this->rmpHigh.x = this->dwPc + dx;
  289. }
  290. /* Smax - Top of the saturation range */
  291. dx = CCal_MulDiv(this->dwPmax - this->dwPc, dwSat, RANGEDIVISIONS);
  292. this->rmpHigh.dx = (this->dwPc + dx) - this->rmpHigh.x;
  293. /*
  294. * Establish the vertical extent of the high end of the ramp.
  295. *
  296. * If the high end is zero, then the entire ramp is zero.
  297. * Otherwise, put the bottom at +1 so that when the user
  298. * just barely leaves the dead zone, we report a nonzero
  299. * value. Note: If we were really clever, we could use
  300. * a bias to get "round upwards", but it's not worth it.
  301. *
  302. */
  303. if ( (this->lMax > this->lC) && (this->dwPmax > this->dwPc+1) ) {
  304. this->rmpHigh.y = this->lC + 1;
  305. } else {
  306. this->rmpHigh.y = this->lC;
  307. }
  308. this->rmpHigh.dy = this->lMax - this->rmpHigh.y;
  309. #if 0
  310. RPF( "Raw: %d Dead Zone: 0x%08x Saturation: 0x%08x",
  311. this->fRaw, this->dwDz, this->dwSat );
  312. RPF( "Physical min: 0x%08x max: 0x%08x cen: 0x%08x",
  313. this->lMin, this->lMax, this->lC );
  314. RPF( "Logical min: 0x%08x max: 0x%08x cen: 0x%08x",
  315. this->dwPmin, this->dwPmax, this->dwPc );
  316. RPF( "Lo ramp X: 0x%08x dX: 0x%08x Y: 0x%08x dY: 0x%08x",
  317. this->rmpLow.x, this->rmpLow.dx, this->rmpLow.y, this->rmpLow.dy );
  318. RPF( "Hi ramp X: 0x%08x dX: 0x%08x Y: 0x%08x dY: 0x%08x",
  319. this->rmpHigh.x, this->rmpHigh.dx, this->rmpHigh.y, this->rmpHigh.dy );
  320. #endif
  321. }
  322. /*****************************************************************************
  323. *
  324. * @doc INTERNAL
  325. *
  326. * @method HRESULT | CCal | GetProperty |
  327. *
  328. * Read a property from a calibration structure.
  329. *
  330. * The caller is permitted to pass a property that doesn't
  331. * apply to calibration, in which case <c E_NOTIMPL>
  332. * is returned, as it should be.
  333. *
  334. * @cwrap PJOYRANGECONVERT | this
  335. *
  336. * @parm REFGUID | rguid |
  337. *
  338. * The property being retrieved.
  339. *
  340. * @parm IN REFGUID | rguid |
  341. *
  342. * The identity of the property to be obtained.
  343. *
  344. * @parm IN LPDIPROPHEADER | pdiph |
  345. *
  346. * Points to the <t DIPROPHEADER> portion of a structure
  347. * which depends on the property.
  348. *
  349. * @returns
  350. *
  351. * <c S_OK> if the operation completed successfully.
  352. *
  353. * <c E_NOTIMPL> nothing happened. The caller will do
  354. * the default thing in response to <c E_NOTIMPL>.
  355. *
  356. *****************************************************************************/
  357. STDMETHODIMP
  358. CCal_GetProperty(PJOYRANGECONVERT this, REFGUID rguid, LPDIPROPHEADER pdiph)
  359. {
  360. HRESULT hres;
  361. LPDIPROPRANGE pdiprg = CONTAINING_RECORD(pdiph, DIPROPRANGE, diph);
  362. LPDIPROPDWORD pdipdw = CONTAINING_RECORD(pdiph, DIPROPDWORD, diph);
  363. LPDIPROPCAL pdipcal = CONTAINING_RECORD(pdiph, DIPROPCAL , diph);
  364. LPDIPROPCPOINTS pdipcps = CONTAINING_RECORD(pdiph, DIPROPCPOINTS , diph);
  365. EnterProc(CCal::GetProperty, (_ "pxp", this, rguid, pdiph));
  366. switch ((DWORD)(UINT_PTR)rguid) {
  367. case (DWORD)(UINT_PTR)DIPROP_RANGE:
  368. pdiprg->lMin = this->lMin;
  369. pdiprg->lMax = this->lMax;
  370. hres = S_OK;
  371. break;
  372. case (DWORD)(UINT_PTR)DIPROP_DEADZONE:
  373. pdipdw->dwData = this->dwDz;
  374. hres = S_OK;
  375. break;
  376. case (DWORD)(UINT_PTR)DIPROP_SATURATION:
  377. pdipdw->dwData = this->dwSat;
  378. hres = S_OK;
  379. break;
  380. case (DWORD)(UINT_PTR)DIPROP_CALIBRATIONMODE:
  381. pdipdw->dwData = this->fRaw;
  382. hres = S_OK;
  383. break;
  384. case (DWORD)(UINT_PTR)DIPROP_CALIBRATION:
  385. pdipcal->lMin = this->dwPmin;
  386. pdipcal->lMax = this->dwPmax;
  387. pdipcal->lCenter = this->dwPc;
  388. hres = S_OK;
  389. break;
  390. case (DWORD)(UINT_PTR)DIPROP_CPOINTS:
  391. pdipcps->dwCPointsNum = this->dwCPointsNum;
  392. memcpy( &pdipcps->cp, &this->cp, sizeof(this->cp) );
  393. hres = S_OK;
  394. break;
  395. default:
  396. hres = E_NOTIMPL;
  397. break;
  398. }
  399. ExitOleProc();
  400. return hres;
  401. }
  402. /*****************************************************************************
  403. *
  404. * @doc INTERNAL
  405. *
  406. * @method HRESULT | CCal | SetCalibration |
  407. *
  408. * The app (hopefully a control panel) is changing the
  409. * calibration.
  410. *
  411. * @cwrap PJOYRANGECONVERT | this
  412. *
  413. * @parm IN LPCDIPROPINFO | ppropi |
  414. *
  415. * Information describing the property being set.
  416. *
  417. * @parm IN LPCDIPROPHEADER | pdiph |
  418. *
  419. * Points to the <t DIPROPHEADER> portion of a structure
  420. * which depends on the property.
  421. *
  422. * @parm HKEY | hkType |
  423. *
  424. * Registry key to use calibration information.
  425. *
  426. * @returns
  427. *
  428. * <c S_OK> if the operation completed successfully.
  429. *
  430. * <c E_NOTIMPL> nothing happened. The caller will do
  431. * the default thing in response to <c E_NOTIMPL>.
  432. *
  433. *****************************************************************************/
  434. STDMETHODIMP
  435. CCal_SetCalibration(PJOYRANGECONVERT this, LPCDIPROPINFO ppropi,
  436. LPCDIPROPHEADER pdiph, HKEY hkType)
  437. {
  438. HRESULT hres;
  439. #ifdef WINNT
  440. if( ppropi->dwDevType == DIDFT_POV ) {
  441. if( this->fPolledPOV ) {
  442. LPCDIPROPCALPOV pdipcalpov = CONTAINING_RECORD(pdiph, DIPROPCALPOV, diph);
  443. if (hkType) {
  444. LPDIPOVCALIBRATION ppov;
  445. HKEY hk;
  446. /*
  447. * We pun a DIPROPCALPOV as a DIPOVCALIBRATION.
  448. */
  449. #define CheckField(f) \
  450. CAssertF(FIELD_OFFSET(DIPROPCALPOV, l##f) - cbX(DIPROPHEADER) == \
  451. FIELD_OFFSET(DIPOVCALIBRATION, l##f))
  452. CheckField(Min);
  453. CheckField(Max);
  454. #undef CheckField
  455. ppov = pvAddPvCb(pdipcalpov, cbX(DIPROPHEADER));
  456. AssertF( !memcmp(ppov->lMin, pdipcalpov->lMin, cbX(DIPOVCALIBRATION)) );
  457. AssertF( !memcmp(ppov->lMax, pdipcalpov->lMax, cbX(DIPOVCALIBRATION)) );
  458. hres = CType_OpenIdSubkey(hkType, ppropi->dwDevType,
  459. DI_KEY_ALL_ACCESS, &hk);
  460. if (SUCCEEDED(hres)) {
  461. /*
  462. * All 0x0's for calibration is our cue to reset
  463. * to default values.
  464. */
  465. if( ppov->lMin[0] == ppov->lMin[1] == ppov->lMin[2] == ppov->lMin[3] == ppov->lMin[4] ==
  466. ppov->lMax[0] == ppov->lMax[1] == ppov->lMax[2] == ppov->lMax[3] == ppov->lMax[4] == 0 )
  467. {
  468. RegDeleteValue(hk, TEXT("Calibration")) ;
  469. } else
  470. {
  471. hres = JoyReg_SetValue(hk, TEXT("Calibration"),
  472. REG_BINARY, ppov,
  473. cbX(DIPOVCALIBRATION));
  474. }
  475. RegCloseKey(hk);
  476. }
  477. } else {
  478. hres = S_FALSE;
  479. }
  480. if (SUCCEEDED(hres)) {
  481. memcpy( this->lMinPOV, pdipcalpov->lMin, cbX(pdipcalpov->lMin) );
  482. memcpy( this->lMaxPOV, pdipcalpov->lMax, cbX(pdipcalpov->lMax) );
  483. }
  484. } else {
  485. hres = E_NOTIMPL;
  486. }
  487. } else
  488. #endif
  489. {
  490. LPCDIPROPCAL pdipcal = CONTAINING_RECORD(pdiph, DIPROPCAL, diph);
  491. if (hkType) {
  492. LPDIOBJECTCALIBRATION pcal;
  493. HKEY hk;
  494. /*
  495. * We pun a DIPROPCAL as a DIOBJECTCALIBRATION.
  496. */
  497. #define CheckField(f) \
  498. CAssertF(FIELD_OFFSET(DIPROPCAL, l##f) - cbX(DIPROPHEADER) == \
  499. FIELD_OFFSET(DIOBJECTCALIBRATION, l##f))
  500. CheckField(Min);
  501. CheckField(Max);
  502. CheckField(Center);
  503. #undef CheckField
  504. pcal = pvAddPvCb(pdipcal, cbX(DIPROPHEADER));
  505. AssertF(pcal->lMin == pdipcal->lMin);
  506. AssertF(pcal->lMax == pdipcal->lMax);
  507. AssertF(pcal->lCenter == pdipcal->lCenter);
  508. hres = CType_OpenIdSubkey(hkType, ppropi->dwDevType,
  509. DI_KEY_ALL_ACCESS, &hk);
  510. if (SUCCEEDED(hres)) {
  511. /*
  512. * All 0x0's for calibration is our cue to reset
  513. * to default values.
  514. */
  515. if( pcal->lMin == pcal->lMax &&
  516. pcal->lCenter == pcal->lMax &&
  517. pcal->lMax == 0x0 )
  518. {
  519. RegDeleteValue(hk, TEXT("Calibration")) ;
  520. } else
  521. {
  522. hres = JoyReg_SetValue(hk, TEXT("Calibration"),
  523. REG_BINARY, pcal,
  524. cbX(DIOBJECTCALIBRATION));
  525. }
  526. RegCloseKey(hk);
  527. }
  528. } else {
  529. hres = S_FALSE;
  530. }
  531. if (SUCCEEDED(hres)) {
  532. this->dwPmin = pdipcal->lMin;
  533. this->dwPmax = pdipcal->lMax;
  534. this->dwPc = pdipcal->lCenter;
  535. CCal_RecalcRange(this);
  536. }
  537. }
  538. return hres;
  539. }
  540. /*****************************************************************************
  541. *
  542. * @doc INTERNAL
  543. *
  544. * @method HRESULT | CCal | SetProperty |
  545. *
  546. * Write a property to a calibration structure.
  547. *
  548. * The caller is permitted to pass a property that doesn't
  549. * apply to calibration, in which case <c E_NOTIMPL>
  550. * is returned, as it should be.
  551. *
  552. * @cwrap PJOYRANGECONVERT | this
  553. *
  554. * @parm IN LPCDIPROPINFO | ppropi |
  555. *
  556. * Information describing the property being set.
  557. *
  558. * @parm IN LPDIPROPHEADER | pdiph |
  559. *
  560. * Points to the <t DIPROPHEADER> portion of a structure
  561. * which depends on the property.
  562. *
  563. * @parm HKEY | hkType |
  564. *
  565. * Registry key to use if setting calibration information.
  566. *
  567. * @returns
  568. *
  569. * <c S_OK> if the operation completed successfully.
  570. *
  571. * <c E_NOTIMPL> nothing happened. The caller will do
  572. * the default thing in response to <c E_NOTIMPL>.
  573. *
  574. *****************************************************************************/
  575. STDMETHODIMP
  576. CCal_SetProperty(PJOYRANGECONVERT this, LPCDIPROPINFO ppropi,
  577. LPCDIPROPHEADER pdiph, HKEY hkType)
  578. {
  579. HRESULT hres;
  580. LPCDIPROPRANGE pdiprg = (PCV)pdiph;
  581. LPCDIPROPDWORD pdipdw = (PCV)pdiph;
  582. LPCDIPROPCPOINTS pdipcps = (PCV)pdiph;
  583. LPDWORD pdw;
  584. EnterProc(CCal::SetProperty, (_ "pxp", this, ppropi->pguid, pdiph));
  585. switch ((DWORD)(UINT_PTR)ppropi->pguid) {
  586. case (DWORD)(UINT_PTR)DIPROP_RANGE:
  587. if (pdiprg->lMin <= pdiprg->lMax) {
  588. this->lMin = pdiprg->lMin;
  589. this->lMax = pdiprg->lMax;
  590. this->lC = CCal_Midpoint(this->lMin, this->lMax);
  591. CCal_RecalcRange(this);
  592. SquirtSqflPtszV(sqflCal,
  593. TEXT("CCal_SetProperty:DIPROP_RANGE: lMin: %08x, lMax: %08x"),
  594. this->lMin, this->lMax );
  595. hres = S_OK;
  596. } else {
  597. RPF("ERROR DIPROP_RANGE: lMin must be <= lMax");
  598. hres = E_INVALIDARG;
  599. }
  600. break;
  601. case (DWORD)(UINT_PTR)DIPROP_DEADZONE:
  602. pdw = &this->dwDz;
  603. goto finishfraction;
  604. case (DWORD)(UINT_PTR)DIPROP_SATURATION:
  605. pdw = &this->dwSat;
  606. goto finishfraction;
  607. finishfraction:;
  608. if (pdipdw->dwData <= RANGEDIVISIONS) {
  609. *pdw = pdipdw->dwData;
  610. CCal_RecalcRange(this);
  611. hres = S_OK;
  612. } else {
  613. RPF("SetProperty: Value must be 0 .. 10000");
  614. hres = E_INVALIDARG;
  615. }
  616. break;
  617. case (DWORD)(UINT_PTR)DIPROP_CALIBRATIONMODE:
  618. if ((pdipdw->dwData & ~DIPROPCALIBRATIONMODE_VALID) == 0) {
  619. this->fRaw = pdipdw->dwData;
  620. hres = S_OK;
  621. } else {
  622. RPF("ERROR SetProperty: invalid calibration flags");
  623. hres = E_INVALIDARG;
  624. }
  625. break;
  626. case (DWORD)(UINT_PTR)DIPROP_CALIBRATION:
  627. case (DWORD)(UINT_PTR)DIPROP_SPECIFICCALIBRATION:
  628. hres = CCal_SetCalibration(this, ppropi, pdiph, hkType);
  629. break;
  630. case (DWORD)(UINT_PTR)DIPROP_CPOINTS:
  631. this->dwCPointsNum = pdipcps->dwCPointsNum;
  632. memcpy( &this->cp, &pdipcps->cp, sizeof(this->cp) );
  633. hres = S_OK;
  634. break;
  635. default:
  636. hres = E_NOTIMPL;
  637. break;
  638. }
  639. ExitOleProc();
  640. return hres;
  641. }