|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
DfsShPrp.cpp
Abstract:
This module contains the implementation for CDfsShellExtProp This is used to implement the property page for Shell Extension.
Author:
Constancio Fernandes (ferns@qspl.stpp.soft.net) 12-Jan-1998
Environment:
Revision History:
--*/
#include "stdafx.h"
#include "resource.h"
#include "DfsShlEx.h"
#include "DfsPath.h"
#include "DfsShPrp.h"
#include "DfsShell.h"
#include <lmcons.h>
#include <lmerr.h>
#include <lmdfs.h>
#include "dfshelp.h"
CDfsShellExtProp::CDfsShellExtProp():CQWizardPageImpl<CDfsShellExtProp>(false) /*++
Routine Description: Ctor of CDfsShellExtProp. Calls the ctor of it's parent --*/ { m_pIShProp = NULL; LoadStringFromResource(IDS_ALTERNATE_LIST_PATH, &m_bstrAlternateListPath); LoadStringFromResource(IDS_ALTERNATE_LIST_ACTIVE, &m_bstrAlternateListActive); LoadStringFromResource(IDS_ALTERNATE_LIST_STATUS, &m_bstrAlternateListStatus); LoadStringFromResource(IDS_ALTERNATE_LIST_YES, &m_bstrAlternateListYes); LoadStringFromResource(IDS_ALTERNATE_LIST_NO, &m_bstrAlternateListNo); LoadStringFromResource(IDS_ALTERNATE_LIST_OK, &m_bstrAlternateListOK); LoadStringFromResource(IDS_ALTERNATE_LIST_UNREACHABLE, &m_bstrAlternateListUnreachable); }
CDfsShellExtProp::~CDfsShellExtProp( ) /*++
Routine Description: dtor of CDfsShellExtProp. Free the notify handle. --*/ { /* ImageList_Destroy already called by the desctructor of list control
if (NULL != m_hImageList) ImageList_Destroy(m_hImageList); */ }
LRESULT CDfsShellExtProp::OnInitDialog( IN UINT i_uMsg, IN WPARAM i_wParam, LPARAM i_lParam, IN OUT BOOL& io_bHandled ) /*++
Routine Description: Called at the start. Used to set dialog defaults --*/ { SetDlgItemText(IDC_DIR_PATH, m_bstrDirPath);
_SetImageList(); _SetAlternateList();
return TRUE; }
HRESULT CDfsShellExtProp::put_DfsShellPtr( IN IShellPropSheetExt* i_pDfsShell ) /*++
Routine Description: Called at the start by CDfsShell. Used to set a back pointer to CDfsShell object to call Release(). --*/ { if (!i_pDfsShell) return(E_INVALIDARG);
if (m_pIShProp) m_pIShProp->Release();
m_pIShProp = i_pDfsShell; m_pIShProp->AddRef();
return(S_OK); }
HRESULT CDfsShellExtProp::put_DirPaths( IN BSTR i_bstrDirPath, IN BSTR i_bstrEntryPath ) /*++
Routine Description: Set the value of Directory Path for this directory. and the largest entrypath.
Arguments: i_bstrDirPath - Contains the new value for Entry Path i_bstrEntryPath - The largest Dfs entry path that matches this directory. --*/ { if (!i_bstrDirPath) return(E_INVALIDARG);
m_bstrDirPath = i_bstrDirPath; m_bstrEntryPath = i_bstrEntryPath;
if (!m_bstrDirPath || !i_bstrEntryPath) return(E_OUTOFMEMORY);
return S_OK; }
LRESULT CDfsShellExtProp::OnApply( ) { return TRUE; }
LRESULT CDfsShellExtProp::OnParentClosing( IN UINT i_uMsg, IN WPARAM i_wParam, LPARAM i_lParam, IN OUT BOOL& io_bHandled ) /*++
Routine Description: Used by the node to tell the propery page to close. --*/ { return TRUE; }
void CDfsShellExtProp::Delete() /*++
Routine Description: Called when property sheet is release to do clean up. */ { if (m_pIShProp) m_pIShProp->Release(); }
LRESULT CDfsShellExtProp::OnFlushPKT( IN WORD i_wNotifyCode, IN WORD i_wID, IN HWND i_hWndCtl, IN OUT BOOL& io_bHandled ) /*++
Routine Description: Called when Flush PKT table is called. Flushes client PKT table. */ { if (!m_bstrEntryPath) return(E_FAIL);
NET_API_STATUS nstatRetVal = 0; DFS_INFO_102 DfsInfoLevel102;
// Set timeout = 0 to flush local PKT.
DfsInfoLevel102.Timeout = 0;
// Display hour glass.
CWaitCursor WaitCursor;
nstatRetVal = NetDfsSetClientInfo( m_bstrEntryPath, NULL, NULL, 102, (LPBYTE) &DfsInfoLevel102 );
if (nstatRetVal != NERR_Success) DisplayMessageBoxForHR(HRESULT_FROM_WIN32(nstatRetVal));
return(true); }
void CDfsShellExtProp::_UpdateTextForReplicaState( IN HWND hwndControl, IN int nIndex, IN enum SHL_DFS_REPLICA_STATE ReplicaState ) { LVITEM lvi = {0};
lvi.iItem = nIndex; lvi.mask = LVIF_TEXT;
// insert the 2nd column "Active"
lvi.iSubItem = 1; if (ReplicaState == SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN || ReplicaState == SHL_DFS_REPLICA_STATE_ACTIVE_OK || ReplicaState == SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE ) lvi.pszText = m_bstrAlternateListYes; else lvi.pszText = m_bstrAlternateListNo;
ListView_SetItem(hwndControl, &lvi);
// insert the 3rd column "Status"
lvi.iSubItem = 2; switch (ReplicaState) { case SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN: case SHL_DFS_REPLICA_STATE_UNKNOWN: lvi.pszText = _T(""); break; case SHL_DFS_REPLICA_STATE_ACTIVE_OK: case SHL_DFS_REPLICA_STATE_OK: lvi.pszText = m_bstrAlternateListOK; break; case SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE: case SHL_DFS_REPLICA_STATE_UNREACHABLE: lvi.pszText = m_bstrAlternateListUnreachable; break; } ListView_SetItem(hwndControl, &lvi); }
void CDfsShellExtProp::_SetAlternateList() /*++
Routine Description: Finds out if the given path is a Dfs Path, and if it is then finds out the alternates available for this path up to the last directory. These are then added to the alternate list. */ { HWND hwndControl = ::GetDlgItem(m_hWnd, IDC_ALTERNATE_LIST);
if (NULL == ((CDfsShell *)m_pIShProp)->m_ppDfsAlternates) return;
//
// calculate the listview column width
//
RECT rect; ZeroMemory(&rect, sizeof(rect)); ::GetWindowRect(hwndControl, &rect); int nControlWidth = rect.right - rect.left; int nVScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL); int nBorderWidth = GetSystemMetrics(SM_CXBORDER); int nControlNetWidth = nControlWidth - nVScrollbarWidth - 4 * nBorderWidth; int nWidth1 = nControlNetWidth / 2; int nWidth2 = nControlNetWidth / 4; int nWidth3 = nControlNetWidth - nWidth1 - nWidth2;
//
// insert columns
//
LV_COLUMN col; ZeroMemory(&col, sizeof(col)); col.mask = LVCF_TEXT | LVCF_WIDTH; col.cx = nWidth1; col.pszText = m_bstrAlternateListPath; ListView_InsertColumn(hwndControl, 0, &col); col.cx = nWidth2; col.pszText = m_bstrAlternateListActive; ListView_InsertColumn(hwndControl, 1, &col); col.cx = nWidth3; col.pszText = m_bstrAlternateListStatus; ListView_InsertColumn(hwndControl, 2, &col);
//
// Set full row selection style
//
ListView_SetExtendedListViewStyleEx(hwndControl, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
// For each alternate stored in the parent shell object
// add to list.
for (int i = 0; NULL != ((CDfsShell *)m_pIShProp)->m_ppDfsAlternates[i] ; i++) { int nIndex = 0; LVITEM lvi = {0};
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; lvi.pszText = (((CDfsShell *)m_pIShProp)->m_ppDfsAlternates[i])->bstrAlternatePath; lvi.iImage = (((CDfsShell *)m_pIShProp)->m_ppDfsAlternates[i])->ReplicaState; lvi.lParam = (LPARAM)(((CDfsShell *)m_pIShProp)->m_ppDfsAlternates[i]); lvi.iSubItem = 0;
// Select the active replica.
switch ((((CDfsShell *)m_pIShProp)->m_ppDfsAlternates[i])->ReplicaState) { case SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN: case SHL_DFS_REPLICA_STATE_ACTIVE_OK: case SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE: lvi.mask |= LVIF_STATE; lvi.state = LVIS_SELECTED | LVIS_FOCUSED; nIndex = ListView_InsertItem(hwndControl, &lvi); break; case SHL_DFS_REPLICA_STATE_UNKNOWN: case SHL_DFS_REPLICA_STATE_OK: case SHL_DFS_REPLICA_STATE_UNREACHABLE: nIndex = ListView_InsertItem(hwndControl, &lvi); break; default: _ASSERT(FALSE); break; }
_UpdateTextForReplicaState(hwndControl, nIndex, (((CDfsShell *)m_pIShProp)->m_ppDfsAlternates[i])->ReplicaState); } }
HRESULT CDfsShellExtProp::_SetImageList( ) /*++
Routine Description: Create and initialize the Imagelist for alternates. --*/ { // Load bitmap from resource
HBITMAP hBitmap = (HBITMAP)LoadImage(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDB_Replica), IMAGE_BITMAP, 0, 0, LR_SHARED | LR_LOADTRANSPARENT); if(!hBitmap) return HRESULT_FROM_WIN32(GetLastError());;
// Try and get the exact bitmap size and number of bitmaps for
// image list
int icxBitmap = 16; int icyBitmap = 16; int iNoOfBitmaps = 6; BITMAP bmpRec; if (GetObject(hBitmap, sizeof(bmpRec), &bmpRec)) { if (bmpRec.bmHeight > 0) { icyBitmap = bmpRec.bmHeight; // Since the bitmaps are squares
icxBitmap = icyBitmap; // Since all the bitmaps are in a line in the original bitmap
iNoOfBitmaps = bmpRec.bmWidth / bmpRec.bmHeight; } }
// Create the image list
HIMAGELIST hImageList = ImageList_Create(icxBitmap, icyBitmap, ILC_COLOR, iNoOfBitmaps, 0); if (NULL == hImageList) { DeleteObject(hBitmap); return E_FAIL; }
ImageList_Add(hImageList, hBitmap, (HBITMAP)NULL);
// The specified image list will be destroyed when the list view control is destroyed.
SendDlgItemMessage( IDC_ALTERNATE_LIST, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)hImageList);
DeleteObject(hBitmap);
return S_OK; }
LRESULT CDfsShellExtProp::OnNotify( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) /*++
Routine Description: Notify message for user actions. We handle only the mouse double click right now
Arguments: i_lParam - Details about the control sending the notify io_bHandled - Whether we handled this message or not. --*/ { io_bHandled = FALSE; // So that the base class gets this notify too
NMHDR* pNMHDR = (NMHDR*)i_lParam; if (!pNMHDR) return FALSE;
if (IDC_ALTERNATE_LIST == pNMHDR->idFrom) { if (NM_DBLCLK == pNMHDR->code) { SetActive(); } else if (LVN_ITEMCHANGED == pNMHDR->code) { int n = ListView_GetSelectedCount(GetDlgItem(IDC_ALTERNATE_LIST)); ::EnableWindow(GetDlgItem(IDC_SET_ACTIVE), (n == 1)); } }
return TRUE; }
BOOL CDfsShellExtProp::SetActive() /*++
Routine Description: Sets the first selected alternate to be active. --*/ { HWND hwndAlternateLV = GetDlgItem(IDC_ALTERNATE_LIST); int iSelected = ListView_GetNextItem(hwndAlternateLV, -1, LVNI_ALL | LVNI_SELECTED); if (-1 == iSelected) return FALSE; // nothing selected
LV_ITEM lvItem = {0}; lvItem.mask = LVIF_PARAM; lvItem.iItem = iSelected;
ListView_GetItem(hwndAlternateLV, &lvItem);
LPDFS_ALTERNATES pDfsAlternate = (LPDFS_ALTERNATES)lvItem.lParam; if (!pDfsAlternate ) return(FALSE);
// set the item to be active
DFS_INFO_101 DfsInfo101 = {0}; DfsInfo101.State = DFS_STORAGE_STATE_ACTIVE; NET_API_STATUS nstatRetVal = NetDfsSetClientInfo( m_bstrEntryPath, pDfsAlternate->bstrServer, pDfsAlternate->bstrShare, 101, (LPBYTE) &DfsInfo101 );
if (nstatRetVal != NERR_Success) { DisplayMessageBoxForHR(HRESULT_FROM_WIN32(nstatRetVal)); return FALSE; }
// Reset the image of the last Active alternate/s to normal.
int nIndex = -1; while ((nIndex = ListView_GetNextItem(hwndAlternateLV, nIndex, LVNI_ALL)) != -1) { ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_PARAM; lvItem.iItem = nIndex;
ListView_GetItem(hwndAlternateLV, &lvItem);
LPDFS_ALTERNATES pTempDfsAlternate = (LPDFS_ALTERNATES)lvItem.lParam;
BOOL bActive = TRUE; switch (pTempDfsAlternate->ReplicaState) { case SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN: pTempDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_UNKNOWN; break; case SHL_DFS_REPLICA_STATE_ACTIVE_OK: pTempDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_OK; break; case SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE: pTempDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_UNREACHABLE; break; case SHL_DFS_REPLICA_STATE_UNKNOWN: case SHL_DFS_REPLICA_STATE_OK: case SHL_DFS_REPLICA_STATE_UNREACHABLE: default: bActive = FALSE; break; }
if (bActive) { lvItem.mask = LVIF_IMAGE | LVIF_STATE; lvItem.state = LVIS_SELECTED | LVIS_FOCUSED; lvItem.iImage = pTempDfsAlternate->ReplicaState; ListView_SetItem(hwndAlternateLV,&lvItem); _UpdateTextForReplicaState(hwndAlternateLV, nIndex, pTempDfsAlternate->ReplicaState);
break; } }
// set the new active alternate
BOOL bActive = FALSE; switch (pDfsAlternate->ReplicaState) { case SHL_DFS_REPLICA_STATE_UNKNOWN: pDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN; break; case SHL_DFS_REPLICA_STATE_OK: pDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_ACTIVE_OK; break; case SHL_DFS_REPLICA_STATE_UNREACHABLE: pDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE; break; case SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN: case SHL_DFS_REPLICA_STATE_ACTIVE_OK: case SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE: default: bActive = TRUE; break; }
if (!bActive) { lvItem.iItem = iSelected; lvItem.mask = LVIF_IMAGE; lvItem.iImage = pDfsAlternate->ReplicaState; ListView_SetItem(hwndAlternateLV,&lvItem); _UpdateTextForReplicaState(hwndAlternateLV, iSelected, pDfsAlternate->ReplicaState); }
return TRUE; }
/*++
This function is called when a user clicks the ? in the top right of a property sheet and then clciks a control, or when they hit F1 in a control. --*/ LRESULT CDfsShellExtProp::OnCtxHelp( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { LPHELPINFO lphi = (LPHELPINFO) i_lParam; if (!lphi || lphi->iContextType != HELPINFO_WINDOW || lphi->iCtrlId < 0) return FALSE;
::WinHelp((HWND)(lphi->hItemHandle), DFS_CTX_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(PVOID)g_aHelpIDs_IDD_DFS_SHELL_PROP);
return TRUE; }
/*++
This function handles "What's This" help when a user right clicks the control --*/ LRESULT CDfsShellExtProp::OnCtxMenuHelp( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { ::WinHelp((HWND)i_wParam, DFS_CTX_HELP_FILE, HELP_CONTEXTMENU, (DWORD_PTR)(PVOID)g_aHelpIDs_IDD_DFS_SHELL_PROP);
return TRUE; }
LRESULT CDfsShellExtProp::OnCheckStatus( IN WORD i_wNotifyCode, IN WORD i_wID, IN HWND i_hWndCtl, IN OUT BOOL& io_bHandled ) /*++
Routine Description: Checks the status of all selected alternates. If it is reachable then the reachable icon is displayed or the unreachable icon is displayed. --*/ { CWaitCursor WaitCursor; HWND hwndAlternateLV = GetDlgItem(IDC_ALTERNATE_LIST);
int nIndex = -1; while (-1 != (nIndex = ListView_GetNextItem(hwndAlternateLV, nIndex, LVNI_ALL | LVNI_SELECTED))) { LV_ITEM lvItem = {0}; lvItem.mask = LVIF_PARAM; lvItem.iItem = nIndex;
ListView_GetItem(hwndAlternateLV, &lvItem);
LPDFS_ALTERNATES pDfsAlternate = (LPDFS_ALTERNATES)lvItem.lParam; if (!pDfsAlternate ) return(FALSE);
// See if the path actaully exists (reachable).
DWORD dwErr = GetFileAttributes(pDfsAlternate->bstrAlternatePath); if (0xffffffff == dwErr) { // We failed to get the file attributes for entry path
switch (pDfsAlternate->ReplicaState) { case SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN: case SHL_DFS_REPLICA_STATE_ACTIVE_OK: case SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE: pDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE; break; case SHL_DFS_REPLICA_STATE_UNKNOWN: case SHL_DFS_REPLICA_STATE_OK: case SHL_DFS_REPLICA_STATE_UNREACHABLE: pDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_UNREACHABLE; break; default: _ASSERT(FALSE); break; } } else { switch (pDfsAlternate->ReplicaState) { case SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN: case SHL_DFS_REPLICA_STATE_ACTIVE_OK: case SHL_DFS_REPLICA_STATE_ACTIVE_UNREACHABLE: pDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_ACTIVE_OK; break; case SHL_DFS_REPLICA_STATE_UNKNOWN: case SHL_DFS_REPLICA_STATE_OK: case SHL_DFS_REPLICA_STATE_UNREACHABLE: pDfsAlternate->ReplicaState = SHL_DFS_REPLICA_STATE_OK; break; default: _ASSERT(FALSE); break; } }
lvItem.mask = LVIF_IMAGE; lvItem.iImage = pDfsAlternate->ReplicaState; ListView_SetItem(hwndAlternateLV,&lvItem);
_UpdateTextForReplicaState(hwndAlternateLV, nIndex, pDfsAlternate->ReplicaState); }
return TRUE; }
LRESULT CDfsShellExtProp::OnSetActiveReferral( IN WORD i_wNotifyCode, IN WORD i_wID, IN HWND i_hWndCtl, IN OUT BOOL& io_bHandled ) { SetActive(); return TRUE; }
HRESULT LoadStringFromResource( IN const UINT i_uResourceID, OUT BSTR* o_pbstrReadValue ) /*++
Routine Description:
This method returns a resource string. The method no longer uses a fixed string to read the resource. Inspiration from MFC's CString::LoadString.
Arguments: i_uResourceID - The resource id o_pbstrReadValue - The BSTR* into which the value is copied
--*/ { if (!o_pbstrReadValue) return E_INVALIDARG;
TCHAR szResString[1024]; ULONG uCopiedLen = 0; szResString[0] = NULL; // Read the string from the resource
uCopiedLen = ::LoadString(_Module.GetModuleInstance(), i_uResourceID, szResString, 1024);
// If nothing was copied it is flagged as an error
if(uCopiedLen <= 0) { return HRESULT_FROM_WIN32(::GetLastError()); } else { *o_pbstrReadValue = ::SysAllocString(szResString); if (!*o_pbstrReadValue) return E_OUTOFMEMORY; }
return S_OK; }
HRESULT GetErrorMessage( IN DWORD i_dwError, OUT BSTR* o_pbstrErrorMsg ) { if (0 == i_dwError || !o_pbstrErrorMsg) return E_INVALIDARG;
HRESULT hr = S_OK; LPTSTR lpBuffer = NULL;
DWORD dwRet = ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, i_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpBuffer, 0, NULL); if (0 == dwRet) { // if no message is found, GetLastError will return ERROR_MR_MID_NOT_FOUND
hr = HRESULT_FROM_WIN32(GetLastError());
if (HRESULT_FROM_WIN32(ERROR_MR_MID_NOT_FOUND) == hr || 0x80070000 == (i_dwError & 0xffff0000) || 0 == (i_dwError & 0xffff0000) ) { // Try locating the message from NetMsg.dll.
hr = S_OK; DWORD dwNetError = i_dwError & 0x0000ffff; HINSTANCE hLib = LoadLibrary(_T("netmsg.dll")); if (!hLib) hr = HRESULT_FROM_WIN32(GetLastError()); else { dwRet = ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, hLib, dwNetError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpBuffer, 0, NULL);
if (0 == dwRet) hr = HRESULT_FROM_WIN32(GetLastError());
FreeLibrary(hLib); } } }
if (SUCCEEDED(hr)) { *o_pbstrErrorMsg = SysAllocString(lpBuffer); LocalFree(lpBuffer); } else { // we failed to retrieve the error message from system/netmsg.dll,
// report the error code directly to user
hr = S_OK; TCHAR szString[32]; _stprintf(szString, _T("0x%x"), i_dwError); *o_pbstrErrorMsg = SysAllocString(szString); }
if (!*o_pbstrErrorMsg) hr = E_OUTOFMEMORY;
return hr; }
int DisplayMessageBox( IN HWND hwndParent, IN UINT uType, // style of message box
IN DWORD dwErr, IN UINT iStringId, // OPTIONAL: String resource Id
...) // Optional arguments
{ _ASSERT(dwErr != 0 || iStringId != 0); // One of the parameter must be non-zero
HRESULT hr = S_OK;
TCHAR szCaption[1024], szString[1024]; CComBSTR bstrErrorMsg, bstrResourceString, bstrMsg;
::LoadString(_Module.GetModuleInstance(), IDS_APPLICATION_NAME, szCaption, sizeof(szCaption)/sizeof(TCHAR));
if (dwErr) hr = GetErrorMessage(dwErr, &bstrErrorMsg);
if (SUCCEEDED(hr)) { if (iStringId == 0) { bstrMsg = bstrErrorMsg; } else { ::LoadString(_Module.GetModuleInstance(), iStringId, szString, sizeof(szString)/sizeof(TCHAR));
va_list arglist; va_start(arglist, iStringId); LPTSTR lpBuffer = NULL; DWORD dwRet = ::FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, szString, 0, // dwMessageId
0, // dwLanguageId, ignored
(LPTSTR)&lpBuffer, 0, // nSize
&arglist); va_end(arglist);
if (dwRet == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { bstrMsg = lpBuffer; if (dwErr) bstrMsg += bstrErrorMsg; LocalFree(lpBuffer); } } }
if (FAILED(hr)) { // Failed to retrieve the proper message, report the failure directly to user
_stprintf(szString, _T("0x%x"), hr); bstrMsg = szString; }
return ::MessageBox(hwndParent, bstrMsg, szCaption, uType); }
HRESULT DisplayMessageBoxForHR( IN HRESULT i_hr ) { DisplayMessageBox(::GetActiveWindow(), MB_OK, i_hr, 0);
return S_OK; }
|