Copy embedded structure to clipboard and retrieve it in win32 - winapi

I am trying to implement clipboard operation (cut/copy/paste) on my win32 window. This window has a bunch of gdi objects drawn over it, and the window can have child controls inserted in it as well.
I have searched allot on the win32 clipboard API, and every where they have explained how to handle a single type of data, e.g. we can write text onto clipboard by specifying the appropriate clipboard format and etc.
What I need is to place ALL the data on the clipboard that will be used to reconstruct the original window after the paste operation. I do not want to use COM as suggested by msdn for embedded data structures.
Can this be carried out using the basic clipboard API? Can anybody point me in the right direction and what steps do I need to take to bring this about? I am a newbie in win32 and don't know allot about what I am doing.

Use RegisterClipboardFormat() to register a custom clipboard format ID. Then serialize your data as needed, using whatever serialization format is meaningful for your data, and store it on the clipboard using SetClipboardData(). At a later time, you can use GetCliipboardData() to retrieve your data and de-serialize it as needed.
Update: For example:
struct sMyData
{
int Value1;
int Value2;
float Value3;
float Value4;
};
UINT uMyDataFmtID = RegisterClipboardFormat(TEXT("MyData"));
...
HANDLE hMyData = GlobalAlloc(GHND, sizeof(sMyData));
sMyData *pMyData = (sMyData*) GlobalLock(hMyData);
// fill in pMyData as needed...
GlobalUnlock(hMyData);
SetClipboardData(uMyDataFmtID, hMyData);
...
HANDLE hMyData = GetClipboardData(uMyDataFmtID);
sMyData *pMyData = (sMyData*) GlobalLock(hMyData);
// use pMyData as needed...
GlobalUnlock(hMyData);

Related

How to force Explorer use modern file operation dialog with Shell Namespace Extension

