I was toying with an IRC client, integrating it with the windows 7 app bar.
To get a "Frequent" or "Recent" items list one has to call SHAddToRecentDocs API.
I want to add recent IRC channels visited to the Windows 7 Jumplist for the IRC application.
Now, my problem is, IRC channels don't exist in the file system. And SHAddToRecentDocs seems to insist on getting some sort of file system object.
Ive tried to work around it by creating a IShellItem pointing to my application, and giving it a command line to launch the channel. The shell is rebelling however, and thus far has not visibly added any of my "recent document" attempts to the Jumplist.
Is there no way to do this without creating some kind of entirely unwanted filesystem object?
The code in the answer to question 1671793 goes part of the way. You want an IShellLink instead of an IShellItem. I tried that code bit by bit. Things wouldn't work before using the IPropertyStore to set the title. The IPersistFile code doesn't seem to be necessary.
All of that said, while I now have items appearing when I right-click on my app's taskbar icon, I don't yet have them appearing as a sub-menu of my app on the start menu (as word docs do, for example), so I'm not yet entirely satisfied. I think this is a result of the warning in the docs for SHAddToRecentDocs:
Executable (.exe) files are filtered from the recently used documents list in Windows XP and later versions. Although SHAddToRecentDocs will accept the path of an executable file, that file will not appear in the Recent Items list.
Here's my code as it stands. I'm jumping through some hoops as my development environment is using an older Windows SDK (so I have to create PKEY_Title for myself) and my app needs to support Win2k (so I don't want to bind to functions like InitPropVariantFromString which require newer Windows versions).
HRESULT hr;
IShellLink* link;
// Get a pointer to the IShellLink interface.
hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&link);
if (FAILED(hr))
return;
link->SetPath(path_to_app);
link->SetArguments(L"/some /args");
link->SetDescription(L"A description"); // Turns into tooltip
IPropertyStore* prop_store;
hr = link->QueryInterface(&prop_store);
if(SUCCEEDED(hr))
{
PROPVARIANT pv;
pv.vt=VT_LPWSTR;
pv.pwszVal=L"Name of item"; // Turns into actual item name
PROPERTYKEY PKEY_Title;
CLSIDFromString(L"{F29F85E0-4FF9-1068-AB91-08002B27B3D9}", &(PKEY_Title.fmtid));
PKEY_Title.pid=2;
// Set the title property.
hr = prop_store->SetValue(PKEY_Title, pv); // THIS is where the displayed title is actually set
// Save the changes we made to the property store
prop_store->Commit();
prop_store->Release();
}
SHARDAPPIDINFOLINK appinfo;
appinfo.pszAppID=L"Company.AppName"; // Previously registered using SetCurrentProcessExplicitAppUserModelID
appinfo.psl=link;
SHAddToRecentDocs(SHARD_APPIDINFOLINK, &appinfo);
link->Release();
Related
I am programmatically setting up a cluster resource (specifically, a Generic Service), using the Windows MI API (Microsoft.Management.Infrastructure).
I can add the service resource just fine. However, my service requires the "Use Network Name for computer name" checkbox to be checked (this is available in the Cluster Manager UI by looking at the Properties for the resource).
I can't figure out how to set this using the MI API. I have searched MSDN and multiple other resources for this without luck. Does anybody know if this is possible? Scripting with Powershell would be fine as well.
I was able to figure this out, after a lot of trial and error, and the discovery of an API bug along the way.
It turns out cluster resource objects have a property called PrivateProperties, which is basically a property bag. Inside, there's a property called UseNetworkName, which corresponds to the checkbox in the UI (and also, the ServiceName property, which is also required for things to work).
The 'wbemtest' tool was invaluable in finding this out. Once you open the resource instance in it, you have to double-click the PrivateProperties property to bring up a dialog which has a "View Embedded" button, which is then what shows you the properties inside. Somehow I had missed this before.
Now, setting this property was yet another pain. Due to what looks like a bug in the API, retrieving the resource instance with CimSession.GetInstance() does not populate property values. This misled me into thinking I had to add the PrivateProperties property and its inner properties myself, which only resulted in lots of cryptic errors.
I finally stumbled upon this old MSDN post about it, where I realized the property is dynamic and automatically set by WMI. So, in the end, all you have to do is know how to get the property bag using CimSession.QueryInstances(), so you can then set the inner properties like any other property.
This is what the whole thing looks like (I ommitted the code for adding the resource):
using (var session = CimSession.Create("YOUR_CLUSTER", new DComSessionOptions()))
{
// This query finds the newly created resource and fills in the
// private props we'll change. We have to do a manual WQL query
// because CimSession.GetInstance doesn't populate prop values.
var query =
"SELECT PrivateProperties FROM MSCluster_Resource WHERE Id=\"{YOUR-RES-GUID}\"";
// Lookup the resource. For some reason QueryInstances does not like
// the namespace in the regular form - it must be exactly like this
// for the call to work!
var res = session.QueryInstances(#"root/mscluster", "WQL", query).First();
// Add net name dependency so setting UseNetworkName works.
session.InvokeMethod(
res,
"AddDependency",
new CimMethodParametersCollection
{
CimMethodParameter.Create(
"Resource", "YOUR_NET_NAME_HERE", CimFlags.Parameter)
});
// Get private prop bag and set our props.
var privProps =
(CimInstance)res.CimInstanceProperties["PrivateProperties"].Value;
privProps.CimInstanceProperties["ServiceName"].Value = "YOUR_SVC_HERE";
privProps.CimInstanceProperties["UseNetworkName"].Value = 1;
// Persist the changes.
session.ModifyInstance(#"\root\mscluster", res);
}
Note how the quirks in the API make things more complicated than they should be: QueryInstances expects the namespace in a special way, and also, if you don't add the network name dependency first, setting private properties fails silently.
Finally, I also figured out how to set this through PowerShell. You have to use the Set-ClusterParameter command, see this other answer for the full info.
I am working on developing a debugger plugin for visual studio using VSIX. My problem is I have an array of addresses but I cannot set the IDebugMemoryBytes2 to a particular address. I use DEBUG_PROPERTY_INFO and get the array of addresses, and I also am able to set the context to the particular addresses in the array using the Add function in IDebugMemoryContext2. However, I need to use the ReadAt function to retrieve n bytes from a specified address (from IDebugMemoryBytes2).
Does anyone have any idea how to retrieve data from arbitrary addresses from memory?
I am adding more information on the same:
I am using the Microsoft Visual Studio Extensibility package to build my debugger plugin. In the application I am trying to debug using this plugin, there is a double pointer and I need to read those values to process them further in my plugin. For this, there is no way to display all the pointer variables in the watch window and hence, I am not able to get the DEBUG_PROPERTY_INFO for all the block of arrays which the pointer variable is pointing to. This is my problem which I am trying to address. There is no way for me to read the memory pointed to by this double pointer.
Now as for the events in the debuggee process, since the plugin is for debugging variables, I put a breakpoint at a place where I know this pointer is populated and then come back to the plugin for further evaluation.
As a start, I was somehow able to get the starting addresses of each of the array. But still, I am not able to read x bytes of memory from each of these starting addresses.
ie., for example, if I have int **ptr = // pointing to something
I have the addresses present in ptr[0], ptr[1], ptr[2], etc. But I need to go to each of these addresses and fetch the memory block they are pointing to.
For this, after much search, I found this link: https://macropolygon.wordpress.com/2012/12/16/evaluating-debugged-process-memory-in-a-visual-studio-extension/ which seems to address exactly my issue.
So to use expression evaluator functions, I need an IDebugStackFrame2 object to get the ExpressionContext. To get this object, I need to register to events in the debuggee process which is for breakpoint. As said in the post, I did:
public int Event(IDebugEngine2 engine, IDebugProcess2 process,
IDebugProgram2 program, IDebugThread2 thread, IDebugEvent2
debugEvent, ref Guid riidEvent, uint attributes)
{
if (debugEvent is IDebugBreakpointEvent2)
{
this.thread = thread;
}
return VSConstants.S_OK;
}
And my registration is like:
private void GetCurrentThread()
{
uint cookie;
DBGMODE[] modeArray = new DBGMODE[1];
// Get the Debugger service.
debugService = Package.GetGlobalService(typeof(SVsShellDebugger)) as
IVsDebugger;
if (debugService != null)
{
// Register for debug events.
// Assumes the current class implements IDebugEventCallback2.
debugService.AdviseDebuggerEvents(this, out cookie);
debugService.AdviseDebugEventCallback(this);
debugService.GetMode(modeArray);
modeArray[0] = modeArray[0] & ~DBGMODE.DBGMODE_EncMask;
if (modeArray[0] == DBGMODE.DBGMODE_Break)
{
GetCurrentStackFrame();
}
}
}
But this doesn't seem to invoke the Event function at all and hence, I am not sure how to get the IDebugThread2 object.
I also tried the other way suggested in the same post:
namespace Microsoft.VisualStudio.Debugger.Interop.Internal
{
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("1DA40549-8CCC-48CF-B99B-FC22FE3AFEDF")]
public interface IDebuggerInternal11 {
[DispId(0x6001001f)]
IDebugThread2 CurrentThread { [return:
MarshalAs(UnmanagedType.Interface)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
get; [param: In, MarshalAs(UnmanagedType.Interface)]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)] set; }
}
}
private void GetCurrentThread()
{
debugService = Package.GetGlobalService(typeof(SVsShellDebugger)) as IVsDebugger;
if (debugService != null)
{
IDebuggerInternal11 debuggerServiceInternal =
(IDebuggerInternal11)debugService;
thread = debuggerServiceInternal.CurrentThread;
GetCurrentStackFrame();
}
}
But in this method, I think I am missing something but I am not sure what, because after the execution of the line
IDebuggerInternal11 debuggerServiceInternal =
(IDebuggerInternal11)debugService;
when I check the values of the debuggerServiceInternal variable, I see there is a System.Security.SecurityException for CurrentThread, CurrentStackFrame (and so obviously the next line causes a crash). For this, I googled the error and found I was missing the ComImport attribute to the class. So I added that and now, I get a System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I am new to C# programming as well and hence, it is a bit difficult to grasp many things in short duration. I am lost as to how to proceed further now.
Any help in the same or suggestions to try another way to achieve my objective will be greatly appreciated.
Thanks a lot,
Esash
After much search, since I am short of time, I need a quick solution and hence, for now, it seems like the quickest way to solve this problem is to hack the .natvis files by making it display all the elements of the pointer and then using the same old way by using IDebug* interface methods to access and retrieve the memory context for each of the pointer elements. But, after posting the same question in msdn forums, I think the proper answer to this problem is as mentioned by Greggs:
"For reading memory, if you want a fast way to do this, you just want the raw memory, and the debug engine of the target is the normal Visual Studio native engine (in other words, you aren't creating your own debug engine), I would recommend referencing Microsoft.VisualStudio.Debugger.Engine. You can then use DkmStackFrame.ExtractFromDTEObject to get the DkmStackFrame object. This will give you the DkmProcess object and you can call DkmProcess.ReadMemory to read memory from the target."
Now, after trying a lot to understand how to implement this, I found that you could just accomplish this using :
DkmProcess.GetProcesses() and doing a ReadMemory on the process returned.
There is a question now, what if more than one processes are returned. Well, I tried attaching many processes to the current debugging process and tried attaching many processes to the debuggee process as well, but found that the DkmProcess.GetProcesses() gets only the one from which I regained the control from, and not the other processes I am attached to. I am not sure if this will work in all cases but for me, it worked this way and for anyone who has similar requirements, this might work as well.
Using the .natvis files to accomplish this means, using IndexListItems for VS2013 and prior versions, and using CustomListItems for VS2015 and greater versions, and to make it look prettier, use the "no-derived" attribute. There is no way to make the Synthetic tag display only the base address of each variable and hence, the above attribute is the best way to go about, but this is not available in VS2013 and prior versions (The base address might get displayed but for people who want to go beyond just displaying contents and also access the memory context of the pointer element, Synthetic tag is not the right thing).
I hope this helps some developer who struggled like me using IDebug* interfaces. For reference, I am also giving the link to the msdn forum where my question was answered.
https://social.msdn.microsoft.com/Forums/en-US/030cef1c-ee79-46e9-8e40-bfc59f14cc34/how-can-i-send-a-custom-debug-event-to-my-idebugeventcallback2-handler?forum=vsdebug
Thanks.
I would like to display some info on the screen ... which will disappear.
Example : an Uiview is displayed for the first time to an user (or feature never used by the user). I would like to display on a screen a label or an image to explain how to use this new feature. After that it will disappear ...
If this functionality has already been used by the user, the message is ofcourse not displayed.
example of message --> to add a gamer, press +
How to do that ? a lot of apps have this kind of help.
thanks
What you have to do is actually very simple : have a persistent variable, and change its value. Each time the user could see the help popup, you check the value of the variable you stored persistently. If this variable indicates that the user have already seen the help, you don't display it again. Otherwise, you show it. Simple example:
let helpSeen: Bool = getVarFromPersistent()
if helpSeen == false {
// DISPLAY THE HELP MESSAGE OR POPUP
setHelpSeenVar(true)
}
Where getVarFromPersistent() and setHelpSeenVar() are function you could create to respectively retrieve the variable from the persistent data and set the variable in the persistent data.
Now, you have to figure out how to use persistent data. You can have a look at CoreData, that is provided by Apple and "ready to use" in Xcode. You've probably already seen the use core data tickbox when you create a project.
Third party libraries exists as well like RealmSwift, who reached version 1.0 recently.
I'm not an expert, but I think Realm is simpler to use than Core Data. The technology used by the two libraries could be different though, maybe someone else could tell you more about it. Anyway, you will find a lot of article about Realm and Core Data on Google.
I've been researching how to implement a Namespace Extension.
The NSE should show files and folders (they are physical files and folders, but located elsewhere on the disk).
Also, the NSE must behave as closely as possible to the normal Explorer view, e.g. it must have:
Context menus that would normally appear in a normal Explorer view that are applicable to the file/folder(s) chosen
Drag and drop (both of files/folders and other things like Document Scraps)
'Right Drag and Drop' (e.g. 7Zips 'Extract here...')
Clipboard Copy/Cut/Paste
Share With entries
Any registered Shell Icon Overlay Handlers must work (e.g. Tortoise SVN/GIT)
Column sizing/re-ordering
View customisation, including ordering and grouping
So, basically anything the Explorer view can do so must we.
Looking at all the things that Explorer can do (that I used to take for granted), I felt a bit overwhelmed.
Because I'm both lazy and a realist (I realise it'd be near impossible to replicate all this functionality without issue), my plan is to reuse the functionality of the Explorer view in my NSE.
I've looked at various samples of NSEs. Most of these use virtual data, but as I said, I'm representing physical files and folder elsewhere on the disk. I've also read about the SHCreateShellFolderView method.
Armed with this information, I thought it'd be a relatively simple case of providing a PIDL of my root folder and then in my IShellFolder::CreateViewObject call SHCreateShellFolder method. Here is that method:
STDMETHODIMP CShellFolderImpl::CreateViewObject(
HWND hwndOwner,
REFIID riid,
void** ppvOut )
{
HRESULT hr=E_NOINTERFACE;
if ( NULL == ppvOut )
return E_POINTER;
*ppvOut = NULL;
if (riid == IID_IShellView)
{
SFV_CREATE SfvCreate =
{
sizeof(SFV_CREATE)
};
if (SUCCEEDED(hr = QueryInterface(IID_PPV_ARGS(&SfvCreate.pshf))))
{
hr = ::SHCreateShellFolderView(
&SfvCreate,
reinterpret_cast<IShellView **>(ppvOut));
}
SfvCreate.pshf->Release();
}
else if (riid == IID_ITransferSource)
{
}
return hr;
}
No such luck with that. SHCreateShellFolderView was always returning E_NOTIMPL. Turns out that this is because it requires a pointer to something implementing IShellFolder2 (and IPersist2 for GetCurFolder where I can provide my PIDL). My folder just implemented IShellFolder and IPerist.
So after changing these to implement the newer interfaces, I got... nothing! The NSE would be loaded by Explorer, the constructor would be called, but immediately after, the destructor would be called. If I changed the interfaces back to how they were, it fired up (but still with the same problem).
I've since been looking for a sample that implements IShellFolder2, but again, the documentation is as bad as it is for the rest of these APIs.
How can I use SHCreateShellFolderView so that I don't have to reimplement everything Explorer already does?
Even if you are able to use and embed a Windows Explorer window for your namespace extension, the problem is that you are no longer in control of what it does. For example, if the user double-clicks on a folder, the actual filesystem folder will be browsed, not your namespace extension node which represents the filesystem folder.
Your only option is to do your own implementation. Check out EZNamespaceExtensionsMFC which makes it very easy to develop namespace extensions. It has a "FileSystemBrowser" sample which you can use as a starting point.
DISCLAIMER: I work for LogicNP, the developers of EZNamespaceExtensionsMFC.
I need to retrieve a list of Active Directory users and their attributes using Delphi 2010.
I've seen a few similar questions on SO (e.g. Delphi - Find primary email address for an Active Directory user), but they all seem to require the user name before any additional information can be retrieved.
I had written an article for [The Delphi Magazine] way back when..... if you have access to a backlog of those magazines, it's in issue no. 62 (October 2000) - unfortunately, it seems those back issues aren't available for purchase anymore :-(
It's too long of an article and a code sample to post here.... basically it's about wrapping the IDirectorySearch interface in a nicer Delphi-like shell. You pass in a base container where to search, you define an LDAP filter, and you define a set of attributes you're interested in - then you search and get back basically an enumerator for the results, which you can get one by one.
In the end, I discovered TJvObjectPickerDialog, part of JVCL. It wraps the Windows Select Object dialog and does everything I need with very little coding. Just set the required properties and call execute. The selected user objects are returned along with the attributes that you set in the 'Attributes' property.