get file name from IShellItem in IfileOperation.GetDisplayName - shell

I hooked the CopyItems method of IFileOperation to monitor/intercept file copy in windows.
My problem is how can i retrieve the full file name from IShellItem(last param of CopyItems)
function New_CopyItems(p: Pointer; punkItems: IUnknown;psiDestinationFolder: IShellItem): HResult; stdcall;
The psiDestinationFolder have a method called GetDisplayName that return only the folder name of current file was begin copied!! But i want to get full file name and don't know what i should to do !? There is any other method to help me getting full name ?? Or i have to using another API ....?
Excuse me if my English is bad!

The CopyItems method copies potentially multiple items. So right off the bat you are mistaken looking for a single file name. This is a very complex API and you do need to read the documentation carefully and understand clearly how the function works.
The psiDestinationFolder parameter is an IShellItem that identifies the destination. Use the GetDisplayName method to get the file path.
The other parameter, punkItems is more complex. It is documented like this:
Pointer to the IUnknown of the IShellItemArray, IDataObject, or IEnumShellItems object which represents the group of items to be copied. You can also point to an IPersistIDList object to represent a single item, effectively accomplishing the same function as IFileOperation::CopyItem.
This is telling you that there could be an IShellItemArray, IDataObject, IEnumShellItems or a IPersistIDList object behind the IUnknown interface that you receive. And that there could be multiple items in that single object, each one to be copied to the destination folder. You will need to query punkItems for each possible interface in turn until you find out which of these possibilities you have to deal with. And then handle each one with special code. In order to test this you'll need to write code that calls CopyItems with each of the possible interfaces. You'll find out how to do all of this from the documentation of each of the four interfaces. If you don't already know shell programming and COM well, expect to do so by the time you complete this work.
Finally, I doubt that this is a very good way to detect file copying. Files are copied using many different APIs. And IFileOperation.CopyItems is but one of them. If you only hook IFileOperation.CopyItems then you'll miss a lot of file copy operations.

Related

How does URL's resourceValues(forKeys: [.typeIdentifierKey]) determine the UTI?

I've got a URL, and I'm calling resourceValues(forKeys: [.typeIdentifierKey]) on it, to find out the UTIs it conforms to. Works great.
Does this method simply check whether it's a directory (like with stat(2), to report "public.folder"), and if it's not a directory, the filename extension (and if none, then just "public.data", "public.item")?
That seems to be the case, but I can't find any documentation that says for sure how it determines the type.
Rationale: I've got a bunch of URLs whose UTIs I want to check against a known value, and I know they're not folders, so I could save a ton of I/O calls if I were sure that that's all that this method is doing.
UPDATE: I looked in swift-corelibs-foundation/URL.swift, but it just passes through to the NSURL method of the same name. The swift-corelibs-foundation/NSURL.swift method just throws NSUnimplemented(). I tried looking in CFLite, which has an implementation of CFURL, but I can't seem to find anything there related to UTIs. AFAICT, there's no open-source implementation of this method from Apple.

Detect if golang method is internal?

I'm writing a function that iterates over the methods on a given struct and binds the methods to handlers. I would like to skip over internal methods if possible. I'm not sure if this is possible to do so explicitly - I reviewed the documentation for the reflect package and I didn't see a means to detect if a given Value is an internal method. I know I can get the method's name, and then check if it starts with a lowercase character but I'm not sure if there's a kosher way to accomplish this. It's also possible that the internal / public boundary really only exists at compile time anyways, so there really isn't even a way of knowing this beyond the method's name. In either case I'd like to know for sure. Thanks!
The reflect package will not give you unexported methods via Type.Method. Pretty much, if you can see it via reflect, it is already exported.
See https://play.golang.org/p/61qQYO38P0

create vbscript vbdataobject

