Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1168 lines
25 KiB

/*++
Copyright (c) 1999 - 2000 Microsoft Corporation
Module Name:
util.c
Abstract:
Common used functions in fax configuration wizard
Environment:
Fax configuration wizard
Revision History:
03/13/00 -taoyuan-
Created it.
mm/dd/yy -author-
description
--*/
#include "faxcfgwz.h"
#include <devguid.h>
#include <shlwapi.h>
//
// Information about list of dependent services which we stopped
//
typedef struct {
PVOID pNext;
TCHAR serviceName[1];
} DEPENDENT_SERVICE_LIST, *PDEPENDENT_SERVICE_LIST;
//
// offset of field m in a struct s
// copied from stddef.h, so we don't need to include stddef.h
//
#define offsetof(s,m) (size_t)( (char *)&(((s *)0)->m) - (char *)0 )
VOID
LimitTextFields(
HWND hDlg,
INT *pLimitInfo
)
/*++
Routine Description:
Limit the maximum length for a number of text fields
Arguments:
hDlg - Specifies the handle to the dialog window
pLimitInfo - Array of text field control IDs and their maximum length
ID for the 1st text field, maximum length for the 1st text field
ID for the 2nd text field, maximum length for the 2nd text field
...
0
Note: The maximum length counts the NUL-terminator.
Return Value:
NONE
--*/
{
while (*pLimitInfo != 0) {
SendDlgItemMessage(hDlg, pLimitInfo[0], EM_SETLIMITTEXT, pLimitInfo[1]-1, 0);
pLimitInfo += 2;
}
}
INT
DisplayMessageDialog(
HWND hwndParent,
UINT type,
INT titleStrId,
INT formatStrId,
...
)
/*++
Routine Description:
Display a message dialog box
Arguments:
hwndParent - Specifies a parent window for the error message dialog
titleStrId - Title string (could be a string resource ID)
formatStrId - Message format string (could be a string resource ID)
...
Return Value:
NONE
--*/
{
TCHAR tszTitle[MAX_TITLE_LEN + 1];
TCHAR tszFormat[MAX_MESSAGE_LEN + 1];
TCHAR tszMessage[MAX_MESSAGE_LEN + 1];
va_list ap;
DEBUG_FUNCTION_NAME(TEXT("DisplayMessageDialog()"));
//
// Load dialog box title string resource
//
if (titleStrId == 0)
{
titleStrId = IDS_ERROR_TITLE;
}
if(!LoadString(g_hResource, titleStrId, tszTitle, ARR_SIZE(tszTitle)))
{
DebugPrintEx(DEBUG_ERR,
TEXT("LoadString failed: string ID=%d, error=%d"),
titleStrId,
GetLastError());
return IDCANCEL;
}
//
// Load message format string resource
//
if(!LoadString(g_hResource, formatStrId, tszFormat, ARR_SIZE(tszFormat)))
{
DebugPrintEx(DEBUG_ERR,
TEXT("LoadString failed: string ID=%d, error=%d"),
formatStrId,
GetLastError());
return IDCANCEL;
}
//
// Compose the message string
//
va_start(ap, formatStrId);
wvnsprintf(tszMessage, ARR_SIZE(tszMessage), tszFormat, ap);
va_end(ap);
//
// Terminate string with NULL regardless of success / failure of wvnsprintf
//
tszMessage[ARR_SIZE(tszMessage) - 1] = TEXT('\0');
//
// Display the message box
//
if (type == 0)
{
type = MB_OK | MB_ICONERROR;
}
return AlignedMessageBox(hwndParent, tszMessage, tszTitle, type);
}
int CALLBACK
BrowseCallbackProc(
HWND hDlg,
UINT uMsg,
LPARAM lParam,
LPARAM dwData
)
/*++
Routine Description:
We use this callback function to specify the initial folder
Arguments:
hDlg - Specifies the dialog window on which the Browse button is displayed
uMsg - Value identifying the event.
lParam - Value dependent upon the message contained in the uMsg parameter.
dwData - Application-defined value that was specified in the lParam member of the BROWSEINFO structure.
Return Value:
Returns zero.
--*/
{
switch(uMsg)
{
case BFFM_INITIALIZED:
SendMessage(hDlg, BFFM_SETSELECTION, TRUE, dwData);
break;
case BFFM_SELCHANGED:
{
BOOL bFolderIsOK = FALSE;
TCHAR szPath [MAX_PATH + 1];
if (SHGetPathFromIDList ((LPITEMIDLIST) lParam, szPath))
{
DWORD dwFileAttr = GetFileAttributes(szPath);
if (-1 != dwFileAttr && (dwFileAttr & FILE_ATTRIBUTE_DIRECTORY))
{
//
// The directory exists - enable the 'Ok' button
//
bFolderIsOK = TRUE;
}
}
//
// Enable / disable the 'ok' button
//
SendMessage(hDlg, BFFM_ENABLEOK , 0, (LPARAM)bFolderIsOK);
break;
}
}
return 0;
}
BOOL
BrowseForDirectory(
HWND hDlg,
INT hResource,
LPTSTR title
)
/*++
Routine Description:
Browse for a directory
Arguments:
hDlg - Specifies the dialog window on which the Browse button is displayed
hResource - resource id to receive the directory
title - the title to be shown in the browse dialog
Return Value:
TRUE if successful, FALSE if the user presses Cancel
--*/
{
LPITEMIDLIST pidl;
TCHAR buffer[MAX_PATH];
BOOL bResult = FALSE;
LPMALLOC pMalloc = NULL;
BROWSEINFO bi = {
hDlg,
NULL,
buffer,
title,
BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON,
BrowseCallbackProc,
(LPARAM) buffer,
};
DEBUG_FUNCTION_NAME(TEXT("BrowseForDirectory()"));
if (!GetDlgItemText( hDlg, hResource, buffer, MAX_PATH))
{
buffer[0] = 0;
}
if(E_FAIL == SHGetMalloc(&pMalloc))
{
DebugPrintEx(DEBUG_ERR, TEXT("SHGetMalloc failed"));
return bResult;
}
if (pidl = SHBrowseForFolder(&bi))
{
if (SHGetPathFromIDList(pidl, buffer))
{
if (lstrlen(buffer) > MAX_ARCHIVE_DIR)
{
DisplayMessageDialog(hDlg, 0, 0,IDS_ERR_DIR_TOO_LONG);
}
else
{
SetDlgItemText(hDlg, hResource, buffer);
bResult = TRUE;
}
}
pMalloc->lpVtbl->Free(pMalloc, (LPVOID)pidl);
}
pMalloc->lpVtbl->Release(pMalloc);
return bResult;
}
VOID
DisConnect(
)
/*++
Routine Description:
Close current connection to the fax service
Arguments:
None.
Return Value:
None.
--*/
{
if (g_hFaxSvcHandle) {
FaxClose(g_hFaxSvcHandle);
g_hFaxSvcHandle = NULL;
}
}
BOOL
Connect(
)
/*++
Routine Description:
Connect to the fax service
Arguments:
None.
Return Value:
TRUE if successfully connected, FALSE if there is an error.
--*/
{
DEBUG_FUNCTION_NAME(TEXT("Connect()"));
//
// Check if already connected to the fax service
//
if (g_hFaxSvcHandle) {
return TRUE;
}
//
// Connect to the fax service
//
if (!FaxConnectFaxServer(NULL, &g_hFaxSvcHandle))
{
LPCTSTR faxDbgFunction = TEXT("Connect()");
DebugPrintEx(DEBUG_ERR, TEXT("Can't connect to the fax server, ec = %d."), GetLastError());
return FALSE;
}
return TRUE;
}
DWORD
DoesTAPIHaveDialingLocation (
LPBOOL lpbRes
)
/*++
Routine name : DoesTAPIHaveDialingLocation
Routine description:
Checks if TAPI as at least one dialing location
Author:
Eran Yariv (EranY), Dec, 2000
Arguments:
lpbRes [out] - TRUE if TAPI has at least one dialing location. FALSE if none
Return Value:
Standard Win32 error code
--*/
{
DWORD dwRes = ERROR_SUCCESS;
HLINEAPP hLineApp = HandleToULong(NULL);
DWORD dwNumDevs;
LINEINITIALIZEEXPARAMS LineInitializeExParams;
DWORD dwAPIVer = 0x00020000;
LINETRANSLATECAPS LineTransCaps;
HANDLE hEvent = NULL;
DEBUG_FUNCTION_NAME(TEXT("DoesTAPIHaveDialingLocation"));
//
// Create a dummy event
//
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!hEvent)
{
DebugPrintEx(DEBUG_ERR,
TEXT("CreateEvent failed: %#lx"),
GetLastError());
return GetLastError ();
}
//
// Initialize TAPI
//
LineInitializeExParams.dwTotalSize = sizeof(LINEINITIALIZEEXPARAMS);
LineInitializeExParams.dwNeededSize = 0;
LineInitializeExParams.dwUsedSize = 0;
LineInitializeExParams.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT ;
LineInitializeExParams.Handles.hEvent = hEvent;
dwRes = (DWORD)lineInitializeEx(
&hLineApp,
GetModuleHandle(NULL),
NULL,
NULL,
&dwNumDevs,
&dwAPIVer,
&LineInitializeExParams
);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(DEBUG_ERR,
TEXT("lineInitializeEx failed: %#lx"),
dwRes);
goto exit;
}
LineTransCaps.dwTotalSize = sizeof(LINETRANSLATECAPS);
dwRes = (DWORD)lineGetTranslateCaps (hLineApp, 0x00020000, &LineTransCaps);
if ((DWORD)LINEERR_INIFILECORRUPT == dwRes)
{
//
// This is a special return code from TAPI which indicates no dialing rules are defined.
//
*lpbRes = FALSE;
}
else
{
*lpbRes = TRUE;
}
dwRes = ERROR_SUCCESS;
exit:
if (hLineApp)
{
lineShutdown (hLineApp);
}
if (hEvent)
{
CloseHandle (hEvent);
}
return dwRes;
} // DoesTAPIHaveDialingLocation
void
InstallModem (
HWND hWnd
)
/*++
Routine Description:
Pop up the hardware installation wizard to install a modem.
Arguments:
hWnd - window handle of the caller.
Return Value:
None.
--*/
{
HINSTANCE hInst = NULL;
PINSTNEWDEV pInstNewDev;
DEBUG_FUNCTION_NAME(TEXT("InstallModem()"));
hInst = LoadLibrary (NEW_DEV_DLL);
if (NULL == hInst)
{
DebugPrintEx(DEBUG_ERR, TEXT("LoadLibrary failed: %#lx"), GetLastError());
return;
}
pInstNewDev = (PINSTNEWDEV)GetProcAddress (hInst, INSTALL_NEW_DEVICE);
if (NULL != pInstNewDev)
{
EnableWindow (hWnd, FALSE);
pInstNewDev (hWnd, (LPGUID)&GUID_DEVCLASS_MODEM, NULL);
EnableWindow (hWnd, TRUE);
}
else
{
DebugPrintEx(DEBUG_ERR, TEXT("GetProcAddress failed: %#lx"), GetLastError());
}
FreeLibrary (hInst);
DebugPrintEx(DEBUG_MSG, TEXT("Exit modem installation."));
return;
} // InstallModem
BOOL
StartFaxService(
LPTSTR pServerName
)
/*++
Routine Description:
Start the fax service
Arguments:
pServerName - Specifies the name of the server computer, NULL for local machine
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
BOOL success = FALSE;
DEBUG_FUNCTION_NAME(TEXT("StartFaxService()"));
//
// Start the fax service and wait for it to be in the running state
//
if (EnsureFaxServiceIsStarted(pServerName))
{
success = WaitForServiceRPCServer(60 * 1000);
if(!success)
{
DebugPrintEx(DEBUG_ERR, TEXT("WaitForServiceRPCServer failed: %d"), GetLastError());
}
}
return success;
}
BOOL
IsUserInfoConfigured()
/*++
Routine Description:
Check whether it's the first time starting the wizard
Arguments:
Return Value:
TRUE if User Info Configured, FALSE if not
--*/
{
//
// Set flag in the registry to specify we have done the
// fax configuration wizard
//
HKEY hRegKey;
BOOL bRes = FALSE;
DEBUG_FUNCTION_NAME(TEXT("IsUserInfoConfigured()"));
//
// Open the user registry key for writing and create it if necessary
//
if ((hRegKey = OpenRegistryKey(HKEY_CURRENT_USER, REGKEY_FAX_SETUP, TRUE, KEY_QUERY_VALUE)))
{
bRes = GetRegistryDword(hRegKey, REGVAL_CFGWZRD_USER_INFO);
//
// Close the registry key before returning to the caller
//
RegCloseKey(hRegKey);
}
else
{
LPCTSTR faxDbgFunction = TEXT("IsUserInfoConfigured()");
DebugPrintEx(DEBUG_ERR, TEXT("Can't open registry to set the wizard flag."));
}
return bRes;
}
BOOL
FaxDeviceEnableRoutingMethod(
HANDLE hFaxHandle,
DWORD dwDeviceId,
LPCTSTR pRoutingGuid,
LONG Enabled
)
/*++
Routine Description:
Get or set the current status of a routing method for specific device
Arguments:
hFaxHandle - fax handle by FaxConnectFaxServer()
dwDeviceId - device ID
pRoutingGuid - GUID that identifies the fax routing method
Enabled - enabled status for the device and method, if Enabled is QUERY_STATUS,
it means return value is the current state
Return Value:
if Enabled is QUERY_STATUS, return the current state of routing method;
if Enabled is QUERY_ENABLE or QUERY_DISABLE, return TRUE for success, FALSE for failure.
--*/
{
BOOL bRes = FALSE;
PFAX_ROUTING_METHOD pRoutMethod = NULL;
DWORD dwMethodsNum;
HANDLE hFaxPortHandle = NULL;
DWORD dwInx;
DEBUG_FUNCTION_NAME(TEXT("FaxDeviceEnableRoutingMethod()"));
if(!hFaxHandle)
{
Assert(FALSE);
return bRes;
}
if(!FaxOpenPort(hFaxHandle,
dwDeviceId,
PORT_OPEN_QUERY | PORT_OPEN_MODIFY,
&hFaxPortHandle))
{
DebugPrintEx(DEBUG_ERR, TEXT("FaxOpenPort failed: %d."), GetLastError());
goto exit;
}
if(Enabled == QUERY_STATUS)
{
if(!FaxEnumRoutingMethods(hFaxPortHandle, &pRoutMethod, &dwMethodsNum))
{
DebugPrintEx(DEBUG_ERR, TEXT("FaxEnumRoutingMethods failed: %d."), GetLastError());
goto exit;
}
for(dwInx=0; dwInx < dwMethodsNum; ++dwInx)
{
if(!_tcsicmp(pRoutMethod[dwInx].Guid, pRoutingGuid))
{
bRes = pRoutMethod[dwInx].Enabled;
goto exit;
}
}
DebugPrintEx(DEBUG_MSG, TEXT("Routing method not found"));
goto exit;
}
else
{
if(!FaxEnableRoutingMethod(hFaxPortHandle,
pRoutingGuid,
(Enabled == STATUS_ENABLE) ? TRUE : FALSE))
{
DebugPrintEx(DEBUG_ERR, TEXT("FaxEnableRoutingMethod failed: %d."), GetLastError());
goto exit;
}
}
bRes = TRUE;
exit:
if(pRoutMethod)
{
FaxFreeBuffer(pRoutMethod);
}
if(hFaxPortHandle)
{
FaxClose(hFaxPortHandle);
}
return bRes;
}
BOOL
VerifyDialingLocations (
HWND hWndParent
)
/*++
Routine name : VerifyDialingLocations
Routine description:
Makes sure there's at least one TAPI dialing location defined.
If none are defined, pops the system U/I for defining one.
If the user cancels that U/I, offer the user a chance to re-enter a dialing location.
If the user still refuses, return FALSE.
Author:
Eran Yariv (EranY), Jan, 2001
Arguments:
hWndParent [in] - Parent window handle
Return Value:
See discussion on the return value in the description above.
--*/
{
BOOL bDialingRulesDefined;
DWORD dwRes;
DEBUG_FUNCTION_NAME(TEXT("VerifyDialingLocations"));
//
// Check if there are dialing rules defined
//
dwRes = DoesTAPIHaveDialingLocation (&bDialingRulesDefined);
if (ERROR_SUCCESS != dwRes)
{
//
// Can't detect - return now.
// Assume TRUE.
//
return TRUE;
}
if (bDialingRulesDefined)
{
//
// Good. Return TRUE
//
return TRUE;
}
for (;;)
{
//
// No dialing rules defined, pop the simple dialing rules dialog
//
extern LONG LOpenDialAsst(
IN HWND hwnd,
IN LPCTSTR lpszAddressIn,
IN BOOL fSimple, // if TRUE, uses a dialog for dialing locations. Otherwise, uses a property sheet.
IN BOOL fSilentInstall );
EnableWindow (hWndParent, FALSE);
LOpenDialAsst(hWndParent, NULL, TRUE, TRUE);
EnableWindow (hWndParent, TRUE);
//
// After we popped the system dialing locations dialog, we should check and see if a location was really added.
//
dwRes = DoesTAPIHaveDialingLocation (&bDialingRulesDefined);
if (ERROR_SUCCESS != dwRes)
{
//
// Can't detect - return now.
// Assume TRUE.
//
return TRUE;
}
if (bDialingRulesDefined)
{
//
// Good. The user just added a dialing rule
//
return TRUE;
}
//
// Oh no - the user canceled.
// Pop a message box asking him to retry
//
if (IDYES == DisplayMessageDialog(hWndParent,
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2,
0,
IDS_ERR_NO_DIALING_LOCATION))
{
//
// User chose to abort the wizard - return now
//
return FALSE;
}
//
// Try again
//
}
ASSERT_FALSE;
} // VerifyDialingLocations
DWORD
CountFaxDevices ()
/*++
Routine name : CountFaxDevices
Routine description:
Counts the number of fax devices (ports) the service knows about
Author:
Eran Yariv (EranY), Apr, 2001
Arguments:
Return Value:
Standard Win32 error code
--*/
{
PFAX_PORT_INFO_EX pPortsInfo = NULL;
DWORD dwPorts;
DEBUG_FUNCTION_NAME(TEXT("CountFaxDevices()"));
if(!FaxEnumPortsEx(g_hFaxSvcHandle, &pPortsInfo, &dwPorts))
{
DebugPrintEx(DEBUG_MSG, TEXT("FaxEnumPortsEx: failed: error=%d."), GetLastError());
return 0;
}
if(pPortsInfo)
{
FaxFreeBuffer(pPortsInfo);
}
return dwPorts;
} // CountFaxDevices
BOOL
IsFaxDeviceInstalled(
HWND hWnd,
LPBOOL lpbAbort
)
/*++
Routine Description:
Checks if some fax devices are installed.
If not, suggest to the user to install a device.
Also, checks if TAPI has a dialing location.
If not, asks the user to add one.
If the user refuses, sets lpbAbort to TRUE and return FALSE.
Arguments:
hWnd - [in] caller window handle
lpbAbort - [out] TRUE if the user refused to enter a dialing location and the calling process should abort.
Return Value:
return TRUE for YES, FALSE for NO
--*/
{
DWORD dwDevices;
DEBUG_FUNCTION_NAME(TEXT("IsFaxDeviceInstalled()"));
//
// See how many fax devices the server has found
//
dwDevices = CountFaxDevices();
if(0 == dwDevices)
{
int iInstallNewModem;
//
// no available device, pop up a U/I to install modem
//
iInstallNewModem = DisplayMessageDialog(hWnd,
MB_YESNO | MB_ICONQUESTION,
0,
IDS_ERR_NO_DEVICE);
if(iInstallNewModem == IDYES)
{
//
// Make sure we have at least one TAPI dialing location.
// If not, pop a system U/I for the dialing locations.
//
HCURSOR hOldCursor;
int i;
if (!VerifyDialingLocations (hWnd))
{
//
// The user refused to enter a dialing location and the calling process should abort.
//
*lpbAbort = TRUE;
return FALSE;
}
hOldCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
InstallModem(hWnd);
//
// We don't need to restart the service because the
// service can detect the addition of new fax devices.
// Let's wait a while for the service to discover the new device.
// We wait up to 12 seconds.
//
for (i=0; i < 4; i++)
{
Sleep (3000);
dwDevices = CountFaxDevices();
if (dwDevices)
{
//
// Hooray. Device found by service
//
break;
}
}
SetCursor (hOldCursor);
}
}
else
{
//
// At least one device is already installed.
// Make sure we have at least one TAPI dialing location.
// If not, pop a system U/I for the dialing locations.
//
if (!VerifyDialingLocations (hWnd))
{
//
// The user refused to enter a dialing location and the calling process should abort.
//
*lpbAbort = TRUE;
return FALSE;
}
}
return (dwDevices != 0);
} // IsFaxDeviceInstalled
VOID
ListView_SetDeviceImageList(
HWND hwndLv,
HINSTANCE hinst
)
/*++
Routine Description:
Sets ImageList to list view
Arguments:
hwndLv - list view handle
hinst - application instance
Return Value:
none
--*/
{
HICON hIcon;
HIMAGELIST himl;
himl = ImageList_Create(
GetSystemMetrics( SM_CXSMICON ),
GetSystemMetrics( SM_CYSMICON ),
ILC_MASK, 2, 2 );
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IDI_Modem ) );
Assert(hIcon);
ImageList_ReplaceIcon( himl, -1, hIcon );
DestroyIcon( hIcon );
ListView_SetImageList( hwndLv, himl, LVSIL_SMALL );
}
BOOL
IsSendEnable()
/*++
Routine Description:
Determine if the any of the devices configured to send faxes
Arguments:
Return Value:
TRUE or FALSE
--*/
{
DWORD dw;
if(NULL == g_wizData.pDevInfo)
{
return FALSE;
}
for(dw=0; dw < g_wizData.dwDeviceCount; ++dw)
{
if(g_wizData.pDevInfo[dw].bSend)
{
return TRUE;
}
}
return FALSE;
}
BOOL
IsReceiveEnable()
/*++
Routine Description:
Determine if the any of the devices configured to receive faxes
Arguments:
Return Value:
TRUE or FALSE
--*/
{
DWORD dw;
if(NULL == g_wizData.pDevInfo)
{
return FALSE;
}
for(dw=0; dw < g_wizData.dwDeviceCount; ++dw)
{
if(FAX_DEVICE_RECEIVE_MODE_OFF != g_wizData.pDevInfo[dw].ReceiveMode)
{
return TRUE;
}
}
return FALSE;
}
int
GetDevIndexByDevId(
DWORD dwDeviceId
)
/*++
Routine Description:
Finds appropriate item index in WIZARDDATA.pDevInfo array
by device ID
Arguments:
dwDeviceId - device ID
Return Value:
device index in WIZARDDATA.pDevInfo array
or -1 on failure
--*/
{
DWORD dwIndex;
if(NULL == g_wizData.pDevInfo)
{
Assert(FALSE);
return -1;
}
for(dwIndex = 0; dwIndex < g_wizData.dwDeviceCount; ++dwIndex)
{
if(g_wizData.pDevInfo[dwIndex].dwDeviceId == dwDeviceId)
{
return (int)dwIndex;
}
}
Assert(FALSE);
return -1;
}
VOID
InitDeviceList(
HWND hDlg,
DWORD dwListViewResId
)
/*++
Routine Description:
Initializes devices list view control
Arguments:
hDlg - Handle to property page
dwListViewResId - list view resource ID
Return Value:
NONE
--*/
{
HWND hwndLv;
LV_COLUMN col = {0};
DEBUG_FUNCTION_NAME(TEXT("InitDeviceList()"));
Assert(hDlg);
hwndLv = GetDlgItem(hDlg, dwListViewResId);
Assert(hwndLv);
//
// Add the modem images.
//
ListView_SetDeviceImageList(hwndLv, g_hResource );
ListView_SetExtendedListViewStyle(hwndLv, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
//
// Add a single column exactly wide enough to fully display
// the widest member of the list.
//
col.mask = LVCF_FMT;
col.fmt = LVCFMT_LEFT;
ListView_InsertColumn(hwndLv, 0, &col );
return;
}