public static void HandleDebugKeys(this SpectrumGenericToolWindowViewModel vm, KeyEventArgs args)
        {
            if (!vm.VmPaused)
            {
                return;
            }

            if (args.Key == Key.F5 && Keyboard.Modifiers == ModifierKeys.None)
            {
                // --- Run
                vm.MachineViewModel.StartDebugVm();
                args.Handled = true;
            }
            else if (args.Key == Key.F11 && Keyboard.Modifiers == ModifierKeys.None)
            {
                // --- Step into
                vm.MachineViewModel.StepInto();
                args.Handled = true;
            }
            else if (args.Key == Key.System && args.SystemKey == Key.F10 && Keyboard.Modifiers == ModifierKeys.None)
            {
                // --- Step over
                vm.MachineViewModel.StepOver();
                args.Handled = true;
            }
            if (args.Handled)
            {
                SpectNetPackage.UpdateCommandUi();
            }
        }
 /// <summary>
 /// Gets the hierarchy information for the selected item.
 /// </summary>
 /// <param name="hierarchy">Hierarchy object</param>
 /// <param name="itemId">Hierarchy item id</param>
 /// <remarks>
 /// If the selected item is the project, it retrieves the hierarchy information for the
 /// default code file
 /// </remarks>
 public void GetCodeItem(out IVsHierarchy hierarchy, out uint itemId)
 {
     SpectNetPackage.IsSingleItemSelection(AllowProjectItem, out hierarchy, out itemId);
     if (itemId == VSConstants.VSITEMID_ROOT)
     {
         // --- We have a project item, let's query the default code file
         var currentProject = Package.CodeDiscoverySolution.CurrentProject;
         currentProject.GetHierarchyByIdentity(currentProject.DefaultZ80CodeItem.Identity,
                                               out hierarchy, out itemId);
     }
 }
        /// <summary>
        /// Override this method to execute the command
        /// </summary>
        protected override void OnExecute()
        {
            var cancel = IsCancelled = false;

            PrepareCommandOnMainThread(ref cancel);
            if (cancel)
            {
                IsCancelled = true;
                return;
            }
            JoinableTaskFactory.RunAsync(async() =>
            {
                try
                {
                    await Task.Yield(); // get off the caller's callstack.
                    await ExecuteAsync();
                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                    CompleteOnMainThread();
                }
                catch (OperationCanceledException)
                {
                    // --- This exception is expected because we signaled the cancellation token
                    IsCancelled = true;
                    OnCancellation();
                }
                catch (AggregateException ex)
                {
                    // --- ignore AggregateException containing only OperationCanceledExceptionI
                    if (ex.InnerException is OperationCanceledException)
                    {
                        IsCancelled = true;
                        OnCancellation();
                    }
                    else
                    {
                        OnException(ex);
                    }
                }
                catch (Exception ex)
                {
                    var x = 1;
                }
                finally
                {
                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                    await FinallyOnMainThreadAsync();
                    if (UpdateUiWhenComplete)
                    {
                        SpectNetPackage.UpdateCommandUi();
                    }
                }
            });
        }
        /// <summary>
        /// Checks if the active project has changed
        /// </summary>
        /// <param name="oldActiveProject">The file name of the old active project</param>
        private void CheckActiveProjectChange(string oldActiveProject)
        {
            _lastCollectedActiveProject = ActiveProject?.Root?.FileName;
            if (oldActiveProject == _lastCollectedActiveProject) return;

            var oldProject = Projects.FirstOrDefault(p => p.Root.FileName == oldActiveProject);
            var newProject = Projects.FirstOrDefault(p => p.Root.FileName == _lastCollectedActiveProject);
            ActiveProjectChanged?.Invoke(this, 
                new ActiveProjectChangedEventArgs(oldProject, newProject));
            if (newProject == null) return;

            SpectNetPackage.Log($"New active project: {newProject.Root.FileName}");
        }
        /// <summary>
        /// Override this method to prepare assembler options
        /// </summary>
        /// <returns>Options to use with the assembler</returns>
        protected virtual AssemblerOptions PrepareOptions()
        {
            var options = new AssemblerOptions
            {
                CurrentModel = SpectNetPackage.GetCurrentSpectrumModelType()
            };
            var runOptions = SpectNetPackage.Default.Options.RunSymbols;

            if (runOptions != null)
            {
                var symbols = runOptions.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var symbol in symbols)
                {
                    if (!options.PredefinedSymbols.Contains(symbol))
                    {
                        options.PredefinedSymbols.Add(symbol);
                    }
                }
            }
            return(options);
        }
        /// <summary>
        /// Compiles the program code
        /// </summary>
        /// <returns>True, if compilation successful; otherwise, false</returns>
        public async Task <bool> CompileCode()
        {
            var start = DateTime.Now;

            SpectNetPackage.Log(_compiler.ServiceName);
            var output = await _compiler.CompileDocument(_itemFullPath, PrepareAssemblerOptions());

            var duration = (DateTime.Now - start).TotalMilliseconds;

            SpectNetPackage.Log($"Compile time: {duration}ms");
            var compiled = output != null;

            if (compiled)
            {
                // --- Sign that compilation was successful
                HostPackage.DebugInfoProvider.CompiledOutput = Output = output;
                CreateCompilationListFile(_hierarchy, _itemId);
            }
            HostPackage.CodeManager.RaiseCompilationCompleted(output);
            return(compiled);
        }
        /// <summary>
        /// Processes the command text
        /// </summary>
        /// <param name="commandText">The command text</param>
        /// <param name="validationMessage">
        ///     Null, if the command is valid; otherwise the validation message to show
        /// </param>
        /// <param name="topAddress">
        /// Non-null value indicates that the view should be scrolled to that address
        /// </param>
        /// <returns>
        /// True, if the command has been handled; otherwise, false
        /// </returns>
        public bool ProcessCommandline(string commandText, out string validationMessage,
                                       out ushort?topAddress)
        {
            const string INV_S48_COMMAND = "This command cannot be used for a Spectrum 48K model.";
            const string INV_RUN_COMMAND = "This command can only be used when the virtual machine is running.";

            // --- Prepare command handling
            validationMessage = null;
            topAddress        = null;
            var isSpectrum48 = SpectNetPackage.IsSpectrum48Model();
            var banks        = MachineViewModel.SpectrumVm.MemoryConfiguration.RamBanks;
            var roms         = MachineViewModel.SpectrumVm.RomConfiguration.NumberOfRoms;

            var parser = new MemoryCommandParser(commandText);

            switch (parser.Command)
            {
            case MemoryCommandType.Invalid:
                validationMessage = "Invalid command syntax";
                return(false);

            case MemoryCommandType.Goto:
                topAddress = parser.Address;
                break;

            case MemoryCommandType.GotoSymbol:
                if (CompilerOutput == null)
                {
                    validationMessage = "No compilation has been done, symbols cannot be used with the 'G' command";
                    return(false);
                }

                if (!CompilerOutput.Symbols.TryGetValue(parser.Arg1, out var symbolValue))
                {
                    validationMessage = $"Cannot find symbol '{parser.Arg1}'";
                    return(false);
                }
                topAddress = symbolValue;
                break;

            case MemoryCommandType.SetRomPage:
                if (isSpectrum48)
                {
                    validationMessage = INV_S48_COMMAND;
                    return(false);
                }
                if (parser.Address > roms - 1)
                {
                    validationMessage = $"This machine does not have a ROM bank #{parser.Address}";
                    return(false);
                }
                SetRomViewMode(parser.Address);
                topAddress = 0;
                break;

            case MemoryCommandType.SetRamBank:
                if (isSpectrum48)
                {
                    validationMessage = INV_S48_COMMAND;
                    return(false);
                }
                if (VmStopped)
                {
                    validationMessage = INV_RUN_COMMAND;
                    return(false);
                }
                if (parser.Address > banks - 1)
                {
                    validationMessage = $"This machine does not have a RAM bank #{parser.Address}";
                    return(false);
                }
                SetRamBankViewMode(parser.Address);
                topAddress = 0;
                break;

            case MemoryCommandType.MemoryMode:
                if (isSpectrum48)
                {
                    validationMessage = INV_S48_COMMAND;
                    return(false);
                }
                if (VmStopped)
                {
                    validationMessage = INV_RUN_COMMAND;
                    return(false);
                }
                SetFullViewMode();
                break;

            default:
                return(false);
            }
            return(true);
        }
