I am trying to create a 2017 VS extension with a button command that will display the file path of the current active file. I have followed this https://learn.microsoft.com/en-us/visualstudio/extensibility/extensibility-hello-world?view=vs-2017#prerequisites and have already created the extention but I cannot seem to get the file path of the active file.
if (!IsSingleProjectItemSelection(out hierarchy, out itemid)) return;
// Get the file path
string itemFullPath = null;
((IVsProject) hierarchy).GetMkDocument(itemid, out itemFullPath);
var transformFileInfo = new FileInfo(itemFullPath);
string fullPath = transformFileInfo.FullName;
public static bool IsSingleProjectItemSelection(out IVsHierarchy hierarchy, out uint itemid)
{
hierarchy = null;
itemid = VSConstants.VSITEMID_NIL;
int hr = VSConstants.S_OK;
var monitorSelection = Package.GetGlobalService(typeof(SVsShellMonitorSelection)) as
IVsMonitorSelection;
var solution = Package.GetGlobalService(typeof(SVsSolution)) as IVsSolution;
if (monitorSelection == null || solution == null)
{
return false;
}
IVsMultiItemSelect multiItemSelect = null;
IntPtr hierarchyPtr = IntPtr.Zero;
IntPtr selectionContainerPtr = IntPtr.Zero;
try
{
hr = monitorSelection.GetCurrentSelection(out hierarchyPtr, out itemid, out multiItemSelect, out selectionContainerPtr);
if (ErrorHandler.Failed(hr) || hierarchyPtr == IntPtr.Zero || itemid == VSConstants.VSITEMID_NIL)
{
// there is no selection
return false;
}
// multiple items are selected
if (multiItemSelect != null) return false;
// there is a hierarchy root node selected, thus it is not a single item inside a project
if (itemid == VSConstants.VSITEMID_ROOT) return false;
hierarchy = Marshal.GetObjectForIUnknown(hierarchyPtr) as IVsHierarchy;
if (hierarchy == null) return false;
Guid guidProjectID = Guid.Empty;
if (ErrorHandler.Failed(solution.GetGuidOfProject(hierarchy, out guidProjectID)))
{
return false; // hierarchy is not a project inside the Solution if it does not have a ProjectID Guid
}
// if we got this far then there is a single project item selected
return true;
}
finally
{
if (selectionContainerPtr != IntPtr.Zero)
{
Marshal.Release(selectionContainerPtr);
}
if (hierarchyPtr != IntPtr.Zero)
{
Marshal.Release(hierarchyPtr);
}
}
}
Related
I'm writing a COM add-in for the VBE of access and I want to execute a vba-function out of C# after clicking a commandbar button.
So I use the following code:
const string ApplicationObjectName = "Access.Application";
Microsoft.Office.Interop.Access.Application app = (Microsoft.Office.Interop.Access.Application)Marshal.GetActiveObject(ApplicationObjectName);
app.Run(functionName);
This works fine if there is only one ms-access-db open. But if there are two open databases, ´GetActiveObject´ gets the wrong application and the function is called in the other database. Not in the one the commandbar button is part of.
So, how do I get the correct application object (= the one the button is clicked in)?
At the moment I use the snippet from here (german only):
https://dotnet-snippets.de/snippet/laufende-com-objekte-abfragen/526
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Rainbird.Tools.COMInterop
{
public class RunningObjectTable
{
private RunningObjectTable() { }
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx pctx);
public static object GetRunningCOMObjectByName(string objectDisplayName)
{
IRunningObjectTable runningObjectTable = null;
IEnumMoniker monikerList = null;
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null) return null;
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
IBindCtx bindInfo;
string displayName;
CreateBindCtx(0, out bindInfo);
monikerContainer[0].GetDisplayName(bindInfo, null, out displayName);
Marshal.ReleaseComObject(bindInfo);
if (displayName.IndexOf(objectDisplayName) != -1)
{
object comInstance;
runningObjectTable.GetObject(monikerContainer[0], out comInstance);
return comInstance;
}
}
}
catch
{
return null;
}
finally
{
if (runningObjectTable != null) Marshal.ReleaseComObject(runningObjectTable);
if (monikerList != null) Marshal.ReleaseComObject(monikerList);
}
return null;
}
public static IList<string> GetRunningCOMObjectNames()
{
IList<string> result = new List<string>();
IRunningObjectTable runningObjectTable = null;
IEnumMoniker monikerList = null;
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null) return null;
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
IBindCtx bindInfo;
string displayName;
CreateBindCtx(0, out bindInfo);
monikerContainer[0].GetDisplayName(bindInfo, null, out displayName);
Marshal.ReleaseComObject(bindInfo);
result.Add(displayName);
}
return result;
}
catch
{
return null;
}
finally
{
if (runningObjectTable != null) Marshal.ReleaseComObject(runningObjectTable);
if (monikerList != null) Marshal.ReleaseComObject(monikerList);
}
}
}
}
with this code (works only for ms-access):
var activeProject = m_VBE.ActiveVBProject;
Microsoft.Office.Interop.Access.Application app = (Microsoft.Office.Interop.Access.Application)RunningObjectTable.GetRunningCOMObjectByName(activeProject.FileName);
app.Run(functionName);
But there has to be a better solution to this problem.
Similar issues are also discussed here: How do I get the *actual* host application instance? and here: How to use Marshal.getActiveObject() to get 2 instance of of a running process that has two processes open
I have created a window form application.
This App get the active url of browser and save this into the text file.
And this works fine in chrome & IE.
But when i use firefox, this will not work. This code fails to get the active url of firefox browser.
I don't know why this happening.
I am using the following code to find the URL
public string GetBrowsedUrl()
{
IntPtr hwnd = APIFuncs.getforegroundWindow();
Int32 pid = APIFuncs.GetWindowProcessID(hwnd);
Process process = Process.GetProcessById(pid);
string appId = proc.Id.ToString();
string appName = proc.ProcessName;
string appltitle = APIFuncs.ActiveApplTitle().Trim().Replace("\0", "");
if (process == null)
throw new ArgumentNullException("process");
if (process.MainWindowHandle == IntPtr.Zero)
return null;
AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
if (element == null)
return null;
AutomationElement edit = element.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
string result = ((ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
return result;
}
Finally i found the answer
public string GetBrowsedUrl(Process process)
{
if (process.ProcessName == "firefox")
{
if (process == null)
throw new ArgumentNullException("process");
if (process.MainWindowHandle == IntPtr.Zero)
return null;
AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
if (element == null)
return null;
AutomationElement doc = element.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document));
if (doc == null)
return null;
return ((ValuePattern)doc.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
}
else
{
if (process == null)
throw new ArgumentNullException("process");
if (process.MainWindowHandle == IntPtr.Zero)
return null;
AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
if (element == null)
return null;
AutomationElement edit = element.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
string result = ((ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern)).Current.Value as string;
return result;
}
}
You can not use this code for firefox too.
I recommend a third party library named NDde to do this very easily.
Here is NDde link
public string GetFirefoxUrl()
{
try
{
Process[] pname = Process.GetProcessesByName("Firefox");
if (pname.Length != 0)
{
DdeClient dde = new DdeClient("Firefox", "WWW_GetWindowInfo");
dde.Connect();
string url = dde.Request("URL", int.MaxValue);
url= url.Replace("\"", "").Replace("\0", "");
dde.Disconnect();
return url;
}
else
return null;
}
catch
{
return null;
}
}
What is the Query results window's global service (interface)? Code below:
var dteService = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
if (dteService == null)
{
Debug.WriteLine("");
return;
}
var something=Package.GetGlobalService(typeof(???)) as ???;
EDIT: The goal is, when I press the context menu button, I want the function callback to be able to access the service where the work item is selected (or the results list
Please check this case in MSDN forum for the details how to get it work: https://social.msdn.microsoft.com/Forums/vstudio/en-US/2d158b9c-dec1-4c59-82aa-f1f2312d770b/sdk-packageget-selected-item-from-query-results-list
The following code is quoted from above link for your quick reference:
Document activeDocument = _applicationObject.ActiveDocument;
if (activeDocument != null)
{
DocumentService globalService = (DocumentService)Package.GetGlobalService(typeof(DocumentService));
if (globalService != null)
{
string fullName = activeDocument.FullName;
IWorkItemTrackingDocument document2 = globalService.FindDocument(fullName, null);
if ((document2 != null) && (document2 is IResultsDocument))
{
int[] selectedItemIds = ((IResultsDocument)document2).SelectedItemIds;
}
}
}
var dteService = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
if (dteService == null)
{
Debug.WriteLine("");
return;
}
DocumentService documentService = Package.GetGlobalService(typeof(DocumentService)) as DocumentService;
if (documentService == null)
return;
string fullName = dteService.ActiveDocument.FullName;
IWorkItemTrackingDocument activeDocument = documentService.FindDocument(fullName, null);
if (activeDocument == null || !(activeDocument is IResultsDocument))
return;
I have a problem with scanning with WIA.
public List<Image> Scan(string scannerId)
{
var images = new List<Image>();
var hasMorePages = true;
while (hasMorePages)
{
// select the correct scanner using the provided scannerId parameter
var manager = new DeviceManager();
Device device = null;
foreach (DeviceInfo info in manager.DeviceInfos)
{
if (info.DeviceID == scannerId)
{
// connect to scanner
device = info.Connect();
break;
}
}
// device was not found
if (device == null)
{
// enumerate available devices
string availableDevices = "";
foreach (DeviceInfo info in manager.DeviceInfos)
{
availableDevices += info.DeviceID + "n";
}
// show error with available devices
throw new Exception("The device with provided ID could not be found. Available Devices:n" +
availableDevices);
}
Item item = device.Items[1];
try
{
// scan image
ICommonDialog wiaCommonDialog = new CommonDialog();
var image = (ImageFile) wiaCommonDialog.ShowTransfer(item, WiaFormatBmp, true); // <--- exception goes from there
// save to temp file
string fileName = "test.bmp";//Path.GetTempFileName();
File.Delete(fileName);
image.SaveFile(fileName);
image = null;
// add file to output list
images.Add(Image.FromFile(fileName));
}
catch (Exception exc)
{
throw exc;
}
finally
{
item = null;
//determine if there are any more pages waiting
Property documentHandlingSelect = null;
Property documentHandlingStatus = null;
foreach (Property prop in device.Properties)
{
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_SELECT)
documentHandlingSelect = prop;
if (prop.PropertyID == WIA_PROPERTIES.WIA_DPS_DOCUMENT_HANDLING_STATUS)
documentHandlingStatus = prop;
}
// assume there are no more pages
hasMorePages = false;
// may not exist on flatbed scanner but required for feeder
if (documentHandlingSelect != null)
{
// check for document feeder
if ((Convert.ToUInt32(documentHandlingSelect.get_Value()) && WIA_DPS_DOCUMENT_HANDLING_SELECT.FEEDER) != 0)
{
hasMorePages = ((Convert.ToUInt32(documentHandlingStatus.get_Value()) &&
WIA_DPS_DOCUMENT_HANDLING_STATUS.FEED_READY) != 0);
}
}
}
}
return images;
}
When the scanning is completed i get an exception: "Dynamic operations can only be performed in homogenous AppDomain.". Can someone explain me what im doing wrong? I tried to use it in another Thread but still get the same exception.
Scanner: DSmobile 700D.
I am working on a website. I have to find the value of user can't change password property of a user. I get this link
http://msdn.microsoft.com/en-us/library/aa746448(v=vs.85).aspx[^]
according to which I have to find "ntSecurityDescriptor" value of that user. They are using DirectoryEntry class to find that but in my case I am using LdapConnection class.
If I use entry class I was not able to make connectivity with server So that I change it to LdapConnection class. Now I don't know how to find value.
I find my solution.
SearchResponse response = (SearchResponse)connection.SendRequest(request);
DirectoryAttribute attribute = response.Entries[0].Attributes["ntSecurityDescriptor"];
if (attribute != null)
{
const string PASSWORD_GUID = "{ab721a53-1e2f-11d0-9819-00aa0040529b}";
const int ADS_ACETYPE_ACCESS_DENIED_OBJECT = 6;
bool fEveryone = false;
bool fSelf = false;
ActiveDs.ADsSecurityUtility secUtility = new ActiveDs.ADsSecurityUtility();
ActiveDs.IADsSecurityDescriptor sd = (IADsSecurityDescriptor)secUtility.ConvertSecurityDescriptor((byte[])attribute[0], (int)ADS_SD_FORMAT_ENUM.ADS_SD_FORMAT_RAW, (int)ADS_SD_FORMAT_ENUM.ADS_SD_FORMAT_IID);
ActiveDs.IADsAccessControlList acl = (ActiveDs.IADsAccessControlList)sd.DiscretionaryAcl;
foreach (ActiveDs.IADsAccessControlEntry ace in acl)
{
if ((ace.ObjectType != null) && (ace.ObjectType.ToUpper() == PASSWORD_GUID.ToUpper()))
{
if ((ace.Trustee == "Everyone") && (ace.AceType == ADS_ACETYPE_ACCESS_DENIED_OBJECT))
{
fEveryone = true;
}
if ((ace.Trustee == #"NT AUTHORITY\SELF") && (ace.AceType == ADS_ACETYPE_ACCESS_DENIED_OBJECT))
{
fSelf = true;
}
break;
}
}
if (fEveryone || fSelf)
{
return Global.RequestContants.CANT_CHANGE_PASSWORD;
}
else
{
return string.Empty;
}
}