Folder.CopyHere() from IShellDispatch silently fails to unpack most of a Zip file, but only if the file is on a DVD - com

My application (the Endless OS installer for Windows) uses methods on IShellDispatch (provided by Shell32.dll), to extract a Zip file (example). In various modes of operation, this file may be downloaded from the internet to a fixed disk; on an exFAT filesystem on a USB stick; or in an ISO 9660 (with Joliet extensions) image which may be mounted as a virtual drive, or written to a DVD. In all cases but the last, extracting the Zip file works; but when the Zip file is on a DVD, all that's created in the target directory is the directory structure (EFI\BOOT\) for the first file in the archive (EFI\BOOT\bootx64.efi); neither that file, nor any other files in that directory or any other directory, are extracted. With exactly the same Zip file on any other medium — including inserting the ISO into a VirtualBox virtual optical drive — the problem disappears.
The original C++ code where I first saw this problem is here. It looks like this (with error handling removed, since all methods return a successful HRESULT in my testing, and the FOF_NO_UI also removed in case that was masking an error message):
void UnpackZip(const CComBSTR source, const CComBSTR dest) {
CComPtr<IShellDispatch> pISD;
CComPtr<Folder> pToFolder, pFromFolder;
CComPtr<FolderItems> folderItems;
CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch,
(void **)&pISD);
pISD->NameSpace(CComVariant(dest), &pToFolder);
pISD->NameSpace(CComVariant(source), &pFromFolder);
pFromFolder->Items(&folderItems);
pToFolder->CopyHere(CComVariant(folderItems), CComVariant(0));
}
I can reproduce this problem both by attempting to unpack the Zip file from Windows Explorer GUI (which does not report any errors), and by running the following in PowerShell, so I am reasonably sure it's not my application code that's at fault:
PS> $shell = new-object -ComObject shell.application
PS> $zip = $shell.NameSpace("D:\endless\eos-eos3.3-amd64-amd64.171122-232702.base.boot.zip")
PS> $target = $shell.NameSpace("C:\test")
PS> $target.CopyHere($zip.items())
If I explicitly iterate over the top-level folders in the Zip file, as follows, then some but not all files from each folder are extracted (and still none in EFI\BOOT\):
PS> foreach ($item in $zip.items()) { $target.CopyHere($item) }
If I explicitly select that first file which is not unpacked, no error is raised:
PS> $item = $zip.items().Item(0).GetFolder().Items().Item(0).GetFolder().Items().item(0);
PS> $item
Application : System.__ComObject
Parent : System.__ComObject
Name : bootx64.efi
Path :
GetLink :
GetFolder :
IsLink : False
IsFolder : False
IsFileSystem : False
IsBrowsable : False
ModifyDate : 22/11/2017 23:33:56
Size : 1157984
Type : EFI File
PS> $target.CopyHere($item)
But it's still not unpacked to $target. The DVD drive does not even spin up!
If I copy exactly the same Zip file to a fixed drive – or mount the DVD ISO as a virtual disk, whether within Windows, or from the outside via the VirtualBox VM Windows is running in – everything works correctly. The problem only occurs when the archive is really on a physical DVD. I've received many reports of this problem from users with various hardware, so it's not my DVD drive or laptop. I personally have only tested and reproduced it on Windows 10 (build 14393 and 15063, at least); I'm not sure whether it can be reproduced on older Windows versions but since Windows 10 is the most commonly-used version by users of this application, it's a moot point whether this worked on older versions.
The files which are not unpacked are all those ending .efi (EFI executables) and those ending .mod (legacy BIOS GRUB modules). This is totally deterministic. But I'm stumped as to why the shell would take such a disliking to certain files, only when the archive is on a DVD.
My application can work around this problem by copying the Zip file to the hard disk before extracting it. But the question remains: why is this happening? And at a higher level: short of stepping through the compiled Shell32.dll code in a debugger, how could I diagnose what's going wrong?

Related

Auto-Selecting Script Path