Exemple #8
0
        /// <summary>
        /// Processes the command text
        /// </summary>
        /// <param name="commandText">The command text</param>
        /// <param name="validationMessage">
        ///     Null, if the command is valid; otherwise the validation message to show
        /// </param>
        /// <param name="topAddress">
        /// Non-null value indicates that the view should be scrolled to that address
        /// </param>
        /// <returns>
        /// True, if the command has been handled; otherwise, false
        /// </returns>
        public bool ProcessCommandline(string commandText, out string validationMessage,
                                       out ushort?topAddress)
        {
            // --- Prepare command handling
            validationMessage = null;
            topAddress        = null;
            var isSpectrum48 = SpectNetPackage.IsSpectrum48Model();
            var banks        = SpectrumVm.MemoryConfiguration.RamBanks;
            var roms         = SpectrumVm.RomConfiguration.NumberOfRoms;

            var command = ParseCommand(commandText);

            if (command is CompactToolCommand compactCommand)
            {
                command = ParseCommand(compactCommand.CommandText);
            }
            if (command == null || command.HasSemanticError)
            {
                validationMessage = INV_SYNTAX;
                return(false);
            }

            switch (command)
            {
            case GotoToolCommand gotoCommand:
                if (gotoCommand.Symbol != null)
                {
                    if (ResolveSymbol(gotoCommand.Symbol, out var symbolValue))
                    {
                        topAddress = symbolValue;
                        break;
                    }

                    validationMessage = string.Format(UNDEF_SYMBOL, gotoCommand.Symbol);
                    return(false);
                }
                topAddress = gotoCommand.Address;
                break;

            case RomPageToolCommand romPageCommand:
                if (isSpectrum48)
                {
                    validationMessage = INV_S48_COMMAND;
                    return(false);
                }
                if (romPageCommand.Page > roms - 1)
                {
                    validationMessage = $"This machine does not have a ROM bank #{romPageCommand.Page}";
                    return(false);
                }
                SetRomViewMode(romPageCommand.Page);
                topAddress = 0;
                break;

            case BankPageToolCommand bankPageCommand:
                if (isSpectrum48)
                {
                    validationMessage = INV_S48_COMMAND;
                    return(false);
                }
                if (MachineState == VmState.Stopped)
                {
                    validationMessage = INV_RUN_COMMAND;
                    return(false);
                }
                if (bankPageCommand.Page > banks - 1)
                {
                    validationMessage = $"This machine does not have a RAM bank #{bankPageCommand.Page}";
                    return(false);
                }
                SetRamBankViewMode(bankPageCommand.Page);
                topAddress = 0;
                break;

            case MemoryModeToolCommand _:
                if (isSpectrum48)
                {
                    validationMessage = INV_S48_COMMAND;
                    return(false);
                }
                if (MachineState == VmState.Stopped)
                {
                    validationMessage = INV_RUN_COMMAND;
                    return(false);
                }
                SetFullViewMode();
                break;

            case ExportToolCommand exportMemoryCommand:
            {
                if (!ObtainAddress(exportMemoryCommand.From, null,
                                   out var startAddress,
                                   out validationMessage))
                {
                    return(false);
                }
                if (!ObtainAddress(exportMemoryCommand.To, null,
                                   out var endAddress,
                                   out validationMessage))
                {
                    return(false);
                }

                if (DisplayExportMemoryDialog(out var vm, startAddress, endAddress))
                {
                    // --- Export cancelled
                    break;
                }

                var exporter = new MemoryExporter(vm);
                exporter.ExportMemory(EmulatorViewModel.Machine.SpectrumVm);
                ExportMemoryViewModel.LatestFolder = Path.GetDirectoryName(vm.Filename);
                break;
            }

            default:
                validationMessage = string.Format(INV_CONTEXT, "ZX Spectrum Memory window");
                return(false);
            }
            return(true);
        }
