Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 400

/ вопрос решён /

Добрый день! Я пытаюсь подключить счетчик гейгера к компу. Он дает импульсы довольно короткие, которые я направляю на game port.
Далее процедурка
m:=joySetCapture (form1.Handle,0 , 1, True);
m:=joyGetPos(0,@myjoy);
опрашивает порт. а таймет(T=1ms) считывает значения параметров:
if (myjoy.wbuttons and joy_button1)>1 then...
Данная конструкция работает очень медленно, пропускает импульсы. Возможно ли оптимизировать код? И если есть статьи по работе с паралельным портом скиньте ссылку, буду очень благодарен! (Горю, дипломная...)

Scayn Вопрос решён, но можно продолжить его обсуждение в мини-форуме

Вопрос задал: Scayn (статус: Посетитель)
Вопрос отправлен: 12 марта 2007, 13:39
Состояние вопроса: решён, ответов: 2.

Ответ #1. Отвечает эксперт: Вадим К

1) виндовс не система реального времени. Она имеет полное право "задержать" тик таймера, а то и пропустить (всё это задокументировано).
2) если таймер не мультимедийный, то чаше чем раз в 50 мс он работать не может (опять документировано, даже кажеться 55 мс)

Что же делать?
Попробывать мультимедийний таймер. Он вроде в библиотеке JVCL есть. Но лучше сделать маленькую схему с контролером - надёжность возрастёт в разы, простота работы также

Ответ отправил: Вадим К (статус: Академик)
Время отправки: 12 марта 2007, 13:48
Оценка за ответ: 5

Ответ #2. Отвечает эксперт: Роман

Здравствуйте, Scayn!Здравствуйте, Scayn!Вопервых я бы поставил на выходе счётчика расширитель импульсов Т.к у СГ они очень короткие,во вторых не использовал бы gameport т.к он изначально не расчитан на какую либо точность,а использовал бы com или lpt порт,для работы с lpt используйте LPTWDMIO - драйвер lpt пля делфи под XP,для com используйте компонент TBComPort предназначенный для обмена данными с внешними устройствами
через интерфейс RS-232 в асинхронном или синхронном режиме.
Разработан на основе библиотеки ComPort Library от
Dejan Crnila.
Обеспечивает прием и передачу данных по линиям TXD и RXD,
управление линиями RTS и DTR, мониторинг состояния линий CTS, DSR, RI (Ring Indicator)
и RLSD (Carrier Detect). Управление потоком приема-передачи (Flow Control) не предусмотрено.
Состояние порта отслеживается в отдельном потоке с генерацией соответствующих событий.
Работает с Delphi 2..7 под Windows 9X/ME/NT4/2K/XP. Можно конечно попробовать ещё на выходе СГ поставить защёлку которая будет изменять своё состояние по каждому импульсу СГ т.е 0-импульс-1-импульс-0,то тогда я думаю хватит и точности TTimer,и ненадо там никаких МК тулить. Итак работаем с com или lpt(кстати у меня на celeron 1.2ГГц мфксимальная скорость обращения ч.з LPTWDMIO период min по LPTout1-LPTout0 (меандр) = 10mkS;(F=100KГц);min длительность импульса = 5mkS;) а контроль состояния линий порта - в отдельный поток.

