'Classes/ActiveBasic/Windows/Windows.ab

Namespace ActiveBasic
Namespace Windows

Function GetPathFromIDList(pidl As LPITEMIDLIST) As String
	Dim buf[ELM(MAX_PATH)] As TCHAR
	If SHGetPathFromIDList(pidl, buf) Then
		Return New String(buf)
	Else
		Return ""
	End If
End Function

Function GetFolderPath(hwnd As HWND, folder As Long) As String
	Dim pidl As LPITEMIDLIST
	Dim hr = SHGetSpecialFolderLocation(hwnd, folder, pidl)
	If SUCCEEDED(hr) Then
		GetFolderPath = GetPathFromIDList(pidl)
		CoTaskMemFree(pidl)
	Else
		GetFolderPath = ""
	End If
End Function

Function GetFolderPath(folder As Long) As String
	Return GetFolderPath(0, folder)
End Function
/*
Function MessageBox(hw As HWND, s As PCSTR, t As PCSTR, b As DWord) As DWord
	Return MessageBoxA(hw, s, t, b)
End Function

Function MessageBox(hw As HWND, s As PCWSTR, t As PCWSTR, b As DWord) As DWord
	Return MessageBoxW(hw, s, t, b)
End Function
*/

Namespace Detail
Function _System_MessageBox(hw As HWND, s As PCSTR, t As PCSTR, b As DWord) As DWord
	Return MessageBoxA(hw, s, t, b)
End Function

Function _System_MessageBox(hw As HWND, s As PCWSTR, t As PCWSTR, b As DWord) As DWord
	Return MessageBoxW(hw, s, t, b)
End Function
End Namespace

Function HResultToString(hr As HRESULT) As String
	Dim pszMsg As PCSTR
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER Or FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS,
		0, hr, LANG_USER_DEFAULT, VarPtr(pszMsg) As PTSTR, 0, 0)
	If pszMsg <> 0 Then
		HResultToString = New String(pszMsg)
		LocalFree(pszMsg)
	End If
End Function

/*!
@brief	Windows/COMのエラーを伝える例外クラス
@date	2008/07/13
@auther	Egtra
*/
Class WindowsException
	Inherits System.Exception
Public
	/*!
	@biref	コンストラクタ
	*/
	Sub WindowsException()
		Exception()
		HResult = E_FAIL
	End Sub
	/*!
	@biref	コンストラクタ
	@param[in] hr	エラー値
	*/
	Sub WindowsException(hr As HRESULT)
		Exception(HResultToString(hr))
		HResult = hr
	End Sub
	/*!
	@biref	コンストラクタ
	@param[in] message	エラーメッセージ
	*/
	Sub WindowsException(message As String)
		Exception(message)
		HResult = E_FAIL
	End Sub
	/*!
	@biref	コンストラクタ
	@param[in] hr	エラー値
	@param[in] message	エラーメッセージ
	*/
	Sub WindowsException(hr As HRESULT, message As String)
		Exception(message)
		HResult = hr
	End Sub
	/*!
	@biref	コンストラクタ
	@param[in] message	エラーメッセージ
	@param[in] innerException	内部例外
	*/
	Sub WindowsException(message As String, innerException As Exception)
		Exception(message, innerException)
		HResult = E_FAIL
	End Sub
Private
End Class

/*!
@brief	Windowsのエラー値を基に例外を投げる
@param[in] dwErrorCode	Win32エラーコード
@param[in] msg	補足説明
@throw WindowsException	常に投げられる。
@date 2008/07/13
@auther Egtra
*/
Sub ThrowWithErrorCode(dwErrorCode As DWord, msg = Nothing As String)
	Throw New WindowsException(HRESULT_FROM_WIN32(dwErrorCode), msg)
End Sub
/*!
@brief WindowsExceptionを投げるラッパ。直前に呼び出したAPI関数などが失敗したときに用いる。
@param[in] msg 補足説明
@throw WindowsException 常に投げられる。
@date 2008/08/20
@auther Egtra
WindowsExceptionを構築する際、GetLastError()の値を渡す。
この関数では、直前のAPI関数が成功したかどうかを調べられないことに注意。
*/
Sub ThrowWithLastError(msg = Nothing As String)
	ThrowWithErrorCode(GetLastError(), msg)
End Sub
/*!
@brief （主にuser32の全部、gdi32の一部が対象）WindowsExceptionを投げるラッパ。直前に呼び出したAPI関数などが失敗したときに用いる。
@param[in] msg 補足説明
@throw WindowsException 常に投げられる。
@date 2008/08/26
@auther Egtra
user32やgdi32の一部など、9xではGetLastErrorでエラーメッセージが取得できないものがある。
そのため、9xでは一律にmsgのみでWindowsExceptionを構築して投げるようにしている。

ところで、CEではNT同様GetLastErrorが使用できるため、
CEへの移植を仮定すると、関数名にNTと付けるのがそぐわないと感じる。代案募集中。
*/
Sub ThrowWithLastErrorNT(msg As String)
	If Not Version.Is9x() Then
		ThrowWithErrorCode(GetLastError(), msg)
	Else
		Throw New WindowsException(msg)
	End If
End Sub
/*!
@brief	HRESULT値を基に例外を投げる。
@param[in] hr HRESULT値
@param[in] msg 補足説明
@throw WindowsException	FAILED(hr)が真の場合
@date 2008/07/13
@auther Egtra
hrが成功値 (FAILED(hr) = False) の場合、この関数は何も行わない。
*/
Sub ThrowIfFailed(hr As HRESULT, msg = Nothing As String)
	If FAILED(hr) Then
		Throw New WindowsException(hr, msg)
	End If
End Sub

End Namespace 'Widnows
End Namespace 'ActiveBasic
