|
질문이 님이 쓰신 글 :
: interest 님이 쓰신 글 :
: : 윈도우 메세지를 이용하세요.
: : 몇년전에 비슷한 작업.. USB에 연결된 핸드폰 케이블을 핸드폰에 끼우면 그것 감지해서 어떤넘의 포트인지 찻고, 캐이블이 빠지면 감지해서 포트 클로즈 해주는 프로그램 작성한적이 있습니다. 별문제 없이 동작했구요. 삼성, LG, 스카이, 큐리텔등 우리나라에서 판매되는 대부분의 핸드폰이 꼽힐 경우를 고려해야 했는데 각각의 회사, 제품 모델, 통신사마다 디바이스드라이브가 다른 경우가 많았기 때문에 사용하는 포트가 많아서 어떤넘이 꼽혔는지, 또는 캐이블이 빠졌는지를 확인해야 하는 절차가 필요해서 만든것입니다.
: :
: : 간단하게 동작을 설명 드리면 USB 핸드폰 케이블이 꼽혔을때나 빠졌을때 WM_DEVICECHANGE 메세지가 발생합니다. 물론 USB 카드리더기등 USB나 기타등등 관련장비에 변화가 생기면 WM_DEVICECHANGE 가 발생됩니다. 그것이 어떤 경우인지는 Message.WParam의 값을 보면 됩니다.
: : 당시에 이미 연결된 카드리더기에 메모리카드가 꼽힐 경우 어떠한 윈도우메세지도 발생하지 않아서 무지 고생했던게 아직도 눈에 선 하군요.
: :
: : 해당 메세지핸들러 올려드리겟습니다. 뭐 소스 보시면 어떻게 동작을 하는지 이해 되실겁니다. 소스는 다른 디바이스가 꼽히는 경우가 없으므로(특수장비라서 USB 핸드폰 캐이블만 꼽힐 수 있게 되었습니다.) 다른것은 체크하지 않고 간단하게 확인합니다.
: :
: : 포트 라이브러리가 틀리므로 전체 소스는 의미 없을듯합니다.
: : 주석은 제가 방금 달은것입니다.
: : DBT_DEVICEARRIVAL, DBT_DEVICEREMOVECOMPLETE 를 쓰기 위해선 #include <dbt.h> 해줘야 합니다.
: :
: : void __fastcall TComPortForm::OnMessages(Messages::TMessage &Message)
: : {
: : switch(Message.Msg)
: : {
: : case WM_DEVICECHANGE:
: : switch(Message.WParam)
: : {
: : case DBT_DEVICEARRIVAL :
: : CheckPort(); // 핸드폰 케이블이 꼽혔다. 꼽힌 핸드폰 USB Serial port 번호 찻아서 해당포트 open하기.
: : break;
: : case DBT_DEVICEREMOVECOMPLETE :
: : ComPort1->Close(); // // 핸드폰 케이블이 빠졌다. 포트 뒷 정리.
: : break;
: : }
: : Message.Result = true;
: : break;
: : default:
: : TForm::WndProc(Message);
: : }
: : }
: :
: : 즐겁게~ 님이 쓰신 글 :
: : : CPort264 라이브러리를 사용해서 프로그램을 만들었습니다.
: : : USB로 연결해서 사용(Serial to USB)하고 있구요.
: : :
: : : 그런데, 통신 중 USB를 뽑으면,
: : : ComPort1->Connected도 true이고, OnError등 이벤트도 발생되지 않습니다..
: : : 그러다보니 ComPort1->Write(&txdata,1);를 하게되고, 이 때 Write File Error가 발생합니다.
: : : 물론 프로그램에서 이 에러가 발생되는것을 확인하진 못했고,
: : : 디버깅에서 확인한 것이구요.
: : : ComPort1->Write(&txdata,1); 에서 데이터 송신하지 못하면
: : : 타임아웃되어 리턴되는 값이 '0'일 줄알았는데.. '0'으로 리턴되는 것도 아닌것 같습니다.
: : :
: : : 통신 중 USB를 뽑으면, 그 상황을 알 수 있는 방법이나,
: : : Write File Error를 알 수 있는 방법이나.
: : : 그 상황을 알 수 없다면 다른 처리 방법이 있는지 알려주세요~~~
: : :
: : : 고수님들 도와주세요.... 제발~
:
: interest님이 쓴 글중에
:
: "당시에 이미 연결된 카드리더기에 메모리카드가 꼽힐 경우 어떠한 윈도우메세지도 발생하지 않아서 무지 고생했던게 아직도 눈에 선 하군요. "
:
: 라는 내용이 있는데 다른 글 검색해보다가도 비슷한 내용을 본적이 있습니다.
:
: 혹시 USB리더기만 감지할 수 있는 문제를 해결할 방법이 있는지 궁금합니다.
예 해결은 했습니다. 저도 이문제로 이 게시판에 질문글 올렸었는데요. 답변은 'DDK 프로그래밍을해서 디바이스 드라이브를 만들어서 올려야 한다'. 였습니다. 아마도 '이름'찻기로 '아리랑'을 찻으면 그 질문보이실겁니다.
난감했죠. Application programmer가 System programmer 로 대변신(?)을 해야 하는 기가막힌 상황이였죠. 더불어 더더욱 짜증나는건 윈도우는 메모리카드가 꼽히거나 빠지면 알아서 드라이브 폴더 띄우거나 지워버리죠.
결국은 다른 방법으로 해결하긴 했는데.. 레지스트리를 보아도 변하는게 없고해서 타이머를 이용해서 카드리더기가 연결된 볼륨레이블(L,M,N,O)을 순차적으로 읽어서 drive info를 살펴보는 방법으로 갔습니다. GetVolumeInformation 함수를 써서 File System을 살펴본것이였죠. NULL이 아니면 카드리더기에 카드가 꼽힌 경우고 읽다가 에러나면 뽑힌경우로 처리하는 방법을 썻습니다. 좀 무식한 방법이지만 의외로 효과 만점이였습니다. 물론 경우의 수가(Ex 이미 하나 꼽혔는데 다른 슬롯에 카드가 또 꼽히는경우, 이미 감지한 드라이브를 다시 감지하는 경우등)많아 프로그램이 좀 복잡해졌습니다.
꽁수죠. 정도는 아닙니다. 답변되었기를 바랍니다.
참고로 관련 소스 프로토타입 함수 올려드리겟습니다.
void __fastcall TForm1::CheckDrive(TObject *Sender)
{
//TODO: Add your source code here
char FileSystem[30];
FileSystem[0] = NULL;
GetVolumeInformation((AnsiString('J')+":\\").c_str(), NULL, 0, NULL,
NULL, NULL, FileSystem, 30);
if(FileSystem[0] == NULL)
{
Label1->Caption = "이동식 드라이브 FileSystem is none";
UseDrive = false;
} else {
Label1->Caption = AnsiString("이동식 드라이브 FileSystem is ") + FileSystem;
UseDrive = true;
}
}
이 함수를 IDLE시간에 timer로 적절히 호출해야 겟지요. 보통 카드리더기는 4개의 드라이브를 가지고 있는데 AnsiString('J')+":\\").c_str() 이부분 적절히 손을 봐야 할것입니다.
|