Exemple #9
0
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to compile/run
            GetCodeItem(out var hierarchy, out var itemId);

            // --- Step #1: Compile the code
            if (!CompileCode(hierarchy, itemId))
            {
                return;
            }

            // --- Step #2: Check machine compatibility
            var modelName = SpectNetPackage.Default.CodeDiscoverySolution?.CurrentProject?.ModelName;
            SpectrumModelType modelType;

            if (Output.ModelType == null)
            {
                switch (modelName)
                {
                case SpectrumModels.ZX_SPECTRUM_48:
                    modelType = SpectrumModelType.Spectrum48;
                    break;

                case SpectrumModels.ZX_SPECTRUM_128:
                    modelType = SpectrumModelType.Spectrum128;
                    break;

                case SpectrumModels.ZX_SPECTRUM_P3_E:
                    modelType = SpectrumModelType.SpectrumP3;
                    break;

                case SpectrumModels.ZX_SPECTRUM_NEXT:
                    modelType = SpectrumModelType.Next;
                    break;

                default:
                    modelType = SpectrumModelType.Spectrum48;
                    break;
                }
            }
            else
            {
                modelType = Output.ModelType.Value;
            }
            if (!SpectNetPackage.IsCurrentModelCompatibleWith(modelType))
            {
                VsxDialogs.Show("The model type defined in the code is not compatible with the " +
                                "Spectum virtual machine of this project.",
                                "Cannot run code.");
                return;
            }

            // --- Step #3: Check for zero code length
            if (Output.Segments.Sum(s => s.EmittedCode.Count) == 0)
            {
                VsxDialogs.Show("The lenght of the compiled code is 0, " +
                                "so there is no code to inject into the virtual machine and run.",
                                "No code to run.");
                return;
            }

            // --- Step #4: Check non-zero displacements
            var options = Package.Options;

            if (Output.Segments.Any(s => (s.Displacement ?? 0) != 0) && options.ConfirmNonZeroDisplacement)
            {
                var answer = VsxDialogs.Show("The compiled code contains non-zero displacement" +
                                             "value, so the displaced code may fail. Are you sure you want to run the code?",
                                             "Non-zero displacement found",
                                             MessageBoxButton.YesNo, VsxMessageBoxIcon.Question, 1);
                if (answer == VsxDialogResult.No)
                {
                    return;
                }
            }

            // --- Step #5: Stop the virtual machine if required
            await SwitchToMainThreadAsync();

            Package.ShowToolWindow <SpectrumEmulatorToolWindow>();
            var pane    = OutputWindow.GetPane <SpectrumVmOutputPane>();
            var vm      = Package.MachineViewModel;
            var stopped = await Package.CodeManager.StopSpectrumVm(options.ConfirmMachineRestart);

            if (!stopped)
            {
                return;
            }

            // --- Step #6: Start the virtual machine so that later we can load the program
            pane.WriteLine("Starting the virtual machine in code injection mode.");

            // --- Use specific startup for each model.
            bool started = true;

            try
            {
                switch (modelName)
                {
                case SpectrumModels.ZX_SPECTRUM_48:
                    await Package.StateFileManager.SetSpectrum48StartupState();

                    break;

                case SpectrumModels.ZX_SPECTRUM_128:
                    if (modelType == SpectrumModelType.Spectrum48)
                    {
                        await Package.StateFileManager.SetSpectrum128In48StartupState();
                    }
                    else
                    {
                        await Package.StateFileManager.SetSpectrum128In128StartupState();
                    }
                    break;

                case SpectrumModels.ZX_SPECTRUM_P3_E:
                    if (modelType == SpectrumModelType.Spectrum48)
                    {
                        await Package.StateFileManager.SetSpectrumP3In48StartupState();
                    }
                    else
                    {
                        await Package.StateFileManager.SetSpectrumP3InP3StartupState();
                    }
                    break;

                case SpectrumModels.ZX_SPECTRUM_NEXT:
                    // --- Implement later
                    return;

                default:
                    // --- Implement later
                    return;
                }
            }
            catch (Exception)
            {
                started = false;
            }
            if (!started)
            {
                return;
            }

            // --- Step #7: Inject the code into the memory, and force
            // --- new disassembly
            pane.WriteLine("Injecting code into the Spectrum virtual machine.");
            Package.CodeManager.InjectCodeIntoVm(Output);

            // --- Step #8: Jump to execute the code
            var continuationPoint = GetContinuationAddress();

            if (continuationPoint.HasValue)
            {
                vm.SpectrumVm.Cpu.Registers.PC = continuationPoint.Value;
                pane.WriteLine($"Resuming code execution at address {vm.SpectrumVm.Cpu.Registers.PC:X4}.");
            }
            ResumeVm();
        }
 /// <summary>
 /// Updates the command UI whenever the selected item has changed.
 /// </summary>
 private void OnSelectedItemChanged(object sender, EventArgs e)
 {
     SpectNetPackage.UpdateCommandUi();
 }
 /// <summary>
 /// Respond to changes in any test file's contents
 /// </summary>
 private void OnTestFileChanged(object sender, FileChangedEventArgs e)
 {
     Caption = BaseCaption + "*";
     Vm.HasAnyTestFileChanged = true;
     SpectNetPackage.UpdateCommandUi();
 }
