Пример #1
0
bool FWmfMediaPlayer::Open( const FString& Url )
{
	if (Url.IsEmpty())
	{
		return false;
	}

	TComPtr<IMFSourceResolver> SourceResolver;

	if (FAILED(::MFCreateSourceResolver(&SourceResolver)))
	{
		return false;
	}

	// resolve the media source from the given URL
	MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
	TComPtr<IUnknown> SourceObject;

	if (FAILED(SourceResolver->CreateObjectFromURL(*Url, MF_RESOLUTION_MEDIASOURCE, NULL, &ObjectType, &SourceObject)))
	{
		UE_LOG(LogWmfMedia, Error, TEXT("Failed to create source object from URL for %s"), *Url);

		return false;
	}

	return InitializeMediaSession(SourceObject, Url);
}
Пример #2
0
bool FWmfMediaPlayer::Open( const TSharedRef<TArray<uint8>>& Buffer, const FString& OriginalUrl )
{
	if ((Buffer->Num() == 0) || OriginalUrl.IsEmpty())
	{
		return false;
	}

	TComPtr<IMFSourceResolver> SourceResolver;
	
	if (FAILED(::MFCreateSourceResolver(&SourceResolver)))
	{
		return false;
	}

	// create the media source from the given buffer
	TComPtr<FWmfMediaByteStream> ByteStream = new FWmfMediaByteStream(Buffer);
	MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
	TComPtr<IUnknown> SourceObject;
	
	if (FAILED(SourceResolver->CreateObjectFromByteStream(ByteStream, *OriginalUrl, MF_RESOLUTION_MEDIASOURCE, NULL, &ObjectType, &SourceObject)))
	{
		UE_LOG(LogWmfMedia, Error, TEXT("Failed to create source object from buffer for %s"), *OriginalUrl);

		return false;
	}

	return InitializeMediaSession(SourceObject, OriginalUrl);
}
bool FVisualStudioSourceCodeAccessor::OpenVisualStudioSolutionViaDTE()
{
	// 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 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()))
			{
				bSuccess = true;
			}
			else
			{
				UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't set focus on Visual Studio."));
			}
		}
		break;

	case EAccessVisualStudioResult::VSInstanceIsNotOpen:
		{
			// Automatically fail if there's already an attempt in progress
			if (!IsVSLaunchInProgress())
			{
				bSuccess = RunVisualStudioAndOpenSolution();
			}
		}
		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
		break;
	}

	// Uninitialize the com library, if we initialized it above (don't call if S_FALSE)
	FWindowsPlatformMisc::CoUninitialize();

	return bSuccess;
}
void FWindowsTextInputMethodSystem::Terminate()
{
	HRESULT Result;

	// Get source from thread manager, needed to uninstall profile processor related sinks.
	TComPtr<ITfSource> TSFSource;
	Result = TSFSource.FromQueryInterface(IID_ITfSource, TSFThreadManager);
	if(FAILED(Result) || !TSFSource)
	{
		UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Terminating failed while acquiring the TSF source from the TSF thread manager."));
	}

	if(TSFSource && TSFActivationProxy)
	{
		// Uninstall language notification sink.
		if(TSFActivationProxy->TSFLanguageCookie != TF_INVALID_COOKIE)
		{
			Result = TSFSource->UnadviseSink(TSFActivationProxy->TSFLanguageCookie);
			if(FAILED(Result))
			{
				UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Terminating failed while unadvising the language notification sink from the TSF source."));
			}
		}

		// Uninstall profile notification sink.
		if(TSFActivationProxy->TSFProfileCookie != TF_INVALID_COOKIE)
		{
			Result = TSFSource->UnadviseSink(TSFActivationProxy->TSFProfileCookie);
			if(FAILED(Result))
			{
				UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Terminating failed while unadvising the profile notification sink from the TSF source."));
			}
		}
	}
	TSFActivationProxy.Reset();

	Result = TSFThreadManager->Deactivate();
	if(FAILED(Result))
	{
		UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Terminating failed while deactivating the TSF thread manager."));
	}

	TSFThreadManager.Reset();

	::ImmDestroyContext(IMMContextId);
}
bool FVisualStudioSourceCodeAccessor::SaveAllOpenDocuments() const
{
	bool bSuccess = 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 bSuccess;
	}
	
	TComPtr<EnvDTE::_DTE> DTE;
	const FString SolutionPath = GetSolutionPath();
	if (AccessVisualStudioViaDTE(DTE, SolutionPath, GetPrioritizedVisualStudioVersions(SolutionPath)) == EAccessVisualStudioResult::VSInstanceIsOpen)
	{
		// Save all documents
		TComPtr<EnvDTE::Documents> Documents;
		if (SUCCEEDED(DTE->get_Documents(&Documents)) &&
			SUCCEEDED(Documents->SaveAll()))
		{
			bSuccess = true;
		}
		else
		{
			UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't save all documents"));
		}
	}
	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 FWindowsTextInputMethodSystem::InitializeTSF()
{
	UE_LOG(LogWindowsTextInputMethodSystem, Verbose, TEXT("Initializing TSF..."));

	HRESULT Result = S_OK;

	// Input Processors
	{
		// Get input processor profiles.
		ITfInputProcessorProfiles* RawPointerTSFInputProcessorProfiles;
		Result = ::CoCreateInstance(CLSID_TF_InputProcessorProfiles, nullptr, CLSCTX_INPROC_SERVER, IID_ITfInputProcessorProfiles, reinterpret_cast<void**>(&(RawPointerTSFInputProcessorProfiles)));
		if(FAILED(Result))
		{
			UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Initialzation failed while creating the TSF input processor profiles."));
			return false;
		}
		TSFInputProcessorProfiles.Attach(RawPointerTSFInputProcessorProfiles);

		// Get input processor profile manager from profiles.
		Result = TSFInputProcessorProfileManager.FromQueryInterface(IID_ITfInputProcessorProfileMgr, TSFInputProcessorProfiles);
		if(FAILED(Result))
		{
			UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Initialzation failed while acquiring the TSF input processor profile manager."));
			TSFInputProcessorProfiles.Reset();
			return false;
		}
	}

	// Thread Manager
	{
		// Create thread manager.
		ITfThreadMgr* RawPointerTSFThreadManager;
		Result = ::CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, reinterpret_cast<void**>(&(RawPointerTSFThreadManager)));
		if(FAILED(Result))
		{
			UE_LOG(LogWindowsTextInputMethodSystem, Warning, TEXT("Initialzation failed while creating the TSF thread manager."));
			TSFInputProcessorProfiles.Reset();
			TSFInputProcessorProfileManager.Reset();
			return false;
		}
		TSFThreadManager.Attach(RawPointerTSFThreadManager);

		// Activate thread manager.
		Result = TSFThreadManager->Activate(&(TSFClientId));
		if(FAILED(Result))
		{
			UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Initialzation failed while activating the TSF thread manager."));
			TSFInputProcessorProfiles.Reset();
			TSFInputProcessorProfileManager.Reset();
			TSFThreadManager.Reset();
			return false;
		}

		// Get source from thread manager, needed to install profile processor related sinks.
		TComPtr<ITfSource> TSFSource;
		Result = TSFSource.FromQueryInterface(IID_ITfSource, TSFThreadManager);
		if(FAILED(Result))
		{
			UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Initialzation failed while acquiring the TSF source from TSF thread manager."));
			TSFInputProcessorProfiles.Reset();
			TSFInputProcessorProfileManager.Reset();
			TSFThreadManager.Reset();
			return false;
		}

		TSFActivationProxy = new FTSFActivationProxy(this);

#pragma warning(push)
#pragma warning(disable : 4996) // 'function' was was declared deprecated
		CA_SUPPRESS(28159)
		const DWORD WindowsVersion = ::GetVersion();
#pragma warning(pop)

		const DWORD WindowsMajorVersion = LOBYTE(LOWORD(WindowsVersion));
		const DWORD WindowsMinorVersion = HIBYTE(LOWORD(WindowsVersion));

		static const DWORD WindowsVistaMajorVersion = 6;
		static const DWORD WindowsVistaMinorVersion = 0;

		// Install profile notification sink for versions of Windows Vista and after.
		if(WindowsMajorVersion > WindowsVistaMajorVersion || (WindowsMajorVersion == WindowsVistaMajorVersion && WindowsMinorVersion >= WindowsVistaMinorVersion))
		{
			Result = TSFSource->AdviseSink(IID_ITfInputProcessorProfileActivationSink, static_cast<ITfInputProcessorProfileActivationSink*>(TSFActivationProxy), &(TSFActivationProxy->TSFProfileCookie));
			if(FAILED(Result))
			{
				UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Initialzation failed while advising the profile notification sink to the TSF source."));
				TSFInputProcessorProfiles.Reset();
				TSFInputProcessorProfileManager.Reset();
				TSFThreadManager.Reset();
				TSFActivationProxy.Reset();
				return false;
			}
		}
		// Install language notification sink for versions before Windows Vista.
		else
		{
			Result = TSFSource->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, static_cast<ITfActiveLanguageProfileNotifySink*>(TSFActivationProxy), &(TSFActivationProxy->TSFLanguageCookie));
			if(FAILED(Result))
			{
				UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Initialzation failed while advising the language notification sink to the TSF source."));
				TSFInputProcessorProfiles.Reset();
				TSFInputProcessorProfileManager.Reset();
				TSFThreadManager.Reset();
				TSFActivationProxy.Reset();
				return false;
			}
		}
	}

	// Disabled Document Manager
	Result = TSFThreadManager->CreateDocumentMgr(&(TSFDisabledDocumentManager));
	if(FAILED(Result))
	{
		UE_LOG(LogWindowsTextInputMethodSystem, Warning, TEXT("Initialzation failed while creating the TSF thread manager."));
		TSFInputProcessorProfiles.Reset();
		TSFInputProcessorProfileManager.Reset();
		TSFThreadManager.Reset();
		TSFActivationProxy.Reset();
		return false;
	}

	// Default the focus to the disabled document manager.
	Result = TSFThreadManager->SetFocus(TSFDisabledDocumentManager);
	if(FAILED(Result))
	{
		UE_LOG(LogWindowsTextInputMethodSystem, Error, TEXT("Initialzation failed while activating the TSF thread manager."));
		TSFInputProcessorProfiles.Reset();
		TSFInputProcessorProfileManager.Reset();
		TSFThreadManager.Reset();
		TSFActivationProxy.Reset();
		TSFThreadManager.Reset();
		return false;
	}

	UE_LOG(LogWindowsTextInputMethodSystem, Verbose, TEXT("Initialized TSF!"));

	return true;
}
Пример #7
0
bool FWmfMediaPlayer::InitializeMediaSession( IUnknown* SourceObject, const FString& SourceUrl )
{
	Close();

	if (SourceObject == nullptr)
	{
		return false;
	}

	UE_LOG(LogWmfMedia, Verbose, TEXT("Initializing media session for %s"), *SourceUrl);

	// create presentation descriptor
	TComPtr<IMFMediaSource> MediaSource;

	if (FAILED(SourceObject->QueryInterface(IID_PPV_ARGS(&MediaSource))))
	{
		UE_LOG(LogWmfMedia, Error, TEXT("Failed to query media source"));

		return false;
	}

	TComPtr<IMFPresentationDescriptor> PresentationDescriptor;
	
	if (FAILED(MediaSource->CreatePresentationDescriptor(&PresentationDescriptor)))
	{
		UE_LOG(LogWmfMedia, Error, TEXT("Failed to create presentation descriptor"));

		return false;
	}
	
	// create playback topology
	DWORD StreamCount = 0;

	if (FAILED(PresentationDescriptor->GetStreamDescriptorCount(&StreamCount)))
	{
		UE_LOG(LogWmfMedia, Error, TEXT("Failed to get stream count"));

		return false;
	}

	TComPtr<IMFTopology> Topology;

	if (FAILED(::MFCreateTopology(&Topology)))
	{
		UE_LOG(LogWmfMedia, Error, TEXT("Failed to create playback topology"));

		return false;
	}

	for (uint32 StreamIndex = 0; StreamIndex < StreamCount; ++StreamIndex)
	{
		AddStreamToTopology(StreamIndex, Topology, PresentationDescriptor, MediaSource);
	}

	UE_LOG(LogWmfMedia, Verbose, TEXT("Added a total of %i tracks"), Tracks.Num());

	UINT64 PresentationDuration = 0;
	PresentationDescriptor->GetUINT64(MF_PD_DURATION, &PresentationDuration);
	Duration = FTimespan(PresentationDuration);

	// create session
	MediaSession = new FWmfMediaSession(Duration, Topology);
	MediaUrl = SourceUrl;

	OpenedEvent.Broadcast(SourceUrl);

	return (MediaSession->GetState() != EMediaStates::Error);
}
Пример #8
0
void FWmfMediaPlayer::AddStreamToTopology( uint32 StreamIndex, IMFTopology* Topology, IMFPresentationDescriptor* PresentationDescriptor, IMFMediaSource* MediaSource )
{
	// get stream descriptor
	TComPtr<IMFStreamDescriptor> StreamDescriptor;
	BOOL Selected = FALSE;

	if (FAILED(PresentationDescriptor->GetStreamDescriptorByIndex(StreamIndex, &Selected, &StreamDescriptor)))
	{
		UE_LOG(LogWmfMedia, Warning, TEXT("Skipping missing stream descriptor for stream index %i"), StreamIndex);

		return;
	}

	// fetch media type
	TComPtr<IMFMediaTypeHandler> Handler;

	if (FAILED(StreamDescriptor->GetMediaTypeHandler(&Handler)))
	{
		return;
	}

	GUID MajorType;
		
	if (FAILED(Handler->GetMajorType(&MajorType)))
	{
		return;
	}

	// skip unsupported types
	if ((MajorType != MFMediaType_Audio) &&
		(MajorType != MFMediaType_SAMI) &&
		(MajorType != MFMediaType_Video))
	{
		return;
	}

	// prepare input and output types
	TComPtr<IMFMediaType> OutputType;
	{
		if (FAILED(Handler->GetCurrentMediaType(&OutputType)))
		{
			return;
		}
	}

	TComPtr<IMFMediaType> InputType;
	{
		if (FAILED(::MFCreateMediaType(&InputType)))
		{
			return;
		}

		if (FAILED(InputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE)))
		{
			return;
		}
	}

	if (MajorType == MFMediaType_Audio)
	{
		if (FAILED(InputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)) ||
			FAILED(InputType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)))/* ||
			FAILED(InputType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_BLOCK, 16384u)))*/
		{
			return;
		}
	}
	else if (MajorType == MFMediaType_SAMI)
	{
		if (FAILED(InputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_SAMI)))
		{
			return;
		}
	}
	else if (MajorType == MFMediaType_Video)
	{
		if (FAILED(InputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)) ||
			FAILED(InputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32)))
		{
			return;
		}
	}

	// create sample grabber callback and add to topology
	TComPtr<FWmfMediaSampler> Sampler = new FWmfMediaSampler();
	{
		TComPtr<IMFActivate> MediaSamplerActivator;

		if (FAILED(::MFCreateSampleGrabberSinkActivate(InputType, Sampler, &MediaSamplerActivator)))
		{
			return;
		}

		TComPtr<IMFTopologyNode> SourceNode;
		{
			if (FAILED(::MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &SourceNode)) ||
				FAILED(SourceNode->SetUnknown(MF_TOPONODE_SOURCE, MediaSource)) ||
				FAILED(SourceNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, PresentationDescriptor)) ||
				FAILED(SourceNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, StreamDescriptor)) ||
				FAILED(Topology->AddNode(SourceNode)))
			{
				return;
			}
		}

		TComPtr<IMFTopologyNode> OutputNode;
		{
			if (FAILED(::MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &OutputNode)) ||
				FAILED(OutputNode->SetObject(MediaSamplerActivator)) ||
				FAILED(OutputNode->SetUINT32(MF_TOPONODE_STREAMID, 0)) ||
				FAILED(OutputNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE)) ||
				FAILED(Topology->AddNode(OutputNode)))
			{
				return;
			}
		}

		if (FAILED(SourceNode->ConnectOutput(0, OutputNode, 0)))
		{
			return;
		}
	}

	// create and add track
	if (MajorType == MFMediaType_Audio)
	{
		Tracks.Add(MakeShareable(new FWmfMediaAudioTrack(OutputType, PresentationDescriptor, Sampler, StreamDescriptor, StreamIndex)));
	}
	else if (MajorType == MFMediaType_SAMI)
	{
		Tracks.Add(MakeShareable(new FWmfMediaCaptionTrack(OutputType, PresentationDescriptor, Sampler, StreamDescriptor, StreamIndex)));
	}
	else if (MajorType == MFMediaType_Video)
	{
		Tracks.Add(MakeShareable(new FWmfMediaVideoTrack(OutputType, PresentationDescriptor, Sampler, StreamDescriptor, StreamIndex)));
	}
}
bool FVisualStudioSourceCodeAccessor::AddSourceFiles(const TArray<FString>& AbsoluteSourcePaths, const TArray<FString>& AvailableModules)
{
	// This requires DTE - there is no fallback for this operation when DTE is not available
#if VSACCESSOR_HAS_DTE
	bool bSuccess = true;

	struct FModuleNameAndPath
	{
		FString ModuleBuildFilePath;
		FString ModulePath;
		FName ModuleName;
	};

	TArray<FModuleNameAndPath> ModuleNamesAndPaths;
	ModuleNamesAndPaths.Reserve(AvailableModules.Num());
	for (const FString& AvailableModule : AvailableModules)
	{
		static const int32 BuildFileExtensionLen = FString(TEXT(".Build.cs")).Len();

		// AvailableModule is the relative path to the .Build.cs file
		FModuleNameAndPath ModuleNameAndPath;
		ModuleNameAndPath.ModuleBuildFilePath = FPaths::ConvertRelativePathToFull(AvailableModule);
		ModuleNameAndPath.ModulePath = FPaths::GetPath(ModuleNameAndPath.ModuleBuildFilePath);
		ModuleNameAndPath.ModuleName = *FPaths::GetCleanFilename(ModuleNameAndPath.ModuleBuildFilePath).LeftChop(BuildFileExtensionLen);
		ModuleNamesAndPaths.Add(ModuleNameAndPath);
	}

	struct FModuleNewSourceFiles
	{
		FModuleNameAndPath ModuleNameAndPath;
		TArray<FString> NewSourceFiles;
	};

	// Work out which module each source file will be in
	TMap<FName, FModuleNewSourceFiles> ModuleToNewSourceFiles;
	{
		const FModuleNameAndPath* LastSourceFilesModule = nullptr;
		for (const FString& SourceFile : AbsoluteSourcePaths)
		{
			// First check to see if this source file is in the same module as the last source file - this is usually the case, and saves us a lot of string compares
			if (LastSourceFilesModule && SourceFile.StartsWith(LastSourceFilesModule->ModulePath))
			{
				FModuleNewSourceFiles& ModuleNewSourceFiles = ModuleToNewSourceFiles.FindChecked(LastSourceFilesModule->ModuleName);
				ModuleNewSourceFiles.NewSourceFiles.Add(SourceFile);
				continue;
			}

			// Look for the module which will contain this file
			LastSourceFilesModule = nullptr;
			for (const FModuleNameAndPath& ModuleNameAndPath : ModuleNamesAndPaths)
			{
				if (SourceFile.StartsWith(ModuleNameAndPath.ModulePath))
				{
					LastSourceFilesModule = &ModuleNameAndPath;

					FModuleNewSourceFiles& ModuleNewSourceFiles = ModuleToNewSourceFiles.FindOrAdd(ModuleNameAndPath.ModuleName);
					ModuleNewSourceFiles.ModuleNameAndPath = ModuleNameAndPath;
					ModuleNewSourceFiles.NewSourceFiles.Add(SourceFile);
					break;
				}
			}

			// Failed to find the module for this source file?
			if (!LastSourceFilesModule)
			{
				UE_LOG(LogVSAccessor, Warning, TEXT("Cannot add source file '%s' as it doesn't belong to a known module"), *SourceFile);
				bSuccess = false;
			}
		}
	}

	TComPtr<EnvDTE::_DTE> DTE;
	const FString SolutionPath = GetSolutionPath();
	if (AccessVisualStudioViaDTE(DTE, SolutionPath, GetPrioritizedVisualStudioVersions(SolutionPath)) == EAccessVisualStudioResult::VSInstanceIsOpen)
	{
		TComPtr<EnvDTE::_Solution> Solution;
		if (SUCCEEDED(DTE->get_Solution(&Solution)) && Solution)
		{
			// Process each module
			for (const auto& ModuleNewSourceFilesKeyValue : ModuleToNewSourceFiles)
			{
				const FModuleNewSourceFiles& ModuleNewSourceFiles = ModuleNewSourceFilesKeyValue.Value;

				const FString& ModuleBuildFilePath = ModuleNewSourceFiles.ModuleNameAndPath.ModuleBuildFilePath;
				auto ANSIModuleBuildFilePath = StringCast<ANSICHAR>(*ModuleBuildFilePath);
				FComBSTR COMStrModuleBuildFilePath(ANSIModuleBuildFilePath.Get());

				TComPtr<EnvDTE::ProjectItem> BuildFileProjectItem;
				if (SUCCEEDED(Solution->FindProjectItem(COMStrModuleBuildFilePath, &BuildFileProjectItem)) && BuildFileProjectItem)
				{
					// We found the .Build.cs file in the existing solution - now we need its parent ProjectItems as that's what we'll be adding new content to
					TComPtr<EnvDTE::ProjectItems> ModuleProjectFolder;
					if (SUCCEEDED(BuildFileProjectItem->get_Collection(&ModuleProjectFolder)) && ModuleProjectFolder)
					{
						for (const FString& SourceFile : AbsoluteSourcePaths)
						{
							const FString ProjectRelativeSourceFilePath = SourceFile.Mid(ModuleNewSourceFiles.ModuleNameAndPath.ModulePath.Len());
							TArray<FString> SourceFileParts;
							ProjectRelativeSourceFilePath.ParseIntoArray(SourceFileParts, TEXT("/"), true);
					
							if (SourceFileParts.Num() == 0)
							{
								// This should never happen as it means we somehow have no filename within the project directory
								bSuccess = false;
								continue;
							}

							TComPtr<EnvDTE::ProjectItems> CurProjectItems = ModuleProjectFolder;

							// Firstly we need to make sure that all the folders we need exist - this also walks us down to the correct place to add the file
							for (int32 FilePartIndex = 0; FilePartIndex < SourceFileParts.Num() - 1 && CurProjectItems; ++FilePartIndex)
							{
								const FString& SourceFilePart = SourceFileParts[FilePartIndex];

								auto ANSIPart = StringCast<ANSICHAR>(*SourceFilePart);
								FComBSTR COMStrFilePart(ANSIPart.Get());

								::VARIANT vProjectItemName;
								vProjectItemName.vt = VT_BSTR;
								vProjectItemName.bstrVal = COMStrFilePart;

								TComPtr<EnvDTE::ProjectItem> ProjectItem;
								if (SUCCEEDED(CurProjectItems->Item(vProjectItemName, &ProjectItem)) && !ProjectItem)
								{
									// Add this part
									CurProjectItems->AddFolder(COMStrFilePart, nullptr, &ProjectItem);
								}

								if (ProjectItem)
								{
									ProjectItem->get_ProjectItems(&CurProjectItems);
								}
								else
								{
									CurProjectItems = nullptr;
								}
							}

							if (!CurProjectItems)
							{
								// Failed to find or add all the path parts
								bSuccess = false;
								continue;
							}

							// Now we add the file to the project under the last folder we found along its path
							auto ANSIPath = StringCast<ANSICHAR>(*SourceFile);
							FComBSTR COMStrFileName(ANSIPath.Get());
							TComPtr<EnvDTE::ProjectItem> FileProjectItem;
							if (SUCCEEDED(CurProjectItems->AddFromFile(COMStrFileName, &FileProjectItem)))
							{
								bSuccess &= true;
							}
						}

						// Save the updated project to avoid a message when closing VS
						TComPtr<EnvDTE::Project> Project;
						if (SUCCEEDED(ModuleProjectFolder->get_ContainingProject(&Project)) && Project)
						{
							Project->Save(nullptr);
						}
					}
					else
					{
						UE_LOG(LogVSAccessor, Warning, TEXT("Cannot add source files as we failed to get the parent items container for the '%s' item"), *ModuleBuildFilePath);
						bSuccess = false;
					}
				}
				else
				{
					UE_LOG(LogVSAccessor, Warning, TEXT("Cannot add source files as we failed to find '%s' in the solution"), *ModuleBuildFilePath);
					bSuccess = false;
				}
			}
		}
		else
		{
			UE_LOG(LogVSAccessor, Warning, TEXT("Cannot add source files as Visual Studio failed to return a solution when queried"));
			bSuccess = false;
		}
	}
	else
	{
		UE_LOG(LogVSAccessor, Verbose, TEXT("Cannot add source files as Visual Studio is either not open or not responding"));
		bSuccess = false;
	}

	return bSuccess;
#endif

	return false;
}
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;
}
/** Accesses the correct visual studio instance if possible. */
EAccessVisualStudioResult AccessVisualStudioViaDTE(TComPtr<EnvDTE::_DTE>& OutDTE, const FString& InSolutionPath, const TArray<FVisualStudioSourceCodeAccessor::VisualStudioLocation>& InLocations)
{
	EAccessVisualStudioResult AccessResult = EAccessVisualStudioResult::VSInstanceIsNotOpen;

	// Open the Running Object Table (ROT)
	IRunningObjectTable* RunningObjectTable;
	if(SUCCEEDED(GetRunningObjectTable(0, &RunningObjectTable)) && RunningObjectTable)
	{
		IEnumMoniker* MonikersTable;
		if(SUCCEEDED(RunningObjectTable->EnumRunning(&MonikersTable)))
		{
			MonikersTable->Reset();

			// Look for all visual studio instances in the ROT
			IMoniker* CurrentMoniker;
			while(AccessResult != EAccessVisualStudioResult::VSInstanceIsOpen && MonikersTable->Next(1, &CurrentMoniker, NULL) == S_OK)
			{
				IBindCtx* BindContext;
				LPOLESTR OutName;
				if(SUCCEEDED(CreateBindCtx(0, &BindContext)) && SUCCEEDED(CurrentMoniker->GetDisplayName(BindContext, NULL, &OutName)))
				{
					if(IsVisualStudioDTEMoniker(FString(OutName), InLocations))
					{
						TComPtr<IUnknown> ComObject;
						if(SUCCEEDED(RunningObjectTable->GetObject(CurrentMoniker, &ComObject)))
						{
							TComPtr<EnvDTE::_DTE> TempDTE;
							if (SUCCEEDED(TempDTE.FromQueryInterface(__uuidof(EnvDTE::_DTE), ComObject)))
							{
								// Get the solution path for this instance
								// If it equals the solution we would have opened above in RunVisualStudio(), we'll take that
								TComPtr<EnvDTE::_Solution> Solution;
								BSTR OutPath = nullptr;
								if (SUCCEEDED(TempDTE->get_Solution(&Solution)) &&
									SUCCEEDED(Solution->get_FullName(&OutPath)))
								{
									FString Filename(OutPath);
									FPaths::NormalizeFilename(Filename);

									if (Filename == InSolutionPath)
									{
										OutDTE = TempDTE;
										AccessResult = EAccessVisualStudioResult::VSInstanceIsOpen;
									}

									SysFreeString(OutPath);
								}
								else
								{
									UE_LOG(LogVSAccessor, Warning, TEXT("Visual Studio is open but could not be queried - it may be blocked by a modal operation"));
									AccessResult = EAccessVisualStudioResult::VSInstanceIsBlocked;
								}
							}
							else
							{
								UE_LOG(LogVSAccessor, Warning, TEXT("Could not get DTE interface from returned Visual Studio instance"));
								AccessResult = EAccessVisualStudioResult::VSInstanceIsBlocked;
							}
						}
						else
						{
							UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't get Visual Studio COM object"));
							AccessResult = EAccessVisualStudioResult::VSInstanceUnknown;
						}
					}
				}
				else
				{
					UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't get display name"));
					AccessResult = EAccessVisualStudioResult::VSInstanceUnknown;
				}
				BindContext->Release();
				CurrentMoniker->Release();
			}
			MonikersTable->Release();
		}
		else
		{
			UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't enumerate ROT table"));
			AccessResult = EAccessVisualStudioResult::VSInstanceUnknown;
		}
		RunningObjectTable->Release();
	}
	else
	{
		UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't get ROT table"));
		AccessResult = EAccessVisualStudioResult::VSInstanceUnknown;
	}

	return AccessResult;
}