I am still rather new to scripting and powershell. However I have come across a common problem with my scripts. In my deployment environment I mainly deal with Windows 7 and 8. I deploy several programs through the use of a batch file on a USB. I understand that everything could be pushed through the network but I do not have the permissions for that. Now to use the USB method I must make a path for E: and a path for D: and hope that when the USB was inserted that it received one of those letters or the whole script fails.
Here is an example:
Title Installing "Program"
Echo (Step # of #)
Echo Installing "Program". . .
Echo Please Wait. . .
Echo Attempting Install from D:/
pushd D:\\Path
Echo Attempting Install from E:/
pushd E:\\Path
Echo Complete
cls
Is there a way for me to condense the path to one line that will pick up D:, E: or another drive letter? This must also be able to be used on other flash drives as well. Would something like: .\path work?
This depends on the version of pwershell that you are using. Newer versions will give you the path of the script with $PSCommandPath, and you can extract the drive letter using $PSCommandPath[0].
For older versions, you can get the path using $MyInvocation.MyCommand.Path, and extract the drive letter with
split-path $MyInvocation.MyCommand.Path -Qualifier
I would recommend the second method as it will be more portable between different machines that may only have the older version.
If you are runnig this from within a batch file, instead of a powershell script, then %~do will give you the drive of the script.

What do I have to do to install the missing error messages cab file on a Windows CE Device?

I got this err msg while running my WindowsCE app:
...and so I copied NETCFv35.Messages.EN.wm.cab from my PC to my handheld, and tried to run/install that cab file on the handheld. I got:
So then I tried the same with NETCFv35.Messages.EN.cab. When I ran it on the handheld, it told me that it had already been installed:
...but I went ahead and "reinstalled." I'm not sure its default installation location, though, is the right place:
...so I copied it over again to the folder on the handheld where my .exe resides (NETCFv35.Messages.EN.cab had been deleted out of there after reinstalling). This time I made sure to install it into that same folder, rather than the seemingly random location it chose the first time:
Still, though, running the app shows me the same old "Which way did they go, George?" err msg about not being able to show me error messages (first screamshot above).
This makes me feel kind of Grimm, to the point where I'm thinking this is a pretty revoltin' development (no pun intended).
What do I need to do to be able to see the hidden err msgs?
UPDATE
This is what I got when I unpacked SYCCFA~1.001, renamed it System.SR.dll, and tried to add it as a reference to the project (it claims that it is not a .NET assembly...???):
I tried the same thing with NETCFv35.Messages.EN.wm.cab, with the same results (it looks like the same file - same date, same size...so why the name diff?)
The error messages are in a single file called "System.SR.dll". The CAB simply installs that and puts it into the GAC. You get an "already installed" error because it sees it in the registry, though it doesn't mean the file is actually there.
You can simply extract the DLL from the cab with a zip extractor (I use WinRAR, but whatever). For example, If I open this file:
C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics\NETCFv35.Messages.EN.cab
It has a few things in it. SYCCFA~1.001 is the DLL. Pull it out, rename it to System.SR.dll and add it as a reference in your project. Studio will deploy it when you run and boom, you're cooking with butter.

Oracle virtual box inaccessible

I am using Oracle Virtual Box version 4.2.16 r86992. Everything was fine until yesterday shutdown.
Today, it shows inaccessible and throws this error:
Runtime error opening C:\Users\xxxxxx\VirtualBox VMs\vBoxxxxXubuntu_Beta\vBoxxxxXubuntu_Beta.vbox for reading: -102 (File not found.).
D:\tinderbox\win-4.2\src\VBox\Main\src-server\MachineImpl.cpp[725] (long __cdecl Machine::registeredInit(void)).
It's good to restore this to working, It would save lot of time and restore configuration settings and data. Thanking your support.
This normally happens if the host OS crashes or you pull the plug on it, leaving the .vbox file unsaved.
In the location:
C:\Users\xxxxxxx\VirtualBox VMs\vBoxxxxXubuntu_Beta\
you should find two files:
vBoxxxxXubuntu_Beta.vbox-prev
vBoxxxxXubuntu_Beta.vbox-tmp
Copy vBoxxxxXubuntu_Beta.vbox-prev to vBoxxxxXubuntu_Beta.vbox.
Select vBoxxxxXubuntu_Beta.vbox, in the VBox manager, right click, and then left click on refresh.
Observe that it now shows Powered Off.
Now you are good to go.
Based on my experience, I was on Windows 7 and running Ubuntu 14.04 as guest OS on Virtual Machine.
Go to your Virtualbox folder (in my case):
C:\Users\Dev12\VirtualBox VMs\Ubuntu
You'll see files with extensions: Ubuntu.vbox-tmp or Ubuntu.vbox-prev
Remove -tmp from file name Ubuntu.vbox-tmp so that it reads as Ubuntu.vbox
Exit from Virtual Machine and start it again.
You should now see error gone away.
The virtual box files with extension .vbox contain metadata the virtualbox hypervisor requires to resolve the guest virtual OS' configuration.
If the main .vbox file is corrupted (i.e. reporting that it is empty) then use the backup .vbox-prev file to recover the contents of the original file.
Do this by renaming the empty .vbox files a temporary name (e.g. rename originalVM.vbox to originalVM-empty.vbox).
Then make a copy of the backup file originalVM.vbox-prev, where the copy will have the same name as the original but with the word "copy" appended to it (i.e. originalVM.vbox-prev is renamed to originalVM (copy).vbox-prev).
It is important to retain the original backup .vbox-prev file it should not be altered or itself renamed.
Now go rename the copy of the newly created .vbox-prev file originalVM (copy).vbox-prev to the original name of the empty .vbox file and be mindful to also change it extension from .vbox-prev back to just .vbox.
That is rename originalVM (copy).vbox-prev back to originalVM.vbox. Now that this is done you may add the .vbox file (guest os) back into the VBOX hypervisor. This will recover the state and snapshot of the "inaccessible" guest VM. Now delete the original empty .vbox file.
I've faced the same issue using CentOs 6.8 on a VirtualBox 5.1 installed in Windows 7 and AjayKumarBasuthkar's solution worked perfectly for me:
I went to C:\Users\\VirtualBox VMs\CentOS6.8
Made a copy of the file CentOS6.8.vbox-prev and gave it the name of CentOS6.8.vbox
Went to the VirtualBox GUI, right-clicked the VM instance and hit refresh
The CentOS instance went from the State Inaccessible to Powered Off
VirtualBox 4.3 is released and could it be that you've updated or there was some issues while updating?
In any case if you are not able to bring up the Virtualbox, remember to backup the VirutalBox VMs folder and going for a fresh install should be the best way forward.
I faced the same problem and I resolved by doing following in Oracle Virtual box 4.3.28 with Ubuntu 14.04 LTS, when Virtual box VM was closed.
Removed ubuntu.vbox to another folder outside virtual box folder
removed -prev from file ubuntu.vbox-prev
start oracle virtualbox, it works excellent.
On a Windows 7 Host, I found that Daemon Tools service had a hold on the file.
The solution was to uninstall Daemon Tools, but I suspect if you stop the service and remove the file association, you would be sorted.
The other issue might be that if your Virtual Machine was on an external hard drive, it is possible that the drive letter has changed. If so, go to Computer Management, and select the hard drive and right click to change the drive letter and save (Note that this is for Windows).
This is going to sound stupid but try to reinstall VB. It may work.
I am adding one critical and important comment to the previous great answers. Make sure that the original .vbox file is corrupted and empty before you copy the content from the.vbox-prev file. If it is not the case and you find it with lines and readable content, don't replace the content of the .vbox.
Changes made to the VM directly before the VM got inaccessible might not be updated in the .vbox-prev backup file . The changes could not be synced with those changes before the OS upgrade or system changes that led to the inaccesable issue.
If you find your VM not accessible after an OS upgrade or system change, first check the.vbox file if it is still readable by a text editor and it has lines. Then you just need to delete the VM from the VirtualBox manager list(just remove the appliance from the list and don't remove files) . Then reopen the.vbox file and it should work perfectly.
If the original.vbox file is corrupted or empty when you open it with a text editor, then and only then, you can copy the content from the .vbox-prev and follow the instructions highlighted.
This was my experience, and I wanted to share it with you to avoid losing some last minute changes before the OS upgrade or crash.

script in mac app temporary location

I am a bit new to Mac OS X app development and I got stuck with Mac OS moving some Resources to a temp location wereas the her ones remain in the Resources folder. I have searched through google for a few hours and that did not help.
Here is my situation in a little more detail:
I have an application build in Xcode. It consist of an ObjC TaskWrapper and a perl script (main.pl) that is being called after the app is run. There is also an external file(say the name is extrafunctions (no extension)), that I need to load from the perl script in the runtime of application. Both the perl script and the external file are in the Resources folder inside the .app directory after building it from xcode.
After execution the main.pl file is moved to a temp location. The extrafunctions file remains in Resources inside the myMacApp.app folder. Then, when main.pl tries to load extrafunctions (used to be in the same directory) and fails, as extrafunctions has not been copied to the temp folder along.
I would need to access this extrafunctions file from the perl script, but cannot come across neither a way to get the msipp location, nor a way to let it be copied to the temp location as well.
Overview:
- main.pl = script in Resources inside myMacApp.app
- extrafunctions = external script to be loaded by main.pl in Resources
- main.pl tries to load extrafunctions: does not work
some code:
install.pl
...
if(-f "extrafunctions") {
open my $fh, "<", "extrafunctions" or die "Could not open extrafunctions : $!";
$content = do { local $/; <$fh> };
close $fh;
} else {
...
}
Any help highly appreciated!

Debugging Solaris OS crash

I have access to a remote Solaris terminal which crashes occasionally, and I have to ask someone with physical access to boot the machine up, which it does successfully. I would like to know which tools/files should I look at to find out the cause of the crash so that I can make the necessary configuration changes and avoid it in the future.
What tools you can use will depend on what version of solaris you have running and what the actual problem
is. The first thing to do is check the system console (which it sounds like you don't have access to) and the /var/adm/messages file. This file is updated with system messages and the newest will appear at the end.
Next, you can look for a system core file. If a core file is created, it would be in /var/crash/hostname where "hostname" is the name of the machine.
If you have an actual core file in the /var/crash/hostname directory, this set of commands will give you a good
string to search google with:
# cd /var/crash/hostname
Replace "hostname" with the hostname of your machine.
# mdb -k unix.0 vmcore.0
If you have multiple core files, select the most recent version.
> ::status
This should give you a panic message, cut and paste that into google and see what you can find.
For more core file analysis read this:
http://cuddletech.com/blog/pivot/entry.php?id=965