In my understanding currently there are two ways to copy virtual files from a Shell Namespace Extension with the Explorer so that Copy GUI will be shown to the user:
Via IDataObject interface:
Reading a file is done via IDataObject::GetData that should support CFSTR_FILEDESCRIPTORW, CFSTR_FILECONTENTS and CFSTR_SHELLIDLIST clipboard formats at very minimum. Requesting CFSTR_FILECONTENTS from IDataObject::GetData should create an IStream that is used to access the data. UI is enabled via setting FD_PROGRESSUI flag when CFSTR_FILEDESCRIPTORW is requested.
Via ITransferSource interface:
Reading a file is done via ITransferSource::OpenItem requesting for IShellItemResources. Then IShellItemResources should report {4F74D1CF-680C-4EA3-8020-4BDA6792DA3C} resource as supported (GUID indicating that there is an IStream for the item). Finally an IStream is requested via parent ShellFolder::BindToObject for accessing the data. UI is handled by the Explorer itself, it is always shown.
My problem is: these two mechanisms are working just fine separately (as you can see from the screenshots). But once I enable both IDataObject from IShellFolder::GetUIObjectOf and ITransferSource from IShellFolder::CreateViewObject - the approach via IDataObject is always used leading to the old copy GUI (as on the first screenshot). I see from the trace logs that ITransferSource is requested several times, but no actions are performed, it just gets Released and destroyed right away.
So how may I force Explorer to show fancy copy GUI when copying from my Shell Namespace Extension?
A minimal reproducible example may be found here: https://github.com/BilyakA/SO_73938149
While working on Minimal Reproducible example I somehow managed to make it work as expected with both IDataObject and ITranfserSource interfaces enabled. It happened after:
unregistred x64 build SNE example (regsvr32 /u)
registred x32 build SNE example (it was not working in x64 explorer, root was not opening)
unregistred x32
registred x64 again.
Somehow new copy UI was shown to me when copying the files.
But I was not able to reproduce this result constantly after I have unregistred x64 SNE, restarted explorer and registered SNE x64 again.
What I have tried:
Registred both x32 and x64 SNE - still old GUI
Removed Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Cached value with my NSE GUID and restarted Explorer afterwards. Still old GUI.
I suspect there is some kind of cache (other than Registry) that keeps track if NSE supports ITransferSource. And since I have developed and tested without ITransferSource at the beginning - it is cached that my NSE does not support it even that I have added it later. And somehow registering 32bit reset that cache value.
The current code is doing something like this when asked for an IDataObject:
HRESULT CFolderViewImplFolder::GetUIObjectOf(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT rgfReserved, void **ppv)
{
....
if (riid == IID_IDataObject)
{
CDataObject* dataObject = new (std::nothrow) CDataObject(this, cidl, apidl);
return ::SHCreateDataObject(m_pidl, cidl, apidl, dataObject, riid, ppv);
}
...
}
SHCreateDataObject already creates already a full-blown IDataObject with everything needed from the (optional) input PIDL(s), including all Shell formats for items in the Shell namespace (CFSTR_SHELLIDLIST, etc.).
Passing an inner object 1) will probably conflict with what the Shell does and 2) requires a good implementation (I've not checked it).
So you can just replace it like this:
HRESULT CFolderViewImplFolder::GetUIObjectOf(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT rgfReserved, void **ppv)
{
....
if (riid == IID_IDataObject)
{
return ::SHCreateDataObject(m_pidl, cidl, apidl, NULL, riid, ppv);
}
...
}
In fact, the IDataObject provided by the Shell is complete (supports SetData method, etc.) so you should never need to implement it yourself, it's more complex than it seems. You can reuse it as a general purpose IDataObject (you can pass nulls and 0 for the 4 first arguments).
PS: the Shell also provides the "reverse" method: SHCreateShellItemArrayFromDataObject that gets a list of Shell items from an IDataObject (if the data object contains the expected clipboard formats).
For those who need to use inner IDataObject within SHCreateDataObject for additional format:
Inner IDataObject should support CFSTR_SHELLIDLIST clipboard format in GetData() as well as report this format in EnumFormatEtc(). Supporting SetData() with CFSTR_SHELLIDLIST format is really useful here since DefDataObject sets inner data object with already fully constructed CIDA and you may just store a copy of it.
Once inner data object will report CFSTR_SHELLIDLIST in EnumFormatEtc() and return valid CIDA in GetData() - modern Copy UI will be used since it relies only on PIDL of the items.

Save image (via ImageWriter / FileImageOutputStream) to the filesystem without use of a File object

As a learning task I am converting my software I use every day to NIO, with the somewhat arbitrary objective of having zero remaining instances of java.io.File.
I have been successful in every case except one. It seems an ImageWriter can only write to a FileImageOutputStream which requires a java.io.File.
Path path = Paths.get(inputFileName);
InputStream is = Files.newInputStream(path, StandardOpenOption.READ);
BufferedImage bi = ImageIO.read(is);
...
Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("jpg");
ImageWriter writer = iter.next();
ImageWriteParam param = writer.getDefaultWriteParam();
File outputFile = new File(outputFileName);
ImageOutputStream ios = new FileImageOutputStream(outputFile);
IIOImage iioi = new IIOImage(bi, null, null);
writer.setOutput(ios);
writer.write(null, iioi, param);
...
Is there a way to do this with a java.nio.file.Path? The java 8 api doc for ImageWriter only mentions FileImageOutputStream.
I understand there might only be a symbolic value to doing this, but I was under the impression that NIO is intended to provide a complete alternative to java.io.File.
A RandomAccessFile, constructed with just a String for a filename, can be supplied to the ImageOutputStream constructor constructor.
This doesn't "use NIO" any more than just using the File in the first place, but it doesn't require File to be used directly..
For direct support of Path (or to "use NIO"), the FileImageOutputStream (or RandomAccessFile) could be extended, or a type deriving from the ImageOutputStream interface created, but .. how much work is it worth?
The intended way to instantiate an ImageInputStream or ImageOutputStream in the javax.imageio API, is through the ImageIO.createImageInputStream() and ImageIO.createImageOutputStream() methods.
You will see that both these methods take Object as its parameter. Internally, ImageIO will use a service lookup mechanism, and delegate the creation to a provider able to create a stream based on the parameter. By default, there are providers for File, RandomAccessFile and InputStream.
But the mechanism is extendable. See the API doc for the javax.imageio.spi package for a starting point. If you like, you can create a provider that takes a java.nio.Path and creates a FileImageOutputStream based on it, or alternatively create your own implementation using some more fancy NIO backing (ie. SeekableByteChannel).
Here's source code for a sample provider and stream I created to read images from a byte array, that you could use as a starting point.
(Of course, I have to agree with #user2864740's thoughts on the cost/benefit of doing this, but as you are doing this for the sake of learning, it might make sense.)

How to get the IPreviewHandler for a file extension?

How do i get the shell IPreviewHandler for a particular file extension?
Background
Windows allows developers to create a preview handler for their custom file types:
Preview handlers are called when an item is selected to show a lightweight, rich, read-only preview of the file's contents in the view's reading pane. This is done without launching the file's associated application.
A preview handler is a hosted application. Hosts include the Windows Explorer in Windows Vista or Microsoft Outlook 2007.
I want to leverage the existing IPreviewHandler infrasturcture to get a thumbnail for a file.
In A Stream
The problem is that my files are not housed in the shell namespace (i.e. they are not sitting on the hard drive). They are sitting in memory, accessable through an IStream. This means i cannot use the legacy IExtractImage interface; as it does not support loading a file from a Stream.
Fortunately, this is why the modern IPreviewHandler supports (recommends, and prefers) loading data from a Stream, and recommends against loading previews from a file:
This method is preferred to Initialize due to its ability to use streams that are not accessible through a Win32 path, such as the contents of a compressed file with a .zip file name extension.
So how do i get it?
There is no documentation on the correct way to get ahold of the IPreviewHandler associated with a particular extension. But if i take the directions of how to register an IPreviewHandler, and read the contract from the other side:
HKEY_CLASSES_ROOT
.xyz
(Default) = xyzfile
HKEY_CLASSES_ROOT
xyzfile
shellex
{8895b1c6-b41f-4c1c-a562-0d564250836f} //IPreviewHandler subkey
(Default) = [clsid of the IPreviewHandler]
I should be able to follow the same route, given that i know the extension. Lets follow that with a real world example, a .jpg file:
Notice that the file has a preview. Notice i included the second screenshot only to reinforce the idea that the preview doesn't come from a file sitting on the hard drive.
Lets get spellunking!
First is the fact that it's a .jpg file:
HKEY_CLASSES_ROOT
.jpg
(Default) = ACDC_JPG
HKEY_CLASSES_ROOT
ACDC_JPG
ShellEx
{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
ContextMenuHandlers
Wait, there is no {8895b1c6-b41f-4c1c-a562-0d564250836f} subkey for a previewhandler. That must mean that we cannot get a thumbnail for .jpg files.
reducto an absurdum
The Real Question
The careful reader will realize that the actual question i'm asking is:
How do i get the preview of an image contained only in a stream?
And while that is a useful question, and the real issue i'm having, having an answer on how to use IPreviewHandler is also a useful question.
So feel free to answer either; or both!
Bonus Reading
MSDN: Preview Handlers and Shell Preview Host
MSDN: How to Register a Preview Handler
MSDN: IInitializeWithStream::Initialize method
IPreviewHandler throws uncatchable exception
Outlook IPreviewHandler for Delphi
#hvd had the right answer.
File types have a ShellEx key, with {guid} subkeys. Each {guid} key represents a particular InterfaceID.
There are a number of standard shell interfaces that can be associated with a file type:
{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1} IExtractImage
{953BB1EE-93B4-11d1-98A3-00C04FB687DA} IExtractImage2
{e357fccd-a995-4576-b01f-234630154e96} IThumbnailProvider
{8895b1c6-b41f-4c1c-a562-0d564250836f} IPreviewHandler
Unsupported spelunking of undocumented registry keys
If i want to find, for example, the clsid of the IPreviewHandler associated with a .jpg file, i would look in:
HKEY_CLASSES_ROOT/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. I can also look in:
HKEY_CLASSES_ROOT/.jpg
(default) = jpgfile
HKEY_CLASSES_ROOT/jpgfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. I can also look in:
HKEY_CLASSES_ROOT/SystemFileAssociations/.jpg/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. I can also look in:
HKEY_CLASSES_ROOT/SystemFileAssociations/jpegfile/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
But that's not the only place i could look. If i think the file is an image, i can also look in:
HKEY_CLASSES_ROOT/SystemFileAssociations/image/ShellEx/{8895b1c6-b41f-4c1c-a562-0d564250836f}
(default) = [clsid]
How did i find these locations? Did i only follow documented and supported locations? No, i spied on Explorer using Process Monitor as it went hunting for an IThumbnailProvider.
Don't use undocumented spellunking
So now i want to use a standard shell interface for a file-type myself. This means that i have to crawl the locations. But why crawl these locations in an undocumented, unsupported way. Why incur the wrath from the guy from high atop the thing? Use AssocQueryString:
Guid GetShellClsidForFileType(String fileExtension, Guid interfaceID)
{
//E.g.:
// String fileExtension = ".jpg"
// Guid interfaceID = "{8895b1c6-b41f-4c1c-a562-0d564250836f}"; //IExtractImage
//The interface we're after - in string form
String szInterfaceID := GuidToString(interfaceID);
//Buffer to receive the clsid string
DWORD bufferSize := 1024; //more than enough to hold a 38-character clsid
String buffer;
SetLength(buffer, bufferSize);
HRESULT hr := AssocQueryString(
ASSOCF_INIT_DEFAULTTOSTAR,
ASSOCSTR_SHELLEXTENSION, //for finding shell extensions
fileExtension, //e.g. ".txt"
szInterfaceID, //e.g. "{8895b1c6-b41f-4c1c-a562-0d564250836f}"
buffer, //will receive the clsid string
#bufferSize);
if (hr <> S_OK)
return Guid.Empty;
Guid clsid;
HRESULT hr = CLSIDFromString(buffer, out clsid);
if (hr <> NOERROR)
return Guid.Empty;
return clsid;
}
And so to get the clsid of IPreviewHandler for .xps files:
Guid clsid = GetShellClsidForFileType(".xps", IPreviewHandler);
How to get IPreviewHandler for a file extension?
With all the above, we can now answer the question:
IPreviewHandler GetPreviewHandlerForFileType(String extension)
{
//Extension: the file type to return IPreviewHandler for (e.g. ".xps")
Guid previewHandlerClassID = GetShellClsidForFileType(extension, IPreviewHandler);
//Create the COM object
IUnknown unk = CreateComObject(previewHandlerClassID);
//Return the actual IPreviewHanler interface (not IUnknown)
return (IPreviewhandler)unk;
}

how to find out the FileType of an audio-file?

i'm using Core-Audio/AudioToolbox (Extended Audio File services) to read audio files on OSX.
for my specific application, i need to find out, whether the file i opened successfully using ExtAudioFileOpenURL() is a CAF-file.
unfortunately i seem to miss how to do this properly, as i cannot retrieve the AudioFileTypeID from an ExtAudioFileRef.
(when writing such a file, i can define the type by passing the AudioFileTypeID to ExtAudioFileCreateWithURL; what about the reverse?
like with my other question, it turned out that i have to use the normal AudioAPI (rather than ExtAudio API)
static bool isCAF(const AudioFileID*file) {
/* trying to read format (is it caf?) */
UInt32 format=0;
UInt32 formatSize=sizeof(format);
AudioFileGetProperty (*file, kAudioFilePropertyFileFormat, &formatSize, &format);
return (kAudioFileCAFType==format);
}

Can anyone help me out to load values in string table vc++ mfc programatically

Can anyone help me to load values in a STRINGTABLE in vc++ programmatically? I'm using the MFC.
You can load strings directly from a string table using the LoadString method, I use it all the time.
http://msdn.microsoft.com/en-us/library/ms647486(v=vs.85).aspx
CStringW myString;
myString.LoadString(RESOURCE_ID); //where RESOURCE_ID is the Stringtable
//entry ID
*EDIT: Thanks for the input this makes the answer much better!!
You can have a custom resource where you would put a text file. At runtime, read that text file as resource.
void GetResourceAsString(int nResourceID, CStringA &strResourceString)
{
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(nResourceID), L"DATA");
HGLOBAL hResHandle = LoadResource(NULL, hResource);
// Resource is ANSII
const char* lpData = static_cast<char*> ( LockResource(hResHandle) );
strResourceString.SetString(lpData, SizeofResource(NULL, hResource));
FreeResource(hResource);
}
Where DATA would be your custom resource type, and nResource would be resource-id under DATA resource type. Of course, you can choose another other name rather than "DATA".
Normally you define for each string a constant that gets included in your program as well as in the resource-file. The string resource is then placed in the .rsrc-section of your executable and strings can be retrieved with LoadString() by naming the defined constant for that string.
Maybe you instead want to iterate through all the string-resources of your executable at run-time? You can do that by reading your process-memory at the appropriate entry in the PE-struct. You can find the string-table entry in the PE-struct if you tahttp://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx under "Resource Directory Table" or have a look into the winapi include-files which define the PE-structs.
It's hard to know what you're really asking for, but I'm going to try an answer. This assumes you're asking how to put the strings into resources, rather than how to read an existing resource.
The .rc file containing the resources can contain #include directives. All you have to do is write out a text file containing the strings you want to include, along with the STRINGTABLE, BEGIN, and END directives along with the ID of each string. You should also create a .h file that defines each of the IDs and include that in the .rc too.

Resources