Приложение:
  1. /////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // TBComPort ver.2.13 - 21.07.2006 freeware //
  4. // --------------------------------------------------------------------- //
  5.  
  6.  
  7.  
  8.  
  9. // --------------------------------------------------------------------- //
  10.  
  11. // //
  12. /////////////////////////////////////////////////////////////////////////////
  13.  
  14. unit BCPort;
  15.  
  16. interface
  17.  
  18. uses
  19. Windows, Messages, SysUtils, Classes;
  20.  
  21. {$B-,H+,X+}
  22.  
  23. {$IFDEF VER140}
  24. {$DEFINE D6UP}
  25. {$ENDIF}
  26.  
  27. {$IFDEF VER150}
  28. {$DEFINE D6UP}
  29. {$ENDIF}
  30.  
  31. type
  32. TBaudRate = (br110, br300, br600, br1200, br2400, br4800, br9600, br14400,
  33. br19200, br38400, br56000, br57600, br115200, br128000, br256000);
  34. TByteSize = (bs5, bs6, bs7, bs8);
  35. TComErrors = set of (ceFrame, ceRxParity, ceOverrun, ceBreak, ceIO, ceMode,
  36. ceRxOver, ceTxFull);
  37. TComEvents = set of (evRxChar, evTxEmpty, evRing, evCTS, evDSR, evRLSD,
  38. evError, evRx80Full);
  39. TComSignals = set of (csCTS, csDSR, csRing, csRLSD);
  40. TParity = (paNone, paOdd, paEven, paMark, paSpace);
  41. TStopBits = (sb1, sb1_5, sb2);
  42. TSyncMethod = (smThreadSync, smWindowSync, smNone);
  43. TComSignalEvent = procedure(Sender: TObject; State: Boolean) of object;
  44. TComErrorEvent = procedure(Sender: TObject; Errors: TComErrors) of object;
  45. TRxCharEvent = procedure(Sender: TObject; Count: Integer) of object;
  46.  
  47. TOperationKind = (okWrite, okRead);
  48. TAsync = record
  49. Overlapped: TOverlapped;
  50. Kind: TOperationKind;
  51. Data: Pointer;
  52. Size: Integer;
  53. end;
  54. PAsync = ^TAsync;
  55.  
  56. TBComPort = class;
  57.  
  58. TComThread = class(TThread)
  59. private
  60. FComPort: TBComPort;
  61. FEvents: TComEvents;
  62. FStopEvent: THandle;
  63. protected
  64. procedure DoEvents;
  65. procedure Execute; override;
  66. procedure SendEvents;
  67. procedure Stop;
  68. public
  69. constructor Create(AComPort: TBComPort);
  70. destructor Destroy; override;
  71. end;
  72.  
  73. TComTimeouts = class(TPersistent)
  74. private
  75. FComPort: TBComPort;
  76. FReadInterval: Integer;
  77. FReadTotalM: Integer;
  78. FReadTotalC: Integer;
  79. FWriteTotalM: Integer;
  80. FWriteTotalC: Integer;
  81. procedure SetComPort(const AComPort: TBComPort);
  82. procedure SetReadInterval(const Value: Integer);
  83. procedure SetReadTotalM(const Value: Integer);
  84. procedure SetReadTotalC(const Value: Integer);
  85. procedure SetWriteTotalM(const Value: Integer);
  86. procedure SetWriteTotalC(const Value: Integer);
  87. protected
  88. procedure AssignTo(Dest: TPersistent); override;
  89. public
  90. constructor Create;
  91. property ComPort: TBComPort read FComPort;
  92. published
  93. property ReadInterval: Integer read FReadInterval write SetReadInterval;
  94. property ReadTotalMultiplier: Integer read FReadTotalM write SetReadTotalM;
  95. property ReadTotalConstant: Integer read FReadTotalC write SetReadTotalC;
  96. property WriteTotalMultiplier: Integer
  97. read FWriteTotalM write SetWriteTotalM;
  98. property WriteTotalConstant: Integer
  99. read FWriteTotalC write SetWriteTotalC;
  100. end;
  101.  
  102. TBComPort = class(TComponent)
  103. private
  104. FBaudRate: TBaudRate;
  105. FByteSize: TByteSize;
  106. FConnected: Boolean;
  107. FCTPriority: TThreadPriority;
  108. FEvents: TComEvents;
  109. FEventThread: TComThread;
  110. FHandle: THandle;
  111. FInBufSize: Integer;
  112. FOutBufSize: Integer;
  113. FParity: TParity;
  114. FPort: String;
  115. FStopBits: TStopBits;
  116. FSyncMethod: TSyncMethod;
  117. FTimeouts: TComTimeouts;
  118. FUpdate: Boolean;
  119. FWindow: THandle;
  120. FOnCTSChange: TComSignalEvent;
  121. FOnDSRChange: TComSignalEvent;
  122. FOnError: TComErrorEvent;
  123. FOnRing: TNotifyEvent;
  124. FOnRLSDChange: TComSignalEvent;
  125. FOnRx80Full: TNotifyEvent;
  126. FOnRxChar: TRxCharEvent;
  127. FOnTxEmpty: TNotifyEvent;
  128. procedure CallCTSChange;
  129. procedure CallDSRChange;
  130. procedure CallError;
  131. procedure CallRing;
  132. procedure CallRLSDChange;
  133. procedure CallRx80Full;
  134. procedure CallRxChar;
  135. procedure CallTxEmpty;
  136. procedure SetBaudRate(const Value: TBaudRate);
  137. procedure SetByteSize(const Value: TByteSize);
  138. procedure SetCTPriority(const Value: TThreadPriority);
  139. procedure SetInBufSize(const Value: Integer);
  140. procedure SetOutBufSize(const Value: Integer);
  141. procedure SetParity(const Value: TParity);
  142. procedure SetPort(const Value: String);
  143. procedure SetStopBits(const Value: TStopBits);
  144. procedure SetSyncMethod(const Value: TSyncMethod);
  145. procedure SetTimeouts(const Value: TComTimeouts);
  146. procedure WindowMethod(var Message: TMessage);
  147. protected
  148. procedure ApplyBuffer;
  149. procedure ApplyDCB;
  150. procedure ApplyTimeouts;
  151. procedure CreateHandle;
  152. procedure DestroyHandle;
  153. procedure SetupComPort;
  154. public
  155. constructor Create(AOwner: TComponent); override;
  156. destructor Destroy; override;
  157. procedure AbortAllAsync;
  158. procedure BeginUpdate;
  159. procedure ClearBuffer(Input, Output: Boolean);
  160. procedure Close;
  161. procedure EndUpdate;
  162. function InBufCount: Integer;
  163. function IsAsyncCompleted(AsyncPtr: PAsync): Boolean;
  164. procedure Open;
  165. function OutBufCount: Integer;
  166. function Read(var Buffer; Count: Integer): Integer;
  167. function ReadAsync(var Buffer; Count: Integer; var AsyncPtr: PAsync): Integer;
  168. function ReadStr(var Str: string; Count: Integer): Integer;
  169. function ReadStrAsync(var Str: string; Count: Integer; var AsyncPtr: PAsync): Integer;
  170. procedure SetDTR(State: Boolean);
  171. procedure SetRTS(State: Boolean);
  172. function Signals: TComSignals;
  173. function WaitForAsync(var AsyncPtr: PAsync): Integer;
  174. function Write(const Buffer; Count: Integer): Integer;
  175. function WriteAsync(const Buffer; Count: Integer; var AsyncPtr: PAsync): Integer;
  176. function WriteStr(const Str: string): Integer;
  177. function WriteStrAsync(const Str: string; var AsyncPtr: PAsync): Integer;
  178. property Connected: Boolean read FConnected;
  179. property CTPriority: TThreadPriority read FCTPriority write SetCTPriority;
  180. published
  181. property BaudRate: TBaudRate read FBaudRate write SetBaudRate;
  182. property ByteSize: TByteSize read FByteSize write SetByteSize;
  183. property InBufSize: Integer read FInBufSize write SetInBufSize;
  184. property OutBufSize: Integer read FOutBufSize write SetOutBufSize;
  185. property Parity: TParity read FParity write SetParity;
  186. property Port: String read FPort write SetPort;
  187. property SyncMethod: TSyncMethod read FSyncMethod write SetSyncMethod;
  188. property StopBits: TStopBits read FStopBits write SetStopBits;
  189. property Timeouts: TComTimeouts read FTimeouts write SetTimeouts;
  190. property OnCTSChange: TComSignalEvent read FOnCTSChange write FOnCTSChange;
  191. property OnDSRChange: TComSignalEvent read FOnDSRChange write FOnDSRChange;
  192. property OnError: TComErrorEvent read FOnError write FOnError;
  193. property OnRing: TNotifyEvent read FOnRing write FOnRing;
  194. property OnRLSDChange: TComSignalEvent read FOnRLSDChange write FOnRLSDChange;
  195. property OnRx80Full: TNotifyEvent read FOnRx80Full write FOnRx80Full;
  196. property OnRxChar: TRxCharEvent read FOnRxChar write FOnRxChar;
  197. property OnTxEmpty: TNotifyEvent read FOnTxEmpty write FOnTxEmpty;
  198. end;
  199.  
  200. EComPort = class(Exception);
  201.  
  202. procedure InitAsync(var AsyncPtr: PAsync);
  203. procedure DoneAsync(var AsyncPtr: PAsync);
  204. procedure EnumComPorts(Ports: TStrings);
  205.  
  206. procedure Register;
  207.  
  208. implementation
  209.  
  210. uses
  211. Forms;
  212.  
  213. const
  214. CM_COMPORT = WM_USER + 1;
  215.  
  216. CEMess: array[1..15] of string =
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233. function EventsToInt(const Events: TComEvents): Integer;
  234. begin
  235. Result := 0;
  236. if evRxChar in Events then Result := Result or EV_RXCHAR;
  237. if evTxEmpty in Events then Result := Result or EV_TXEMPTY;
  238. if evRing in Events then Result := Result or EV_RING;
  239. if evCTS in Events then Result := Result or EV_CTS;
  240. if evDSR in Events then Result := Result or EV_DSR;
  241. if evRLSD in Events then Result := Result or EV_RLSD;
  242. if evError in Events then Result := Result or EV_ERR;
  243. if evRx80Full in Events then Result := Result or EV_RX80FULL;
  244. end;
  245.  
  246. function IntToEvents(Mask: Integer): TComEvents;
  247. begin
  248. Result := [];
  249. if (EV_RXCHAR and Mask) <> 0 then Result := Result + [evRxChar];
  250. if (EV_TXEMPTY and Mask) <> 0 then Result := Result + [evTxEmpty];
  251. if (EV_RING and Mask) <> 0 then Result := Result + [evRing];
  252. if (EV_CTS and Mask) <> 0 then Result := Result + [evCTS];
  253. if (EV_DSR and Mask) <> 0 then Result := Result + [evDSR];
  254. if (EV_RLSD and Mask) <> 0 then Result := Result + [evRLSD];
  255. if (EV_ERR and Mask) <> 0 then Result := Result + [evError];
  256. if (EV_RX80FULL and Mask) <> 0 then Result := Result + [evRx80Full];
  257. end;
  258.  
  259. { TComThread }
  260.  
  261. constructor TComThread.Create(AComPort: TBComPort);
  262. begin
  263. inherited Create(True);
  264. FStopEvent := CreateEvent(nil, True, False, nil);
  265. FComPort := AComPort;
  266. Priority := FComPort.CTPriority;
  267. SetCommMask(FComPort.FHandle, EventsToInt(FComPort.FEvents));
  268. Resume;
  269. end;
  270.  
  271. destructor TComThread.Destroy;
  272. begin
  273. Stop;
  274. inherited Destroy;
  275. end;
  276.  
  277. procedure TComThread.Execute;
  278. var
  279. EventHandles: array[0..1] of THandle;
  280. Overlapped: TOverlapped;
  281. Signaled, BytesTrans, Mask: DWORD;
  282. begin
  283. FillChar(Overlapped, SizeOf(Overlapped), 0);
  284. Overlapped.hEvent := CreateEvent(nil, True, True, nil);
  285. EventHandles[0] := FStopEvent;
  286. EventHandles[1] := Overlapped.hEvent;
  287. repeat
  288. WaitCommEvent(FComPort.FHandle, Mask, @Overlapped);
  289. Signaled := WaitForMultipleObjects(2, @EventHandles, False, INFINITE);
  290. if (Signaled = WAIT_OBJECT_0 + 1) and
  291. GetOverlappedResult(FComPort.FHandle, Overlapped, BytesTrans, False) then
  292. begin
  293. FEvents := IntToEvents(Mask);
  294. case FComPort.SyncMethod of
  295. smThreadSync: Synchronize(DoEvents);
  296. smWindowSync: SendEvents;
  297. smNone : DoEvents;
  298. end;
  299. end;
  300. until Signaled <> (WAIT_OBJECT_0 + 1);
  301. SetCommMask(FComPort.FHandle, 0);
  302. PurgeComm(FComPort.FHandle, PURGE_TXCLEAR or PURGE_RXCLEAR);
  303. CloseHandle(Overlapped.hEvent);
  304. CloseHandle(FStopEvent);
  305. end;
  306.  
  307. procedure TComThread.Stop;
  308. begin
  309. SetEvent(FStopEvent);
  310. Sleep(0);
  311. end;
  312.  
  313. procedure TComThread.SendEvents;
  314. begin
  315. if evError in FEvents then
  316. SendMessage(FComPort.FWindow, CM_COMPORT, EV_ERR, 0);
  317. if evRxChar in FEvents then
  318. SendMessage(FComPort.FWindow, CM_COMPORT, EV_RXCHAR, 0);
  319. if evTxEmpty in FEvents then
  320. SendMessage(FComPort.FWindow, CM_COMPORT, EV_TXEMPTY, 0);
  321. if evRing in FEvents then
  322. SendMessage(FComPort.FWindow, CM_COMPORT, EV_RING, 0);
  323. if evCTS in FEvents then
  324. SendMessage(FComPort.FWindow, CM_COMPORT, EV_CTS, 0);
  325. if evDSR in FEvents then
  326. SendMessage(FComPort.FWindow, CM_COMPORT, EV_DSR, 0);
  327. if evRing in FEvents then
  328. SendMessage(FComPort.FWindow, CM_COMPORT, EV_RLSD, 0);
  329. if evRx80Full in FEvents then
  330. SendMessage(FComPort.FWindow, CM_COMPORT, EV_RX80FULL, 0);
  331. end;
  332.  
  333. procedure TComThread.DoEvents;
  334. begin
  335. if evError in FEvents then FComPort.CallError;
  336. if evRxChar in FEvents then FComPort.CallRxChar;
  337. if evTxEmpty in FEvents then FComPort.CallTxEmpty;
  338. if evRing in FEvents then FComPort.CallRing;
  339. if evCTS in FEvents then FComPort.CallCTSChange;
  340. if evDSR in FEvents then FComPort.CallDSRChange;
  341. if evRLSD in FEvents then FComPort.CallRLSDChange;
  342. if evRx80Full in FEvents then FComPort.CallRx80Full;
  343. end;
  344.  
  345. { TComTimeouts }
  346.  
  347. constructor TComTimeouts.Create;
  348. begin
  349. inherited Create;
  350. FReadInterval := -1;
  351. FWriteTotalM := 100;
  352. FWriteTotalC := 1000;
  353. end;
  354.  
  355. procedure TComTimeouts.AssignTo(Dest: TPersistent);
  356. begin
  357. if Dest is TComTimeouts then
  358. begin
  359. with TComTimeouts(Dest) do
  360. begin
  361. FReadInterval := Self.ReadInterval;
  362. FReadTotalM := Self.ReadTotalMultiplier;
  363. FReadTotalC := Self.ReadTotalConstant;
  364. FWriteTotalM := Self.WriteTotalMultiplier;
  365. FWriteTotalC := Self.WriteTotalConstant;
  366. end;
  367. end
  368. else
  369. inherited AssignTo(Dest);
  370. end;
  371.  
  372. procedure TComTimeouts.SetComPort(const AComPort: TBComPort);
  373. begin
  374. FComPort := AComPort;
  375. end;
  376.  
  377. procedure TComTimeouts.SetReadInterval(const Value: Integer);
  378. begin
  379. if Value <> FReadInterval then
  380. begin
  381. FReadInterval := Value;
  382. FComPort.ApplyTimeouts;
  383. end;
  384. end;
  385.  
  386. procedure TComTimeouts.SetReadTotalC(const Value: Integer);
  387. begin
  388. if Value <> FReadTotalC then
  389. begin
  390. FReadTotalC := Value;
  391. FComPort.ApplyTimeouts;
  392. end;
  393. end;
  394.  
  395. procedure TComTimeouts.SetReadTotalM(const Value: Integer);
  396. begin
  397. if Value <> FReadTotalM then
  398. begin
  399. FReadTotalM := Value;
  400. FComPort.ApplyTimeouts;
  401. end;
  402. end;
  403.  
  404. procedure TComTimeouts.SetWriteTotalC(const Value: Integer);
  405. begin
  406. if Value <> FWriteTotalC then
  407. begin
  408. FWriteTotalC := Value;
  409. FComPort.ApplyTimeouts;
  410. end;
  411. end;
  412.  
  413. procedure TComTimeouts.SetWriteTotalM(const Value: Integer);
  414. begin
  415. if Value <> FWriteTotalM then
  416. begin
  417. FWriteTotalM := Value;
  418. FComPort.ApplyTimeouts;
  419. end;
  420. end;
  421.  
  422. { TBComPort }
  423.  
  424. constructor TBComPort.Create(AOwner: TComponent);
  425. begin
  426. inherited Create(AOwner);
  427. FComponentStyle := FComponentStyle - [csInheritable];
  428. FBaudRate := br9600;
  429. FByteSize := bs8;
  430. FConnected := False;
  431. FCTPriority := tpNormal;
  432. FEvents := [evRxChar, evTxEmpty, evRing, evCTS, evDSR, evRLSD, evError,
  433. evRx80Full];
  434. FHandle := INVALID_HANDLE_VALUE;
  435. FInBufSize := 2048;
  436. FOutBufSize := 2048;
  437. FParity := paNone;
  438. FPort := 'COM2';
  439. FStopBits := sb1;
  440. FSyncMethod := smThreadSync;
  441. FTimeouts := TComTimeouts.Create;
  442. FTimeouts.SetComPort(Self);
  443. FUpdate := True;
  444. end;
  445.  
  446. destructor TBComPort.Destroy;
  447. begin
  448. Close;
  449. FTimeouts.Free;
  450. inherited Destroy;
  451. end;
  452.  
  453. procedure TBComPort.CreateHandle;
  454. begin
  455. FHandle := CreateFile(PChar('\.' + FPort), GENERIC_READ or GENERIC_WRITE,
  456. 0, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  457. if FHandle = INVALID_HANDLE_VALUE then
  458. begin
  459. if GetLastError = ERROR_FILE_NOT_FOUND then
  460. raise EComPort.Create(CEMess[1])
  461. else if GetLastError = ERROR_ACCESS_DENIED then
  462. raise EComPort.Create(CEMess[2]);
  463. end;
  464. end;
  465.  
  466. procedure TBComPort.DestroyHandle;
  467. begin
  468. if FHandle <> INVALID_HANDLE_VALUE then CloseHandle(FHandle);
  469. end;
  470.  
  471. procedure TBComPort.WindowMethod(var Message: TMessage);
  472. begin
  473. with Message do
  474. if Msg = CM_COMPORT then
  475. try
  476. if InSendMessage then ReplyMessage(0);
  477. if FConnected then
  478. case wParam of
  479. EV_CTS: CallCTSChange;
  480. EV_DSR: CallDSRChange;
  481. EV_RING: CallRing;
  482. EV_RLSD: CallRLSDChange;
  483. EV_RX80FULL: CallRx80Full;
  484. EV_RXCHAR: CallRxChar;
  485. EV_ERR: CallError;
  486. EV_TXEMPTY: CallTxEmpty;
  487. end;
  488. except
  489. Application.HandleException(Self);
  490. end
  491. else
  492. Result := DefWindowProc(FWindow, Msg, wParam, lParam);
  493. end;
  494.  
  495. procedure TBComPort.BeginUpdate;
  496. begin
  497. FUpdate := False;
  498. end;
  499.  
  500. procedure TBComPort.EndUpdate;
  501. begin
  502. if not FUpdate then FUpdate := True;
  503. SetupComPort;
  504. end;
  505.  
  506. procedure TBComPort.Open;
  507. begin
  508. if not FConnected then
  509. begin
  510. CreateHandle;
  511. FConnected := True;
  512. try
  513. SetupComPort;
  514. except
  515. DestroyHandle;
  516. FConnected := False;
  517. raise;
  518. end;
  519. if (FSyncMethod = smWindowSync) then
  520. {$IFDEF D6UP}
  521. {$WARN SYMBOL_DEPRECATED OFF}
  522. {$ENDIF}
  523. FWindow := AllocateHWnd(WindowMethod);
  524. {$IFDEF D6UP}
  525. {$WARN SYMBOL_DEPRECATED ON}
  526. {$ENDIF}
  527. FEventThread := TComThread.Create(Self);
  528. end;
  529. end;
  530.  
  531. procedure TBComPort.Close;
  532. begin
  533. if FConnected then
  534. begin
  535. SetDTR(False);
  536. SetRTS(False);
  537. AbortAllAsync;
  538. FEventThread.Free;
  539. if FSyncMethod = smWindowSync then
  540. {$IFDEF D6UP}
  541. {$WARN SYMBOL_DEPRECATED OFF}
  542. {$ENDIF}
  543. DeallocateHWnd(FWindow);
  544. {$IFDEF D6UP}
  545. {$WARN SYMBOL_DEPRECATED ON}
  546. {$ENDIF}
  547. DestroyHandle;
  548. FConnected := False;
  549. end;
  550. end;
  551.  
  552. procedure TBComPort.ApplyDCB;
  553. const
  554. CBaudRate: array[TBaudRate] of Integer = (CBR_110, CBR_300, CBR_600,
  555. CBR_1200, CBR_2400, CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400,
  556. CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000);
  557. var
  558. DCB: TDCB;
  559. begin
  560. if FConnected and FUpdate then
  561. begin
  562. FillChar(DCB, SizeOf(TDCB), 0);
  563. DCB.DCBlength := SizeOf(TDCB);
  564. DCB.BaudRate := CBaudRate[FBaudRate];
  565. DCB.ByteSize := Ord(TByteSize(FByteSize)) + 5;
  566. DCB.Flags := 1 or ($30 and (DTR_CONTROL_ENABLE shl 4))
  567. or ($3000 and (RTS_CONTROL_ENABLE shl 12));
  568. if FParity <> paNone then
  569. DCB.Flags := DCB.Flags or 2;
  570. DCB.Parity := Ord(TParity(FParity));
  571. DCB.StopBits := Ord(TStopBits(FStopBits));
  572. DCB.XonChar := #17;
  573. DCB.XoffChar := #19;
  574. if not SetCommState(FHandle, DCB) then
  575. raise EComPort.Create(CEMess[8]);
  576. end;
  577. end;
  578.  
  579. procedure TBComPort.ApplyTimeouts;
  580. var
  581. Timeouts: TCommTimeouts;
  582.  
  583. function MValue(const Value: Integer): DWORD;
  584. begin
  585. if Value < 0 then Result := MAXDWORD else Result := Value;
  586. end;
  587.  
  588. begin
  589. if FConnected and FUpdate then
  590. begin
  591. Timeouts.ReadIntervalTimeout := MValue(FTimeouts.ReadInterval);
  592. Timeouts.ReadTotalTimeoutMultiplier := MValue(FTimeouts.ReadTotalMultiplier);
  593. Timeouts.ReadTotalTimeoutConstant := MValue(FTimeouts.ReadTotalConstant);
  594. Timeouts.WriteTotalTimeoutMultiplier := MValue(FTimeouts.WriteTotalMultiplier);
  595. Timeouts.WriteTotalTimeoutConstant := MValue(FTimeouts.WriteTotalConstant);
  596. if not SetCommTimeouts(FHandle, Timeouts) then
  597. raise EComPort.Create(CEMess[9]);
  598. end;
  599. end;
  600.  
  601. procedure TBComPort.ApplyBuffer;
  602. begin
  603. if FConnected and FUpdate then
  604. if not SetupComm(FHandle, FInBufSize, FOutBufSize) then
  605. raise EComPort.Create(CEMess[10]);
  606. end;
  607.  
  608. procedure TBComPort.SetupComPort;
  609. begin
  610. ApplyBuffer;
  611. ApplyDCB;
  612. ApplyTimeouts;
  613. end;
  614.  
  615. function TBComPort.InBufCount: Integer;
  616. var
  617. Errors: DWORD;
  618. ComStat: TComStat;
  619. begin
  620. if not ClearCommError(FHandle, Errors, @ComStat) then
  621. raise EComPort.Create(CEMess[11]);
  622. Result := ComStat.cbInQue;
  623. end;
  624.  
  625. function TBComPort.OutBufCount: Integer;
  626. var
  627. Errors: DWORD;
  628. ComStat: TComStat;
  629. begin
  630. if not ClearCommError(FHandle, Errors, @ComStat) then
  631. raise EComPort.Create(CEMess[11]);
  632. Result := ComStat.cbOutQue;
  633. end;
  634.  
  635. function TBComPort.Signals: TComSignals;
  636. var
  637. Status: DWORD;
  638. begin
  639. if not GetCommModemStatus(FHandle, Status) then
  640. raise EComPort.Create(CEMess[12]);
  641. Result := [];
  642. if (MS_CTS_ON and Status) <> 0 then Result := Result + [csCTS];
  643. if (MS_DSR_ON and Status) <> 0 then Result := Result + [csDSR];
  644. if (MS_RING_ON and Status) <> 0 then Result := Result + [csRing];
  645. if (MS_RLSD_ON and Status) <> 0 then Result := Result + [csRLSD];
  646. end;
  647.  
  648. procedure TBComPort.SetDTR(State: Boolean);
  649. var
  650. Act: DWORD;
  651. begin
  652. if State then Act := Windows.SETDTR else Act := Windows.CLRDTR;
  653. if not EscapeCommFunction(FHandle, Act) then
  654. raise EComPort.Create(CEMess[13]);
  655. end;
  656.  
  657. procedure TBComPort.SetRTS(State: Boolean);
  658. var
  659. Act: DWORD;
  660. begin
  661. if State then Act := Windows.SETRTS else Act := Windows.CLRRTS;
  662. if not EscapeCommFunction(FHandle, Act) then
  663. raise EComPort.Create(CEMess[13]);
  664. end;
  665.  
  666. procedure TBComPort.ClearBuffer(Input, Output: Boolean);
  667. var
  668. Flag: DWORD;
  669. begin
  670. Flag := 0;
  671. if Input then
  672. Flag := PURGE_RXCLEAR;
  673. if Output then
  674. Flag := Flag or PURGE_TXCLEAR;
  675. if not PurgeComm(FHandle, Flag) then
  676. raise EComPort.Create(CEMess[6]);
  677. end;
  678.  
  679. procedure PrepareAsync(AKind: TOperationKind; const Buffer;
  680. Count: Integer; AsyncPtr: PAsync);
  681. begin
  682. with AsyncPtr^ do
  683. begin
  684. Kind := AKind;
  685. if Data <> nil then FreeMem(Data);
  686. GetMem(Data, Count);
  687. Move(Buffer, Data^, Count);
  688. Size := Count;
  689. end;
  690. end;
  691.  
  692. function TBComPort.WriteAsync(const Buffer; Count: Integer; var AsyncPtr: PAsync): Integer;
  693. var
  694. Success: Boolean;
  695. BytesTrans: DWORD;
  696. begin
  697. if AsyncPtr = nil then
  698. raise EComPort.Create(CEMess[5]);
  699. PrepareAsync(okWrite, Buffer, Count, AsyncPtr);
  700. Success := WriteFile(FHandle, Buffer, Count, BytesTrans, @AsyncPtr^.Overlapped)
  701. or (GetLastError = ERROR_IO_PENDING);
  702. if not Success then
  703. raise EComPort.Create(CEMess[3]);
  704. Result := BytesTrans;
  705. end;
  706.  
  707. function TBComPort.Write(const Buffer; Count: Integer): Integer;
  708. var
  709. AsyncPtr: PAsync;
  710. begin
  711. InitAsync(AsyncPtr);
  712. try
  713. WriteAsync(Buffer, Count, AsyncPtr);
  714. Result := WaitForAsync(AsyncPtr);
  715. finally
  716. DoneAsync(AsyncPtr);
  717. end;
  718. end;
  719.  
  720. function TBComPort.WriteStrAsync(const Str: string; var AsyncPtr: PAsync): Integer;
  721. begin
  722. if Length(Str) > 0 then
  723. Result := WriteAsync(Str[1], Length(Str), AsyncPtr)
  724. else
  725. Result := 0;
  726. end;
  727.  
  728. function TBComPort.WriteStr(const Str: string): Integer;
  729. var
  730. AsyncPtr: PAsync;
  731. begin
  732. InitAsync(AsyncPtr);
  733. try
  734. WriteStrAsync(Str, AsyncPtr);
  735. Result := WaitForAsync(AsyncPtr);
  736. finally
  737. DoneAsync(AsyncPtr);
  738. end;
  739. end;
  740.  
  741. function TBComPort.ReadAsync(var Buffer; Count: Integer; var AsyncPtr: PAsync): Integer;
  742. var
  743. Success: Boolean;
  744. BytesTrans: DWORD;
  745. begin
  746. if AsyncPtr = nil then
  747. raise EComPort.Create(CEMess[5]);
  748. AsyncPtr^.Kind := okRead;
  749. Success := ReadFile(FHandle, Buffer, Count, BytesTrans, @AsyncPtr^.Overlapped)
  750. or (GetLastError = ERROR_IO_PENDING);
  751. if not Success then
  752. raise EComPort.Create(CEMess[4]);
  753. Result := BytesTrans;
  754. end;
  755.  
  756. function TBComPort.Read(var Buffer; Count: Integer): Integer;
  757. var
  758. AsyncPtr: PAsync;
  759. begin
  760. InitAsync(AsyncPtr);
  761. try
  762. ReadAsync(Buffer, Count, AsyncPtr);
  763. Result := WaitForAsync(AsyncPtr);
  764. finally
  765. DoneAsync(AsyncPtr);
  766. end;
  767. end;
  768.  
  769. function TBComPort.ReadStrAsync(var Str: string; Count: Integer; var AsyncPtr: PAsync): Integer;
  770. begin
  771. SetLength(Str, Count);
  772. if Count > 0 then
  773. Result := ReadAsync(Str[1], Count, AsyncPtr)
  774. else
  775. Result := 0;
  776. end;
  777.  
  778. function TBComPort.ReadStr(var Str: string; Count: Integer): Integer;
  779. var
  780. AsyncPtr: PAsync;
  781. begin
  782. InitAsync(AsyncPtr);
  783. try
  784. ReadStrAsync(Str, Count, AsyncPtr);
  785. Result := WaitForAsync(AsyncPtr);
  786. SetLength(Str, Result);
  787. finally
  788. DoneAsync(AsyncPtr);
  789. end;
  790. end;
  791.  
  792. function ErrorCode(AsyncPtr: PAsync): Integer;
  793. begin
  794. if AsyncPtr^.Kind = okRead then Result := 4 else Result := 3;
  795. end;
  796.  
  797. function TBComPort.WaitForAsync(var AsyncPtr: PAsync): Integer;
  798. var
  799. BytesTrans, Signaled: DWORD;
  800. Success: Boolean;
  801. begin
  802. if AsyncPtr = nil then
  803. raise EComPort.Create(CEMess[5]);
  804. Signaled := WaitForSingleObject(AsyncPtr^.Overlapped.hEvent, INFINITE);
  805. Success := (Signaled = WAIT_OBJECT_0) and
  806. (GetOverlappedResult(FHandle, AsyncPtr^.Overlapped, BytesTrans, False));
  807. if not Success then
  808. raise EComPort.Create(CEMess[ErrorCode(AsyncPtr)]);
  809. Result := BytesTrans;
  810. end;
  811.  
  812. procedure TBComPort.AbortAllAsync;
  813. begin
  814. if not PurgeComm(FHandle, PURGE_TXABORT or PURGE_RXABORT) then
  815. raise EComPort.Create(CEMess[6]);
  816. end;
  817.  
  818. function TBComPort.IsAsyncCompleted(AsyncPtr: PAsync): Boolean;
  819. var
  820. BytesTrans: DWORD;
  821. begin
  822. if AsyncPtr = nil then
  823. raise EComPort.Create(CEMess[5]);
  824. Result := GetOverlappedResult(FHandle, AsyncPtr^.Overlapped, BytesTrans, False);
  825. if not Result then
  826. if (GetLastError <> ERROR_IO_PENDING) and (GetLastError <> ERROR_IO_INCOMPLETE) then
  827. raise EComPort.Create(CEMess[7]);
  828. end;
  829.  
  830. procedure TBComPort.CallCTSChange;
  831. begin
  832. if Assigned(FOnCTSChange) then FOnCTSChange(Self, csCTS in Signals);
  833. end;
  834.  
  835. procedure TBComPort.CallDSRChange;
  836. begin
  837. if Assigned(FOnDSRChange) then FOnDSRChange(Self, csDSR in Signals);
  838. end;
  839.  
  840. procedure TBComPort.CallRLSDChange;
  841. begin
  842. if Assigned(FOnRLSDChange) then FOnRLSDChange(Self, csRLSD in Signals);
  843. end;
  844.  
  845. procedure TBComPort.CallError;
  846. var
  847. Errs: TComErrors;
  848. Errors: DWORD;
  849. ComStat: TComStat;
  850. begin
  851. if not ClearCommError(FHandle, Errors, @ComStat) then
  852. raise EComPort.Create(CEMess[11]);
  853. Errs := [];
  854. if (CE_FRAME and Errors) <> 0 then Errs := Errs + [ceFrame];
  855. if ((CE_RXPARITY and Errors) <> 0) and (FParity <> paNone) then
  856. Errs := Errs + [ceRxParity];
  857. if (CE_OVERRUN and Errors) <> 0 then Errs := Errs + [ceOverrun];
  858. if (CE_RXOVER and Errors) <> 0 then Errs := Errs + [ceRxOver];
  859. if (CE_TXFULL and Errors) <> 0 then Errs := Errs + [ceTxFull];
  860. if (CE_BREAK and Errors) <> 0 then Errs := Errs + [ceBreak];
  861. if (CE_IOE and Errors) <> 0 then Errs := Errs + [ceIO];
  862. if (CE_MODE and Errors) <> 0 then Errs := Errs + [ceMode];
  863. if (Errs <> []) and Assigned(FOnError) then FOnError(Self, Errs);
  864. end;
  865.  
  866. procedure TBComPort.CallRing;
  867. begin
  868. if Assigned(FOnRing) then FOnRing(Self);
  869. end;
  870.  
  871. procedure TBComPort.CallRx80Full;
  872. begin
  873. if Assigned(FOnRx80Full) then FOnRx80Full(Self);
  874. end;
  875.  
  876. procedure TBComPort.CallRxChar;
  877. var
  878. Count: Integer;
  879. begin
  880. Count := InBufCount;
  881. if (Count > 0) and Assigned(FOnRxChar) then FOnRxChar(Self, Count);
  882. end;
  883.  
  884. procedure TBComPort.CallTxEmpty;
  885. begin
  886. if Assigned(FOnTxEmpty) then FOnTxEmpty(Self);
  887. end;
  888.  
  889. procedure TBComPort.SetBaudRate(const Value: TBaudRate);
  890. begin
  891. if Value <> FBaudRate then
  892. begin
  893. FBaudRate := Value;
  894. ApplyDCB;
  895. end;
  896. end;
  897.  
  898. procedure TBComPort.SetByteSize(const Value: TByteSize);
  899. begin
  900. if Value <> FByteSize then
  901. begin
  902. FByteSize := Value;
  903. ApplyDCB;
  904. end;
  905. end;
  906.  
  907. procedure TBComPort.SetParity(const Value: TParity);
  908. begin
  909. if Value <> FParity then
  910. begin
  911. FParity := Value;
  912. ApplyDCB;
  913. end;
  914. end;
  915.  
  916. procedure TBComPort.SetPort(const Value: String);
  917. begin
  918. if FConnected then
  919. raise EComPort.Create(CEMess[14])
  920. else
  921. if Value <> FPort then FPort := Value;
  922. end;
  923.  
  924. procedure TBComPort.SetStopBits(const Value: TStopBits);
  925. begin
  926. if Value <> FStopBits then
  927. begin
  928. FStopBits := Value;
  929. ApplyDCB;
  930. end;
  931. end;
  932.  
  933. procedure TBComPort.SetSyncMethod(const Value: TSyncMethod);
  934. begin
  935. if Value <> FSyncMethod then
  936. begin
  937. if FConnected then
  938. raise EComPort.Create(CEMess[14])
  939. else
  940. FSyncMethod := Value;
  941. end;
  942. end;
  943.  
  944. procedure TBComPort.SetCTPriority(const Value: TThreadPriority);
  945. begin
  946. if Value <> FCTPriority then
  947. begin
  948. if FConnected then
  949. raise EComPort.Create(CEMess[14])
  950. else
  951. FCTPriority := Value;
  952. end;
  953. end;
  954.  
  955. procedure TBComPort.SetInBufSize(const Value: Integer);
  956. begin
  957. if Value <> FInBufSize then
  958. begin
  959. FInBufSize := Value;
  960. if (FInBufSize mod 2) = 1 then Dec(FInBufSize);
  961. ApplyBuffer;
  962. end;
  963. end;
  964.  
  965. procedure TBComPort.SetOutBufSize(const Value: Integer);
  966. begin
  967. if Value <> FOutBufSize then
  968. begin
  969. FOutBufSize := Value;
  970. if (FOutBufSize mod 2) = 1 then Dec(FOutBufSize);
  971. ApplyBuffer;
  972. end;
  973. end;
  974.  
  975. procedure TBComPort.SetTimeouts(const Value: TComTimeouts);
  976. begin
  977. FTimeouts.Assign(Value);
  978. ApplyTimeouts;
  979. end;
  980.  
  981. procedure InitAsync(var AsyncPtr: PAsync);
  982. begin
  983. New(AsyncPtr);
  984. with AsyncPtr^ do
  985. begin
  986. FillChar(Overlapped, SizeOf(TOverlapped), 0);
  987. Overlapped.hEvent := CreateEvent(nil, True, True, nil);
  988. Data := nil;
  989. Size := 0;
  990. end;
  991. end;
  992.  
  993. procedure DoneAsync(var AsyncPtr: PAsync);
  994. begin
  995. with AsyncPtr^ do
  996. begin
  997. CloseHandle(Overlapped.hEvent);
  998. if Data <> nil then FreeMem(Data);
  999. end;
  1000. Dispose(AsyncPtr);
  1001. AsyncPtr := nil;
  1002. end;
  1003.  
  1004. procedure EnumComPorts(Ports: TStrings);
  1005. var
  1006. KeyHandle: HKEY;
  1007. ErrCode, Index: Integer;
  1008. ValueName, Data: String;
  1009. ValueLen, DataLen, ValueType: DWORD;
  1010. TmpPorts: TStringList;
  1011. begin
  1012. ErrCode := RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'HARDWAREDEVICEMAPSERIALCOMM',
  1013. 0, KEY_READ, KeyHandle);
  1014. if ErrCode <> ERROR_SUCCESS then
  1015. raise EComPort.Create(CEMess[15]);
  1016. TmpPorts := TStringList.Create;
  1017. try
  1018. Index := 0;
  1019. repeat
  1020. ValueLen := 256;
  1021. DataLen := 256;
  1022. SetLength(ValueName, ValueLen);
  1023. SetLength(Data, DataLen);
  1024. ErrCode := RegEnumValue(KeyHandle, Index, PChar(ValueName),
  1025. {$IFDEF VER120}
  1026. Cardinal(ValueLen),
  1027. {$ELSE}
  1028. ValueLen,
  1029. {$ENDIF}
  1030. nil, @ValueType, PByte(PChar(Data)), @DataLen);
  1031. if ErrCode = ERROR_SUCCESS then
  1032. begin
  1033. SetLength(Data, DataLen - 1);
  1034. TmpPorts.Add(Data);
  1035. Inc(Index);
  1036. end
  1037. else
  1038. if ErrCode <> ERROR_NO_MORE_ITEMS then
  1039. raise EComPort.Create(CEMess[15]);
  1040. until (ErrCode <> ERROR_SUCCESS) ;
  1041. TmpPorts.Sort;
  1042. Ports.Assign(TmpPorts);
  1043. finally
  1044. RegCloseKey(KeyHandle);
  1045. TmpPorts.Free;
  1046. end;
  1047. end;
  1048.  
  1049. procedure Register;
  1050. begin
  1051. RegisterComponents('Samples', [TBComPort]);
  1052. end;
  1053.  
  1054. end.
  1055.  


