/**************************************************************************** Copyright (c) Microsoft Corporation 1997 All rights reserved ***************************************************************************/ #include "pch.h" #include #include #include #include #include "dialogs.h" DEFINE_MODULE("Setup"); #define SMALL_BUFFER_SIZE 256 #define MAX_FILES_SIZE 640000 static const TCHAR chSlash = TEXT('\\'); // // Opens the layout.inf file for a particular platform. // HINF OpenLayoutInf( ) { TCHAR szFilename[ MAX_PATH ]; HANDLE hFile; UINT uErr; DWORD dwLen; DWORD dw; lstrcpy( szFilename, g_Options.szSourcePath ); dwLen = lstrlen( szFilename ); szFilename[ dwLen++ ] = chSlash; dw = LoadString( g_hinstance, IDS_NTSETUPINFFILENAME, &szFilename[ dwLen ], ARRAYSIZE( szFilename ) - dwLen ); Assert( dw ); hFile = SetupOpenInfFile( szFilename, NULL, INF_STYLE_WIN4, &uErr ); return hFile; } // // Creates the RemoteBoot directory tree. // HRESULT CreateDirectories( HWND hDlg ) { BOOL fReturn = FALSE; TCHAR szPath[ MAX_PATH ]; TCHAR szCreating[ SMALL_BUFFER_SIZE ]; HWND hProg = GetDlgItem( hDlg, IDC_P_METER ); DWORD dwLen; DWORD dw; SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM(0, 4 + ( g_Options.fCreateDirectory ? 1 : 0 )) ); SendMessage( hProg, PBM_SETSTEP, 1, 0 ); dw = LoadString( g_hinstance, IDS_CREATINGDIRECTORIES, szCreating, ARRAYSIZE( szCreating ) ); Assert( dw ); SetWindowText( GetDlgItem( hDlg, IDC_S_OPERATION ), szCreating ); if ( g_Options.fCreateDirectory ) { fReturn = CreateDirectory( g_Options.szRemoteBootPath, NULL ); SendMessage( hProg, PBM_DELTAPOS, 1, 0 ); if ( !fReturn ) goto Finish; } lstrcpy( szPath, g_Options.szRemoteBootPath ); dwLen = lstrlen( szPath ); szPath[ dwLen ] = chSlash; dwLen++; dw = LoadString( g_hinstance, IDS_IMAGES, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); CreateDirectory( szPath, NULL ); SendMessage( hProg, PBM_DELTAPOS, 1, 0 ); lstrcpy( g_Options.szImagesPath, szPath ); dw = LoadString( g_hinstance, IDS_TEMPLATEPATH, &szPath[ dwLen ], ARRAYSIZE( szPath )- dwLen ); Assert( dw ); CreateDirectory( szPath, NULL ); SendMessage( hProg, PBM_DELTAPOS, 1, 0 ); dw = LoadString( g_hinstance, IDS_SETUP, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); CreateDirectory( szPath, NULL ); SendMessage( hProg, PBM_DELTAPOS, 1, 0 ); dwLen = lstrlen( szPath ); szPath[ dwLen ] = chSlash; dwLen++; lstrcpy( &szPath[ dwLen ], g_Options.szName ); CreateDirectory( szPath, NULL ); SendMessage( hProg, PBM_DELTAPOS, 1, 0 ); /* // add '\i386' dwLen = lstrlen( szPath ); szPath[ dwLen ] = chSlash; dwLen++; dw = LoadString( g_hinstance, IDS_INTELPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); */ lstrcpy( g_Options.szSetupPath, szPath ); fReturn = TRUE; Finish: g_Options.fError = !fReturn; return fReturn ? S_OK : E_FAIL; } // // Find the filename part from a complete path. // LPTSTR FilenameOnly( LPTSTR pszPath ) { LPTSTR psz = pszPath; // find the end while ( *psz ) psz++; // find the slash while ( psz > pszPath && *psz != chSlash ) psz--; // move in front of the slash if ( psz != pszPath ) psz++; return psz; } typedef struct { PVOID pContext; // "Context" for DefaultQueueCallback HWND hProg; // hwnd to the progress meter HWND hOperation; // hwnd to the "current operation" DWORD nCopied; // number of files copied DWORD nToBeCopied; // number of file to be copied DWORD dwCopyingLength; // length of the IDS_COPYING TCHAR szCopyingString[ SMALL_BUFFER_SIZE ]; // buffer to create "Copying file.ext..." } MYCONTEXT, *LPMYCONTEXT; // // // UINT CALLBACK CopyFilesCallback( IN PVOID Context, IN UINT Notification, IN UINT Param1, IN UINT Param2 ) { MSG Msg; LPMYCONTEXT pMyContext = (LPMYCONTEXT) Context; DWORD dw; // process some messages if ( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &Msg ); DispatchMessage( &Msg ); } if ( g_Options.fAbort ) { if ( !g_Options.fError ) { TCHAR szAbort[ SMALL_BUFFER_SIZE ]; // change filename text to aborting... dw = LoadString( g_hinstance, IDS_ABORTING, szAbort, ARRAYSIZE( szAbort ) ); Assert( dw ); SetWindowText( pMyContext->hOperation, szAbort ); g_Options.fError = TRUE; } SetLastError(ERROR_CANCELLED); return FILEOP_ABORT; } switch ( Notification ) { case SPFILENOTIFY_ENDCOPY: pMyContext->nCopied++; SendMessage( pMyContext->hProg, PBM_SETPOS, (1000 * pMyContext->nCopied) / pMyContext->nToBeCopied, 0 ); break; case SPFILENOTIFY_STARTCOPY: { DWORD dwLen; LPTSTR * ppszCopyingFile = (LPTSTR *) Param1; lstrcpy( &pMyContext->szCopyingString[ pMyContext->dwCopyingLength ], FilenameOnly( *ppszCopyingFile ) ); dwLen = lstrlen( pMyContext->szCopyingString ); lstrcpy( &pMyContext->szCopyingString[ dwLen ], TEXT("...") ); SetWindowText( pMyContext->hOperation, pMyContext->szCopyingString ); } break; case SPFILENOTIFY_RENAMEERROR: case SPFILENOTIFY_DELETEERROR: case SPFILENOTIFY_COPYERROR: case SPFILENOTIFY_NEEDMEDIA: case SPFILENOTIFY_LANGMISMATCH: case SPFILENOTIFY_TARGETEXISTS: case SPFILENOTIFY_TARGETNEWER: return SetupDefaultQueueCallback( pMyContext->pContext, Notification, Param1, Param2 ); } return FILEOP_DOIT; } // // Find a character in a NULL terminated string. // // Returns NULL is not found. // LPTSTR FindChar( LPTSTR pszSrc, TCHAR ch ) { if ( pszSrc ) { while ( *pszSrc ) { if ( *pszSrc == ch ) return pszSrc; pszSrc++; } } return NULL; } // // change layout format to double-null list // void LayoutToDoubleNullList( LPTSTR pszList ) { /* Borrowed from LAYOUT.INF for reference ; ; filename_on_source = diskid,subdir,size,checksum,spare,spare ; extra fields are nt-specific ; bootmediaord: _1 (floppy #1) ; _2 (floppy #2) ; _3 (floppy #3) ; _x (textmode setup) ; nothing (gui mode setup) ; targetdirectory : 1 - 41 (see "WinntDirectories", above) ; upgradedisposition : 0 (always copy) ; 1 (copy if present) ; 2 (copy if not present) ; 3 (never copy) ; textmodedisposition: ; targetname ; */ static const TCHAR chComma = TEXT(','); LPTSTR pszFile = pszList; LPTSTR pszCopyHere = pszList; while ( *pszFile ) { MSG Msg; DWORD dwToNextFile = lstrlen( pszFile ); LPTSTR pszNext; LPTSTR psz = FindChar( pszFile, TEXT('=') ); Assert( psz ); // process some messages if ( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &Msg ); DispatchMessage( &Msg ); } *psz = 0; psz++; pszNext = FindChar( psz, chComma ); *pszNext = 0; // must be "1" if ( !lstrcmp( psz, TEXT("1") ) ) { // copy file name lstrcpy( pszCopyHere, pszFile ); // advance copy pointer pszCopyHere += 1 + lstrlen( pszCopyHere ); } else { AssertMsg( FALSE, "Now what?!" ); } // advanced file pointer pszFile += dwToNextFile + 1; } *pszCopyHere = 0; } // // change semicolon delinated list to double-null list // void SemiColonToDoubleNullList( LPTSTR pszList ) { while ( *pszList ) { if ( *pszList == TEXT(';') ) { *pszList = 0; } pszList++; } pszList++; *pszList = 0; // double the null. } // // Adds double-null terminated list of file name to the Queue. The filename // can have a comma in it indicating a rename operation: // optionalpath\newname.ext,optionalpath\sourcefil.ext // // Returns the number of files added to the Queue. // DWORD CopyFilesAddToQueue( HSPFILEQ Queue, // setup Queue LPTSTR pszSource, // source directory LPTSTR pszDest, // destination directory LPTSTR pszFiles, // Double-null terminated file list LPTSTR pszSubpath, // optional sub-path DWORD dwCopyStyle) // flags { DWORD dwCount = 0; LPTSTR psz = pszFiles; static const TCHAR chComma = TEXT(','); while ( *pszFiles ) { DWORD dwLen; psz = pszFiles; // check for comma which indicates rename while (*psz && *psz != chComma) psz++; if ( *psz == chComma ) { *psz= 0; // terminate psz++; } else { // sources name is dest name psz = pszFiles; } SetupQueueCopy( Queue, pszSource, pszSubpath, psz, NULL, NULL, pszDest, pszFiles, dwCopyStyle ); // get next file pszFiles = psz + lstrlen( psz ) + 1; dwCount++; } return dwCount; } // // Copies the files into the setup directory. // HRESULT CopyFiles( HWND hDlg ) { TCHAR szLayoutFilename[ MAX_PATH ]; TCHAR szSystemPath[ MAX_PATH ]; DWORD dwLen; LPTSTR psz; BOOL fReturn = FALSE; HWND hProg = GetDlgItem( hDlg, IDC_P_METER ); LPTSTR pszFiles = (LPTSTR) TraceAlloc( GMEM_FIXED, MAX_FILES_SIZE ); DWORD dwCount = 0; DWORD dw; HSPFILEQ Queue; MYCONTEXT MyContext; if ( !pszFiles || g_Options.fAbort ) goto Finish; // Setup and display next section of dialog SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM(0, 1000 )); SendMessage( hProg, PBM_SETPOS, 0, 0 ); dw = LoadString( g_hinstance, IDS_BUILDINGFILELIST, szLayoutFilename, ARRAYSIZE( szLayoutFilename )); Assert( dw ); SetDlgItemText( hDlg, IDC_S_OPERATION, szLayoutFilename ); // Create layout filepath lstrcpy( szLayoutFilename, g_Options.szSourcePath ); dwLen = lstrlen( szLayoutFilename ); szLayoutFilename[ dwLen ] = chSlash; dwLen++; dw = LoadString( g_hinstance, IDS_NTSETUPINFFILENAME, &szLayoutFilename[ dwLen ], ARRAYSIZE( szLayoutFilename )- dwLen ); Assert( dw ); Queue = SetupOpenFileQueue( ); // add the files from the INF to the Queue GetPrivateProfileSection( TEXT("SourceDisksFiles"), pszFiles, MAX_FILES_SIZE, szLayoutFilename ); LayoutToDoubleNullList( pszFiles ); if ( g_Options.fIntel ) { TCHAR szPath[ MAX_PATH ]; DWORD dwLen; lstrcpy( szPath, g_Options.szSetupPath ); dwLen = lstrlen( szPath ); szPath[ dwLen++ ] = chSlash; dw = LoadString( g_hinstance, IDS_INTELPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_WARNIFSKIP ); // add the processor dependant files from the INF to the Queue GetPrivateProfileSection( TEXT("SourceDisksFiles.x86"), pszFiles, MAX_FILES_SIZE, szLayoutFilename ); LayoutToDoubleNullList( pszFiles ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_WARNIFSKIP ); // additional files not listed dw = LoadString( g_hinstance, IDS_FILESTOBECOPIED, pszFiles, MAX_FILES_SIZE ); SemiColonToDoubleNullList( pszFiles ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_WARNIFSKIP ); } if ( g_Options.fAlpha ) { TCHAR szPath[ MAX_PATH ]; DWORD dwLen; lstrcpy( szPath, g_Options.szSetupPath ); dwLen = lstrlen( szPath ); szPath[ dwLen++ ] = chSlash; dw = LoadString( g_hinstance, IDS_ALPHAPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_WARNIFSKIP ); // add the processor dependant files from the INF to the Queue GetPrivateProfileSection( TEXT("SourceDisksFiles.Alpha"), pszFiles, MAX_FILES_SIZE, szLayoutFilename ); LayoutToDoubleNullList( pszFiles ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_WARNIFSKIP ); // additional files not listed dw = LoadString( g_hinstance, IDS_FILESTOBECOPIED, pszFiles, MAX_FILES_SIZE ); Assert( dw ); SemiColonToDoubleNullList( pszFiles ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_WARNIFSKIP ); } // add template files if ( g_Options.fIntel ) { TCHAR szPath[ MAX_PATH ]; DWORD dwLen; lstrcpy( szPath, g_Options.szRemoteBootPath ); dwLen = lstrlen( szPath ); szPath[ dwLen++ ] = chSlash; dw = LoadString( g_hinstance, IDS_TEMPLATEPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( szPath ); dwLen = lstrlen( szPath ); szPath[ dwLen++ ] = chSlash; dw = LoadString( g_hinstance, IDS_INTELPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); dw = LoadString( g_hinstance, IDS_TEMPLATEFILES_INTEL, pszFiles, MAX_FILES_SIZE ); Assert( dw ); SemiColonToDoubleNullList( pszFiles ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_NOOVERWRITE | SP_COPY_WARNIFSKIP ); } if ( g_Options.fAlpha ) { TCHAR szPath[ MAX_PATH ]; DWORD dwLen; lstrcpy( szPath, g_Options.szRemoteBootPath ); dwLen = lstrlen( szPath ); szPath[ dwLen++ ] = chSlash; dw = LoadString( g_hinstance, IDS_TEMPLATEPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); dwLen = lstrlen( szPath ); szPath[ dwLen++ ] = chSlash; dw = LoadString( g_hinstance, IDS_INTELPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen ); Assert( dw ); dw = LoadString( g_hinstance, IDS_TEMPLATEFILES_ALPHA, pszFiles, MAX_FILES_SIZE ); Assert( dw ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_NOOVERWRITE | SP_COPY_WARNIFSKIP ); } /* BEGIN ADD/REMOVE PROGRAMS SHOULD DO THIS PART // add the services to the Queue GetSystemDirectory( szSystemPath, MAX_PATH ); dw = LoadString( g_hinstance, IDS_SERVICESFILES, pszFiles, MAX_FILES_SIZE ); Assert( dw ); SemiColonToDoubleNullList( pszFiles ); dwCount += CopyFilesAddToQueue( Queue, g_Options.szSourcePath, szSystemPath, pszFiles, NULL, SP_COPY_NEWER | SP_COPY_NOOVERWRITE | SP_COPY_WARNIFSKIP ); END */ // This information will be passed to CopyFileCallback() as // the Context. MyContext.nToBeCopied = dwCount; MyContext.nCopied = 0; MyContext.pContext = SetupInitDefaultQueueCallback( hDlg ); MyContext.hProg = hProg; MyContext.hOperation = GetDlgItem( hDlg, IDC_S_OPERATION ); MyContext.dwCopyingLength = LoadString( g_hinstance, IDS_COPYING, MyContext.szCopyingString, ARRAYSIZE( MyContext.szCopyingString ) ); Assert( MyContext.dwCopyingLength ); // Start copying fReturn = SetupCommitFileQueue( hDlg, Queue, (PSP_FILE_CALLBACK) CopyFilesCallback, (PVOID) &MyContext ); Finish: SendMessage( hProg, PBM_SETPOS, 1000, 0 ); if ( Queue ) SetupCloseFileQueue( Queue ); if ( pszFiles ) TraceFree( pszFiles ); g_Options.fError = !fReturn; return fReturn ? S_OK : E_FAIL; } // // Modifies registry entries from the SELFREG.INF resource // HRESULT ModifyRegistry( HWND hDlg ) { HRESULT hr = E_FAIL; char szRemoteBootPath[ MAX_PATH ]; TCHAR szText[ SMALL_BUFFER_SIZE ]; STRENTRY seReg[] = { { "25", "%SystemRoot%" }, // NT-specific { "11", "%SystemRoot%\\system32" }, // NT-specific { "RemoteBoot", szRemoteBootPath }, }; STRTABLE stReg = { ARRAYSIZE(seReg), seReg }; HWND hProg = GetDlgItem( hDlg, IDC_P_METER ); DWORD dw; SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM(0, 1 )); SendMessage( hProg, PBM_SETPOS, 0, 0 ); dw = LoadString( g_hinstance, IDS_UPDATING_REGISTRY, szText, ARRAYSIZE( szText ) ); Assert( dw ); SetWindowText( GetDlgItem( hDlg, IDC_S_OPERATION ), szText ); // fill in substitution variables WideCharToMultiByte( CP_ACP, 0, g_Options.szRemoteBootPath, -1, szRemoteBootPath, ARRAYSIZE( szRemoteBootPath ), NULL, NULL ); hr = THR( RegInstall( g_hinstance, "InstallRemoteBoot", &stReg) ); SendMessage( hProg, PBM_SETPOS, 1 , 0 ); return hr; } // // Creates the services needed for remote boot. // HRESULT StartRemoteBootServices( HWND hDlg ) { TCHAR szTFTPD[ SMALL_BUFFER_SIZE ]; TCHAR szBINL[ SMALL_BUFFER_SIZE ]; TCHAR szTFTPDName[ SMALL_BUFFER_SIZE ]; TCHAR szBINLName[ SMALL_BUFFER_SIZE ]; TCHAR szText[ SMALL_BUFFER_SIZE ]; SC_HANDLE schSystem; SC_HANDLE schTFTPD; SC_HANDLE schTCPService; DWORD dwErr = S_OK; HWND hProg = GetDlgItem( hDlg, IDC_P_METER ); DWORD dw; SendMessage( hProg, PBM_SETRANGE, 0, MAKELPARAM(0, 1 )); SendMessage( hProg, PBM_SETPOS, 0, 0 ); dw = LoadString( g_hinstance, IDS_STARTING_SERVICES, szText, ARRAYSIZE( szText ) ); Assert( dw ); SetDlgItemText( hDlg, IDC_S_OPERATION, szText ); dw = LoadString( g_hinstance, IDS_TFTPD, szTFTPD, ARRAYSIZE( szTFTPD ) ); Assert( dw ); dw = LoadString( g_hinstance, IDS_BINL, szBINL, ARRAYSIZE( szBINL ) ); Assert( dw ); dw = LoadString( g_hinstance, IDS_TFTPD_SERVICENAME, szTFTPDName, ARRAYSIZE( szTFTPDName ) ); Assert( dw ); dw = LoadString( g_hinstance, IDS_BINL_SERVICENAME, szBINLName, ARRAYSIZE( szBINLName ) ); Assert( dw ); schSystem = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); Assert( schSystem ); if ( !schSystem ) goto Cleanup; schTFTPD = OpenService( schSystem, szTFTPD, STANDARD_RIGHTS_REQUIRED | SERVICE_START ); schTCPService = OpenService( schSystem, szBINL, STANDARD_RIGHTS_REQUIRED | SERVICE_START ); // start TFTPD if ( !StartService( schTFTPD, 0, NULL ) ) { dwErr = GetLastError( ); switch ( dwErr ) { default: dw = LoadString( g_hinstance, IDS_ERROR_STARTING_SERVICE, szText, ARRAYSIZE( szText ) ); Assert( dw ); MessageBox( hDlg, szText, szTFTPDName, MB_OK ); break; case ERROR_SERVICE_ALREADY_RUNNING: break; } } // start TCP services dw = LoadString( g_hinstance, IDS_STARTING_SERVICES, szText, ARRAYSIZE( szText ) ); Assert( dw ); SetDlgItemText( hDlg, IDC_S_OPERATION, szText ); if ( !StartService( schTCPService, 0, NULL ) ) { dwErr = GetLastError( ); switch ( dwErr ) { default: dw = LoadString( g_hinstance, IDS_ERROR_STARTING_SERVICE, szText, ARRAYSIZE( szText ) ); Assert( dw ); MessageBox( hDlg, szText, szBINLName, MB_OK ); break; case ERROR_SERVICE_ALREADY_RUNNING: break; } } SendMessage( hProg, PBM_SETPOS, 1 , 0 ); Cleanup: if ( schTCPService ) CloseServiceHandle( schTCPService ); if ( schTFTPD ) CloseServiceHandle( schTFTPD ); if ( schSystem ) CloseServiceHandle( schSystem ); return dwErr; } // // create RemoteBoot share // HRESULT CreateRemoteBootShare( HWND hDlg ) { SHARE_INFO_502 si502; TCHAR szRemark[ SMALL_BUFFER_SIZE ]; TCHAR szRemoteBoot[ SMALL_BUFFER_SIZE ]; TCHAR szText[ SMALL_BUFFER_SIZE ]; DWORD dwErr; HWND hProg = GetDlgItem( hDlg, IDC_P_METER ); DWORD dw; dw = LoadString( g_hinstance, IDS_CREATINGSHARES, szText, ARRAYSIZE( szText ) ); Assert( dw ); SetDlgItemText( hDlg, IDC_S_OPERATION, szText ); dw = LoadString( g_hinstance, IDS_REMOTEBOOTSHAREREMARK, szRemark, ARRAYSIZE( szRemark ) ); Assert( dw ); dw = LoadString( g_hinstance, IDS_REMOTEBOOTSHARENAME, szRemoteBoot, ARRAYSIZE( szRemoteBoot ) ); Assert( dw ); si502.shi502_netname = szRemoteBoot; si502.shi502_type = STYPE_DISKTREE; si502.shi502_remark = szRemark; si502.shi502_permissions = ACCESS_ALL; si502.shi502_max_uses = -1; // unlimited si502.shi502_current_uses = 0; si502.shi502_path = g_Options.szRemoteBootPath; si502.shi502_passwd = NULL; // ignored si502.shi502_reserved = 0; // must be zero si502.shi502_security_descriptor = NULL; NetShareAdd( NULL, 502, (LPBYTE) &si502, &dwErr ); switch ( dwErr ) { // ignore these case NERR_Success: case NERR_DuplicateShare: break; default: MessageBoxFromStrings( hDlg, IDS_SHAREERRORCAPTION, IDS_SHAREERRORTEXT, MB_OK ); } SendMessage( hProg, PBM_DELTAPOS, 1 , 0 ); return dwErr; }