I am using a program which makes it possible to customize dialogues via vbscript. Now, the form has an attribute which seems to be a vbDataObject (VarType returns 13).
How can I read the content and create a new vbDataObject to assign it to the attribute?
Don't know if this is exactly the answer, but it seems that vbDataObject's are indeed COM objects, but they just do not expose an IDispatch interface (so they're not true automation objects). As such, VBScript just isn't capable of accessing their content, since it needs an IDispatch interface for it. It just has an IUnknown interface which it doesn't know what to do with.
Passing them around should be possible, though, so if another true automation COM object can manipulate them for you (maybe there is such an object in the app designed to do this?), you could use that to make an object with the correct settings and pass that to the form.
Another option is to contact the authors of the app and ask them if they're willing to give this one object an IDispatch interface as well. Since they presumably went the length to put IDispatch interfaces on most of their objects, this omission might just be an oversight on their part.

Which is the most efficient way to access the value of a control?

Of the two choices I have to access the value of a control which is the most efficient?
getComponent("ControlName").getValue();
or
dataSource.getItemValue("FieldName");
I find that on occasion the getComponent does not seem to return the current value, but accessing the dataSource seems to be more reliable. So does it make much difference from a performance perspective which one is used?
The dataSource.getValue seems to work everywhere that I have tried it. However, when working with rowData I still seem to need to do a rowData.getColumnValue("Something"). rowData.getValue("Something") fails.
Neither. The fastest syntax is dataSource.getValue ("FieldName"). The getItemValue method is only reliable on the document data source, whereas the getValue method is not only also available on view entries accessed via a view data source (although in that context you would pass it the programmatic name of a view column, which is not necessarily the same name as a field), but will also be available on any custom data sources that you develop or install (e.g. third-party extension libraries). Furthermore, it does automatic type conversion that you'd have to do yourself if you used getItemValue instead.
Even on very simple pages, dataSource.getValue ("FieldName") is 5 times as fast as getComponent ("id").getValue (), because, as Fredrik mentions, first it has to find the component, and then ask it what the value is... which, behind the scenes, just asks the data source anyway. So it will always be faster to just ask the data source yourself.
NOTE: the corresponding write method is dataSource.setValue ("FieldName", "NewValue"), not dataSource.replaceItemValue ("FieldName", "NewValue"). Both will work, but setValue also does the same type conversion that getValue does, so you can pass it data that doesn't strictly conform to the old Domino Java API and it usually just figures out what the value needs to be converted to in order to be "safe" for Domino to store.
I would say that the most efficient way is to get the value directly from the datasource.
Because if you use getComponent("ControlName").getValue(); you will do a get on the component first and then a getValue from that. So do a single get from the datasource is more efficient if you ask me.

Cocoa Application Framework with Packages

Ok, I am creating a document-based application in Cocoa and the document's file type is actually a package. Within that package is an XML settings file, a SQLite database and a zip file which is downloaded at runtime. Now the only thing that changes, really, is the XML settings file as the other ones can be recreated at run-time.
Each one of these packages will have one and only one window, hence my desire to use document-based. These files can also be copied, renamed, moved, etc. just like any other file that is part of such an architecture.
But I am completely lost as how to implement this in the Documentation Framework! It seems everywhere I look in the docs it's always talking about in-memory representations of the files which you then write out using the path presented to you in one of the NSDocument overrides (since Cocoa may move it, etc.) But again, I'm using a SQLite database that sits on disk, not in memory.
I have looked all over for overridable methods that would still give me things like dirty-state checking of the doc, open and save file dialog support and the like, but I can't seem to find anything that just says 'Here's a file URL... Open it as you see fit' althought I did get close at the application's delegate level, at least for the opening.
So let's assume that's working as expected. How do I implement the save/save-as where I want to control everything that is written to disk or not? I don't want to (not can I) mess around with data structures or the like. I just want to be given a psth that the user selects in the 'Save As' dialog (for new) and be able to write what I need to there. Simple. But again, the 50+ page document from developer.apple.com about Document-based architecture tells me where to overload a lot of things, but every one seems to stem from some in-memory representation of the document, which again, is not what my package is. Technically, only the internal XML file is what would be tied to the document. Everything else is just support for it.
So? Anyone? Takers?
Mark
I can't seem to find anything that just says 'Here's a file URL... Open it as you see fit'
Implement the readFromURL:ofType:error: method in your document class. Alternatively, since your document type is a package type, implement the readFromFileWrapper:ofType:error: method.
You don't have to read the data into memory; you can do whatever you want in whichever method you implement, including opening the database.
How do I implement the save/save-as where I want to control everything that is written to disk or not?
Implement the writeToURL:ofType:error: method or the fileWrapperOfType:error: method.
If you had or could easily create data in memory, you would implement the readFromData:ofType:error: and dataOfType:error: methods. The URL-based and file-wrapper-based methods are for cases where data in memory is not an option. And the primary use of file wrappers is for package types like yours.
Actually, I found it. It's not the 'writeTo' methods, but rather the 'saveTo' methods you want to override. When I did that, the saving code worked as I expected, including automatic save panel support. For clarity, this is the one I chose...
saveToURL:ofType:forSaveOperation:error:
and it works like a champ! Not too confusing now, was it! Sheesh!!!
That was of course the very first thing that I tried, but if you read the developer documentation--specifically the Cocoa Document-Based Architecture--here's what it says about those very methods...
During writing, your document may be asked to write its contents to a different location or using a different file type. Again, your overridden method should be able to determine everything it needs to do the writing from the passed-in parameters.
If your override cannot determine all of the information it needs from the passed-in parameters, consider overriding another method. For example, if you see the need to invoke fileURL from within an override of readFromData:ofType:error:, perhaps you should instead override readFromURL:ofType:error:. For another example, if you see the need to invoke fileURL from within an override of writeToURL:ofType:error:, perhaps you should instead override writeToURL:ofType:forSaveOperation:originalContentsURL:error:.
In other words, it seems to say that you can't assume the URL that is passed to you is the actual place on disk where the 'something' is eventually written to, which wreaks havoc when dealing with database files that are opened by URL. Maybe I'm missing something.
But ok... forget I read that and simply even try to just override those methods. I do and return TRUE for each, (I log the URL so I can see what is being passed in), I get this error on 'Save As' after you have chosen a filename...
2009-10-28 14:31:51.548 XPanel[1001:a0f] dataOfType:error: is a subclass responsibility but has not been overridden.
...but when you look at the documentation for that it says the default implementation throws an exception because you must override one of the other implementations above... which I obviously just did! Plus, again, this can't be represented as simple data!
So grasping at straws here, I overrode that one too and just returned nil, since again, you can't represent what I'm doing with a NSData object. Then I get a 'Can't be saved' message.
WTF?! Why is it calling that thing anyway??!!
...and that's when I gave up and posted this here.
Now if YOU can give me a simple example that perhaps doesn't even actually read or write a file but instead just logs the URL, that would be perfect. Not to useful but still, it should work... I just can't seem to implement get it to.

Resources