▶ 문제 코드
[환경]
OS : Windos 2000, 98(VMWare)
Language : Visual Basic 6.0 SP6
참고 : 순수 Win32 API 코드이므로 다른 언어에서도 같은 증상이 있을 것이라고 생각됨
[소스 코드]
'//-----------------------------------------------------------------
'// Win32 API 선언
'//-----------------------------------------------------------------
Private Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileA" _
(ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
'// WinNT or above only
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Boolean
End Type
'// COM Port상태 enum
Public Enum ComPortStateConsts
ctComAvailable = 0 '// Port is available
ctComNotAvailable = 1 '// Port is not present
ctComInuse = 2 '// Port is in use
ctComUnknown = 3 '// Unknown error occurred
End Enum
'/*---------------------------------------------------------
' * 함수명 : CheckPort()
' * 인수 설명
' PortNum ; 점검할 포트 번호
' * 반환값
' ComPortStateConsts 참고
' * 함수 설명
' 주어진 번호의 COM 포트를 점검하고 상태를 반환
' *--------------------------------------------------------*/
Public Function CheckPort(ByVal PortNum As Long) As ComPortStateConsts
On Error GoTo ProcError
Dim DevName As String
DevName = "\\.\COM" & PortNum
'// COM 장치명을 통하여 파일 입출력 핸들 얻고 결과에 따라 처리
Dim hFile As Long
Dim sec as SECURITY_ATTRIBUTES
hFile = CreateFile(DevName, _
GENERIC_READ Or GENERIC_WRITE, _
0&, _
sec, _
OPEN_EXISTING, _
0&, 0&)
'// 핸들이 유효하지 않을 경우 GetLastError()로 이유 분석, 유효할 경우 사용 가능
If (hFile = INVALID_HANDLE_VALUE) Then
Select Case GetLastError()
Case ERROR_FILE_NOT_FOUND
CheckPort = ctComNotAvailable
Case ERROR_ACCESS_DENIED
CheckPort = ctComInuse
Case Else
CheckPort = ctComUnknown
End Select
Else
CheckPort = ctComAvailable
End If
Call CloseHandle(hFile)
Exit Function
ProcError:
CheckPort = ctComUnknown
End Function
▶ 문제점
- 같은 머신 상에서 시리얼 포트 체크를 위해 CreateFile()을 호출할 때 Windows 2000, XP일 경우 정상적인 핸들을 반환하였으나 Windows 98에서는 완전히 같은 코드로도INVALID_HANDLE_VALUE를 반환함.
▶ 해결 과정
시도1 : 일단 API 레퍼런스를 참고하여 의심되는 파라미터를 변경해 봄.
[MSDN] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/createfile.asp
[함수 원형] HANDLE CreateFile(
LPCTSTR lpFileName, // pointer to name of the file DWORD dwDesiredAccess, // access (read-write) mode DWORDdwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDisposition, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to file with attributes to copy );
여전히 같은 증상, 시리얼 통신과 관련된 어떤 파라미터나 플래그 값으로도 같은 증상
시도2 : 구글링으로도 정확히 같은 증상은 없고 비슷하거나 반대의 케이스는 몇몇 보임
시도3 : 고심중 언뜻 스치고 지나간 생각, Win98은 SECURITY_ATTRIBUTES를 사용할 수 없다!! 따라서 CreateFile()에서 lpSecurityAttributes에 NULL을 주면 해결되지 않을까...
그런데 VB의 표준 CreateFile() 선언에서는 lpSecurityAttributes가 Byref로 잡혀있어서 NULL을 줄 수 없었던 것.
CreateFile() 선언은 그대로 두고 NULL 파라미터를 줄 수 있는 CreateFileNull()이란 이름으로 따로 선언하고 lpSecurityAttributes에 VB에서의 NULL인 0&를 주었더니 아무 문제 없이 해결됨.
Private Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileA" _
(ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _ ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
- 위에서 굵게 표시한 부분을 다음과 같이 수정 ▶ Byval lpSecurityAttributes As Long
- CreateFile을 호출 할 때 SECURITY_ATTRIBUTES 구조체를 인수로 줬던 부분을 0&로 수정
▶ 정리 - 이 외에도 Win98에서 security_attributes를 요구하는 API를 쓸때는 각별한 주의가 필요함.
- 수정된 완전한 소스 코드
'//-----------------------------------------------------------------
'// Win32 API 선언
'//-----------------------------------------------------------------
Private Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileA" _
(ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
'// lpSecurityAttributes에 NULL을 주기 위한 선언
Private Declare Function CreateFileNull Lib "kernel32.dll" Alias "CreateFileA" _
(ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
'// WinNT or above only
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Boolean
End Type
'// COM Port상태 enum
Public Enum ComPortStateConsts
ctComAvailable = 0 '// Port is available
ctComNotAvailable = 1 '// Port is not present
ctComInuse = 2 '// Port is in use
ctComUnknown = 3 '// Unknown error occurred
End Enum
'/*---------------------------------------------------------
' * 함수명 : CheckPort()
' * 인수 설명
' PortNum ; 점검할 포트 번호
' * 반환값
' ComPortStateConsts 참고
' * 함수 설명
' 주어진 번호의 COM 포트를 점검하고 상태를 반환
' *--------------------------------------------------------*/
Public Function CheckPort(ByVal PortNum As Long) As ComPortStateConsts
On Error GoTo ProcError
Dim DevName As String
DevName = "\\.\COM" & PortNum
'// COM 장치명을 통하여 파일 입출력 핸들 얻고 결과에 따라 처리
Dim hFile As Long
'// 98이든 NT계열이든 시리얼 통신에는 lpSecurityAttributes가 필요치 않음
hFile = CreateFile(DevName, _
GENERIC_READ Or GENERIC_WRITE, _
0&, _
0&, _
OPEN_EXISTING, _
0&, 0&)
'// 핸들이 유효하지 않을 경우 GetLastError()로 이유 분석, 유효할 경우 사용 가능
If (hFile = INVALID_HANDLE_VALUE) Then
Select Case GetLastError()
Case ERROR_FILE_NOT_FOUND
CheckPort = ctComNotAvailable
Case ERROR_ACCESS_DENIED
CheckPort = ctComInuse
Case Else
CheckPort = ctComUnknown
End Select
Else
CheckPort = ctComAvailable
End If
Call CloseHandle(hFile)
Exit Function
ProcError:
CheckPort = ctComUnknown
End Function
Le laboratoire Servier a reconnu que "le Mediator a pu présenter un vrai risque pour certains patients", http://www.timberlandbaratas.com barato timberland, dans une interview au Journal du dimanche (JDD) de sa directrice générale Lucy Vincent, http://www.timberlandbaratas.com botas timberland, qui a affirmé que "la mort de trois personnes, c'est déjà trop", http://www.timberlandbaratas.com outlet timberland. Actu en continu Agriculture bio : la baisse des aides mal per?ue Santé Le labo Servier reconna, http://www.timberlandbaratas.com Hombre Timberland?t, http://www.timberlandbaratas.com Timberland Online, en partie, http://www.timberlandbaratas.com Mujer Timberland, la dangerosité du MediatorRelated articles:
http://pocketknife.tistory.com/?page=46 Un couple d'ex-employés d'un ancien orphelinat de l'
http://firstname.tistory.com/category/鞐办槇鞚�page=51 Le disc-jockey passé à tabac par plusieurs hommes dans la nuit de la Saint-Sylvestre pour avoir re
Submit comment.
그냥 ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES 이부분을
ByRef lpSecurityAttributes As Any 로 고치시고
코딩시에 ByVal 0& 로 설정하시는것도 가독성 및 후방 호환성를 높이는 방법이라고 생각되네요.
결론은 선언 문제지만.
블로그에 가봤는데 정말 인상적이네요.
제가 VB를 한참 배울 때 알았더라면...하는 생각이 들어요. 감사합니다.
Le laboratoire Servier a reconnu que "le Mediator a pu présenter un vrai risque pour certains patients", http://www.timberlandbaratas.com barato timberland, dans une interview au Journal du dimanche (JDD) de sa directrice générale Lucy Vincent, http://www.timberlandbaratas.com botas timberland, qui a affirmé que "la mort de trois personnes, c'est déjà trop", http://www.timberlandbaratas.com outlet timberland. Actu en continu Agriculture bio : la baisse des aides mal per?ue Santé Le labo Servier reconna, http://www.timberlandbaratas.com Hombre Timberland?t, http://www.timberlandbaratas.com Timberland Online, en partie, http://www.timberlandbaratas.com Mujer Timberland, la dangerosité du MediatorRelated articles:
http://pocketknife.tistory.com/?page=46 Un couple d'ex-employés d'un ancien orphelinat de l'
http://firstname.tistory.com/category/鞐办槇鞚�page=51 Le disc-jockey passé à tabac par plusieurs hommes dans la nuit de la Saint-Sylvestre pour avoir re