bool FVSAccessorModule::OpenVisualStudioFileAtLineInternal(const FString& FullPath, int32 LineNumber, int32 ColumnNumber) { // Check that the file actually exists first if (!FPaths::FileExists(FullPath)) { OpenFileFailed.Broadcast(FullPath); return false; } // Initialize the com library, if not already by this thread if (!FWindowsPlatformMisc::CoInitialize()) { UE_LOG(LogVSAccessor, Error, TEXT( "ERROR - Could not initialize COM library!" )); return false; } bool bDefer = false, bSuccess = false; CComPtr<EnvDTE::_DTE> DTE; if (AccessVisualStudio(DTE, SolutionPath, Locations)) { // Set Focus on Visual Studio CComPtr<EnvDTE::Window> MainWindow; if (SUCCEEDED(DTE->get_MainWindow(&MainWindow)) && SUCCEEDED(MainWindow->Activate())) { // Get ItemOperations CComPtr<EnvDTE::ItemOperations> ItemOperations; if (SUCCEEDED(DTE->get_ItemOperations(&ItemOperations))) { // Open File auto ANSIPath = StringCast<ANSICHAR>(*FullPath); CComBSTR COMStrFileName(ANSIPath.Get()); CComBSTR COMStrKind(EnvDTE::vsViewKindTextView); CComPtr<EnvDTE::Window> Window; if (SUCCEEDED(ItemOperations->OpenFile(COMStrFileName, COMStrKind, &Window))) { // Scroll to Line Number CComPtr<EnvDTE::Document> Document; CComPtr<IDispatch> SelectionDispatch; CComPtr<EnvDTE::TextSelection> Selection; if (SUCCEEDED(DTE->get_ActiveDocument(&Document)) && SUCCEEDED(Document->get_Selection(&SelectionDispatch)) && SUCCEEDED(SelectionDispatch->QueryInterface(&Selection)) && SUCCEEDED(Selection->GotoLine(LineNumber, true))) { if (ColumnNumber > 0 && SUCCEEDED(Selection->MoveToLineAndOffset(LineNumber, ColumnNumber, false))) { bSuccess = true; } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't goto column number '%i' of line '%i' in '%s'"), ColumnNumber, LineNumber, *FullPath); } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't goto line number '%i' in '%s'"), LineNumber, *FullPath); } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't open file '%s'."), *FullPath); } VSLaunchFinished( true ); } else { UE_LOG(LogVSAccessor, Log, TEXT("Couldn't get item operations. Visual Studio may still be initializing."), *FullPath); bDefer = true; } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't set focus on Visual Studio.")); } } else { bDefer = true; // We can't process until we're in the main thread, if we aren't initially defer until we are if ( IsInGameThread() ) { // If we haven't already attempted to launch VS do so now if (!IsVSLaunchInProgress()) { // If there's no valid instance of VS running, run one if we have it installed if ( !RunVisualStudioAndOpenSolution() ) { bDefer = false; } else { VSLaunchStarted(); } } } } // If we have attempted to launch VS, and it's taken too long, timeout so the user can try again if ( IsVSLaunchInProgress() && ( FPlatformTime::Seconds() - VSLaunchTime ) > 300 ) { // We need todo this incase the process died or was kill prior to the code gaining focus of it bDefer = false; VSLaunchFinished( false ); // We failed to open the solution and file, so lets just use the platforms default opener. FPlatformProcess::LaunchFileInDefaultExternalApplication( *FullPath ); } // Defer the request until VS is available to take hold of if ( bDefer ) { const FString DeferCommand = FString::Printf( TEXT( "OPEN_VS %s %d %d" ), *FullPath, LineNumber, ColumnNumber); LaunchVSDeferred.Broadcast( DeferCommand ); } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't access Visual Studio")); } // Uninitialize the com library, if we initialized it above (don't call if S_FALSE) FWindowsPlatformMisc::CoUninitialize(); return bSuccess; }
bool FVisualStudioSourceCodeAccessor::OpenVisualStudioFilesInternalViaDTE(const TArray<FileOpenRequest>& Requests, bool& bWasDeferred) { ISourceCodeAccessModule& SourceCodeAccessModule = FModuleManager::LoadModuleChecked<ISourceCodeAccessModule>(TEXT("SourceCodeAccess")); // Initialize the com library, if not already by this thread if (!FWindowsPlatformMisc::CoInitialize()) { UE_LOG(LogVSAccessor, Error, TEXT( "ERROR - Could not initialize COM library!" )); return false; } bool bDefer = false, bSuccess = false; TComPtr<EnvDTE::_DTE> DTE; const FString SolutionPath = GetSolutionPath(); switch (AccessVisualStudioViaDTE(DTE, SolutionPath, GetPrioritizedVisualStudioVersions(SolutionPath))) { case EAccessVisualStudioResult::VSInstanceIsOpen: { // Set Focus on Visual Studio TComPtr<EnvDTE::Window> MainWindow; if (SUCCEEDED(DTE->get_MainWindow(&MainWindow)) && SUCCEEDED(MainWindow->Activate())) { // Get ItemOperations TComPtr<EnvDTE::ItemOperations> ItemOperations; if (SUCCEEDED(DTE->get_ItemOperations(&ItemOperations))) { for ( const FileOpenRequest& Request : Requests ) { // Check that the file actually exists first if ( !FPaths::FileExists(Request.FullPath) ) { SourceCodeAccessModule.OnOpenFileFailed().Broadcast(Request.FullPath); bSuccess |= false; continue; } // Open File auto ANSIPath = StringCast<ANSICHAR>(*Request.FullPath); FComBSTR COMStrFileName(ANSIPath.Get()); FComBSTR COMStrKind(EnvDTE::vsViewKindTextView); TComPtr<EnvDTE::Window> Window; if ( SUCCEEDED(ItemOperations->OpenFile(COMStrFileName, COMStrKind, &Window)) ) { // If we've made it this far - we've opened the file. it doesn't matter if // we successfully get to the line number. Everything else is gravy. bSuccess |= true; // Scroll to Line Number TComPtr<EnvDTE::Document> Document; TComPtr<IDispatch> SelectionDispatch; TComPtr<EnvDTE::TextSelection> Selection; if ( SUCCEEDED(DTE->get_ActiveDocument(&Document)) && SUCCEEDED(Document->get_Selection(&SelectionDispatch)) && SelectionDispatch && SUCCEEDED(SelectionDispatch->QueryInterface(&Selection)) && SUCCEEDED(Selection->GotoLine(Request.LineNumber, VARIANT_TRUE)) ) { if ( !SUCCEEDED(Selection->MoveToLineAndOffset(Request.LineNumber, Request.ColumnNumber, false)) ) { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't goto column number '%i' of line '%i' in '%s'"), Request.ColumnNumber, Request.LineNumber, *Request.FullPath); } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't goto line number '%i' in '%s'"), Request.LineNumber, *Request.FullPath); } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't open file '%s'."), *Request.FullPath); } } VSLaunchFinished( true ); } else { UE_LOG(LogVSAccessor, Log, TEXT("Couldn't get item operations. Visual Studio may still be initializing.")); bDefer = true; } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't set focus on Visual Studio.")); } } break; case EAccessVisualStudioResult::VSInstanceIsNotOpen: { bDefer = true; // We can't process until we're in the main thread, if we aren't initially defer until we are if ( IsInGameThread() ) { // If we haven't already attempted to launch VS do so now if ( !IsVSLaunchInProgress() ) { // If there's no valid instance of VS running, run one if we have it installed if ( !RunVisualStudioAndOpenSolution() ) { bDefer = false; } else { VSLaunchStarted(); } } } } break; case EAccessVisualStudioResult::VSInstanceIsBlocked: { // VS may be open for the solution we want, but we can't query it right now as it's blocked for some reason // Defer this operation so we can try it again later should VS become unblocked bDefer = true; } break; default: // Do nothing if we failed the VS detection, otherwise we could get stuck in a loop of constantly // trying to open a VS instance since we can't detect that one is already running bDefer = false; break; } if ( !bSuccess ) { // If we have attempted to launch VS, and it's taken too long, timeout so the user can try again if ( IsVSLaunchInProgress() && ( FPlatformTime::Seconds() - VSLaunchTime ) > 300 ) { // We need todo this in case the process died or was kill prior to the code gaining focus of it bDefer = false; VSLaunchFinished(false); // We failed to open the solution and file, so lets just use the platforms default opener. for ( const FileOpenRequest& Request : Requests ) { FPlatformProcess::LaunchFileInDefaultExternalApplication(*Request.FullPath); } } // Defer the request until VS is available to take hold of if ( bDefer ) { FScopeLock Lock(&DeferredRequestsCriticalSection); DeferredRequests.Append(Requests); } else if ( !bSuccess ) { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't access Visual Studio")); } } // Uninitialize the com library, if we initialized it above (don't call if S_FALSE) FWindowsPlatformMisc::CoUninitialize(); bWasDeferred = bDefer; return bSuccess; }