Ответ отправил: Роман (статус: 5-ый класс)
Время отправки: 12 марта 2007, 15:09
Оценка за ответ: 5


Мини-форум вопроса

Всего сообщений: 6; последнее сообщение — 13 марта 2007, 12:45; участников в обсуждении: 3.
Scayn

Scayn (статус: Посетитель), 12 марта 2007, 14:01 [#1]:

Спосибо! На контроллер у меня времени не хватит. В паскале я эту проблему решал просто зациклив прямое обращение к lpt порту. под дос и win98 шло прекрасно, но вот с winNT проблемы. Пробовал на прямую обращаться к орту, винда ругается. Опятьже на разработку драйвера времени нет, вот и решил использовать стандартный драйвер джойстика. Может вопрос покажется глупым, но где библиотека JVCL? В политре я ее не обнаружил :(
Вадим К

Вадим К (статус: Академик), 12 марта 2007, 14:10 [#2]:

скачать надо. гугл сразу находит http://homepages.borland.com/jedi/jvcl/
Галочка "подтверждения прочтения" - вселенское зло.
Роман

Роман (статус: 5-ый класс), 12 марта 2007, 16:07 [#3]:

А по поводу проверки joy по таймеру - зачем???
unit JoyUtil;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,MMSystem, ExtCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Panel1: TPanel;
Panel2: TPanel;
Panel3: TPanel;
Panel4: TPanel;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
procedure JMsg(var Msg: TMsg; var Handled: Boolean);
public
{ Public declarations }
end;
var
Form1: TForm1;

implementation
{$R *.dfm}
procedure TForm1.JMsg(var Msg: TMsg; var Handled: Boolean);
begin
case Msg.message of
WM_KEYUP: if wParam(Msg.wParam) = VK_ESCAPE then Application.Terminate;
MM_JOY1MOVE:
begin
Memo1.Lines.Add('JoyMove1'+' x '+inttostr(LOWORD(Msg.lParam))+' y '+floattostr(HIWORD(Msg.lParam)));
case wParam(Msg.wParam) of
JOY_BUTTON1 : Panel1.Color:=clLime;
JOY_BUTTON2 : Panel2.Color:=clLime;
end;
end;
MM_JOY1BUTTONUP:
begin
case wParam(Msg.wParam) of
JOY_BUTTON1CHG : Panel1.Color:=clRed;
JOY_BUTTON2CHG : Panel2.Color:=clRed;
end;
end;
MM_JOY2MOVE:
begin
Memo1.Lines.Add('JoyMove2'+' x '+inttostr(LOWORD(Msg.lParam))+' y '+inttostr(HIWORD(Msg.lParam)));
case wParam(Msg.wParam) of
JOY_BUTTON3CHG : Panel3.Color:=clLime;
JOY_BUTTON4CHG : Panel4.Color:=clLime;
end;
end;
MM_JOY2BUTTONUP:
begin
case wParam(Msg.wParam) of
JOY_BUTTON3CHG : Panel3.Color:=clRed;
JOY_BUTTON4CHG : Panel4.Color:=clRed;
end;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage:=JMsg;
joysetcapture(Form1.Handle,JOYSTICKID1,300,false);
joysetThreshold(JOYSTICKID1,100);
joysetcapture(Form1.Handle,JOYSTICKID2,300,false);
joysetThreshold(JOYSTICKID2,100);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
joyReleaseCapture(JOYSTICKID1);
joyReleaseCapture(JOYSTICKID2);
end;
end.
Scayn

Scayn (статус: Посетитель), 13 марта 2007, 11:38 [#4]:

За код большое спасибо, потестирую. Скачал JVCL, но установить не удалось. Выдает ошибки.
Роман

Роман (статус: 5-ый класс), 13 марта 2007, 12:38 [#5]:

TBComPort работает 100% - пользовался(zip есть кажется наdelphikingdom.com,там и описание в zipe),и работа с game-port_ом тоже без проблем - всё как в win32sdk написано,подключай joystick и смотри:в memo будет аналоговые X-Y,а panel-меняют цвет при нажатии на кнопки.(а JVCL - это дрянь какая-то:)
Вадим К

Вадим К (статус: Академик), 13 марта 2007, 12:45 [#6]:

JVCL тема, если не хочеться писать велосипеды. Смерть изобретателям велосипедов с квадратными колёсами.
Галочка "подтверждения прочтения" - вселенское зло.

31 января 2011, 19:26: Статус вопроса изменён на решённый (изменил модератор Ерёмин А.А.): Автоматическая обработка (2 и более ответов с оценкой 5)

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:54
Выполнено за 0.03 сек.