Exemple #12
0
 /// <summary>
 /// Obtains the current state of the virtual machine
 /// </summary>
 /// <param name="package">Package instance</param>
 /// <returns>Virtual machine state</returns>
 public static VmState GetVmState(SpectNetPackage package)
 => package.MachineViewModel?.MachineState ?? VmState.None;
 /// <summary>
 /// Initializes the provider
 /// </summary>
 public VsIntegratedTapeProvider()
 {
     _package = SpectNetPackage.Default;
 }
        /// <summary>
        /// Compiles the Z80 code file
        /// </summary>
        protected override async Task ExecuteAsync()
        {
            // --- Prepare the appropriate file to compile/run
            GetCodeItem(out var hierarchy, out var itemId);

            // --- Step #1: Compile the code
            if (!CompileCode(hierarchy, itemId))
            {
                return;
            }

            // --- Step #2: Check machine compatibility
            var modelName = SpectNetPackage.Default.CodeDiscoverySolution?.CurrentProject?.ModelName;
            SpectrumModelType modelType;

            if (Output.ModelType == null)
            {
                switch (modelName)
                {
                case SpectrumModels.ZX_SPECTRUM_48:
                    modelType = SpectrumModelType.Spectrum48;
                    break;

                case SpectrumModels.ZX_SPECTRUM_128:
                    modelType = SpectrumModelType.Spectrum128;
                    break;

                case SpectrumModels.ZX_SPECTRUM_P3:
                    modelType = SpectrumModelType.SpectrumP3;
                    break;

                case SpectrumModels.ZX_SPECTRUM_NEXT:
                    modelType = SpectrumModelType.Next;
                    break;

                default:
                    modelType = SpectrumModelType.Spectrum48;
                    break;
                }
            }
            else
            {
                modelType = Output.ModelType.Value;
            }
            if (!SpectNetPackage.IsCurrentModelCompatibleWith(modelType))
            {
                VsxDialogs.Show("The model type defined in the code is not compatible with the " +
                                "Spectum virtual machine of this project.",
                                "Cannot run code.");
                return;
            }

            // --- Step #3: Check for zero code length
            if (Output.Segments.Sum(s => s.EmittedCode.Count) == 0)
            {
                VsxDialogs.Show("The lenght of the compiled code is 0, " +
                                "so there is no code to inject into the virtual machine and run.",
                                "No code to run.");
                return;
            }

            // --- Step #4: Check non-zero displacements
            var options = Package.Options;

            if (Output.Segments.Any(s => (s.Displacement ?? 0) != 0) && options.ConfirmNonZeroDisplacement)
            {
                var answer = VsxDialogs.Show("The compiled code contains non-zero displacement" +
                                             "value, so the displaced code may fail. Are you sure you want to run the code?",
                                             "Non-zero displacement found",
                                             MessageBoxButton.YesNo, VsxMessageBoxIcon.Question, 1);
                if (answer == VsxDialogResult.No)
                {
                    return;
                }
            }

            // --- Step #5: Stop the virtual machine if required
            await SwitchToMainThreadAsync();

            Package.ShowToolWindow <SpectrumEmulatorToolWindow>();
            var pane         = OutputWindow.GetPane <SpectrumVmOutputPane>();
            var vm           = Package.MachineViewModel;
            var machineState = vm.VmState;

            if ((machineState == VmState.Running || machineState == VmState.Paused))
            {
                if (options.ConfirmMachineRestart)
                {
                    var answer = VsxDialogs.Show("Are you sure, you want to restart " +
                                                 "the ZX Spectrum virtual machine?",
                                                 "The ZX Spectum virtual machine is running",
                                                 MessageBoxButton.YesNo, VsxMessageBoxIcon.Question, 1);
                    if (answer == VsxDialogResult.No)
                    {
                        return;
                    }
                }

                // --- Stop the machine and allow 50ms to stop.
                Package.MachineViewModel.StopVm();
                await Task.Delay(50);

                if (vm.VmState != VmState.Stopped)
                {
                    const string MESSAGE = "The ZX Spectrum virtual machine did not stop.";
                    pane.WriteLine(MESSAGE);
                    VsxDialogs.Show(MESSAGE, "Unexpected issue",
                                    MessageBoxButton.OK, VsxMessageBoxIcon.Error);
                    return;
                }
            }

            // --- Step #6: Start the virtual machine so that later we can load the program
            pane.WriteLine("Starting the virtual machine in code injection mode.");

            // --- Use specific startup for each model.
            switch (modelName)
            {
            case SpectrumModels.ZX_SPECTRUM_48:
                // --- Run in ZX Spectrum 48K mode
                vm.RestartVmAndRunToTerminationPoint(0, SP48_MAIN_EXEC_ADDR);
                if (!await WaitStart())
                {
                    return;
                }
                break;

            case SpectrumModels.ZX_SPECTRUM_128:
                // --- Wait while the main menu appears
                vm.RestartVmAndRunToTerminationPoint(0, SP128_MAIN_WAITING_LOOP);
                if (!await WaitStart())
                {
                    return;
                }

                if (modelType == SpectrumModelType.Spectrum48)
                {
                    vm.RunVmToTerminationPoint(1, SP48_MAIN_EXEC_ADDR);

                    // --- Move to Spectrum 48 mode
                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.Enter);
                    if (!await WaitStart())
                    {
                        return;
                    }
                }
                else
                {
                    vm.RunVmToTerminationPoint(0, SP128_RETURN_TO_EDITOR);
                    // --- Move to Spectrum 128 mode
                    QueueKeyStroke(SpectrumKeyCode.N6, SpectrumKeyCode.CShift);
                    await Task.Delay(WAIT_FOR_MENU_KEY);

                    QueueKeyStroke(SpectrumKeyCode.Enter);
                    if (!await WaitStart())
                    {
                        return;
                    }
                }
                break;

            case SpectrumModels.ZX_SPECTRUM_P3:
                // --- Implement later
                return;

            case SpectrumModels.ZX_SPECTRUM_NEXT:
                // --- Implement later
                return;

            default:
                // --- Implement later
                return;
            }

            // --- Step #7: Inject the code into the memory, and force
            // --- new disassembly
            pane.WriteLine("Injecting code into the Spectrum virtual machine.");
            Package.CodeManager.InjectCodeIntoVm(Output);

            // --- Step #8: Jump to execute the code
            var continuationPoint = GetContinuationAddress();

            if (continuationPoint.HasValue)
            {
                vm.SpectrumVm.Cpu.Registers.PC = continuationPoint.Value;
                pane.WriteLine($"Resuming code execution at address {vm.SpectrumVm.Cpu.Registers.PC:X4}.");
            }
            ResumeVm();
        }
 /// <summary>
 /// Gets the hierarchy information for the selected item.
 /// </summary>
 /// <param name="hierarchy">Hierarchy object</param>
 /// <param name="itemId">Hierarchy item id</param>
 /// <remarks>
 /// If the selected item is the project, it retrieves the hierarchy information for the
 /// default code file
 /// </remarks>
 public void GetCodeItem(out IVsHierarchy hierarchy, out uint itemId)
 {
     SpectNetPackage.IsSingleItemSelection(AllowProjectItem, out hierarchy, out itemId);
 }