hello guys i have one simple program which copying itself. Its work great when i copying in D disk. But when im trying to copy it on c disk nothing happens.
This is code :
int main()
{
string appDir = "";
appDir = std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
CopyFile(appDir.c_str(), "C:\\SelfCopyingApp.exe", 1);
system("PAUSE");
return 0;
}
Does anyone have an idea?
Thanks...
By default, the system drive has locked down permissions which prevent anyone from copying things there who are not administrators. Generally, one should not be messing with the root of the drive. If you need to do something like an installer, then you should
Ask for Admin rights
Install yourself in the correct location, namely %PROGRAMFILES%\CompanyName\ProductName
Messing with the root of the drive is asking for trouble; that's not where programs go.
Other notes on this code not related to your question:
system("pause") is wrong. Use std::cin.get() if you really want a portable way to get that behavior.
You should probably be using Unicode.
If GetModuleFileName fails you're going to be copying some random garbage to that location, not yourself. You need to check the return codes and GetLastError codes of every Win32 function.
Related
I have generated a GeoTiff dataset in-memory using GDALTranslate() with a /vsimem/ filepath. I need access to the buffer for the actual GeoTiff file to put it in a stream for an external API. My understanding is that this should be possible with VSIGetMemFileBuffer(), however I can't seem to get this to return anything other than nullptr.
My code is essentially as follows:
//^^ GDALDataset* srcDataset created somewhere up here ^^
//psOptions struct has "-b 4" and "-of GTiff" settings.
const char* filep = "/vsimem/foo.tif";
GDALDataset* gtiffData = GDALTranslate(filep, srcDataset, psOptions, nullptr);
vsi_l_offset size = 0;
GByte* buf = VSIGetMemFileBuffer(filep, &size, true); //<-- returns nullptr
gtiffData seems to be a real dataset on inspection, it has all the appropriate properties (number of bands, raster size, etc). When I provide a real filesystem location to GDALTranslate() rather than the /vsimem/ path and load it up in QGIS it renders correctly too.
Looking a the source for VSIGetMemFileBuffer(), this should really only be returning nullptr if the file can't be found. This suggests i'm using it incorrectly. Does anyone know what the correct usage is?
Bonus points: Is there a better way to do this (stream the file out)?
Thanks!
I don't know anything about the C++ API. But in Python, the snippet below is what I sometimes use to get the contents of an in-mem file. In my case mainly VRT's but it shouldn't be any different for other formats.
But as said, I don't know if the VSI-api translate 1-on-1 to C++.
from osgeo import gdal
filep = "/vsimem/foo.tif"
# get the file size
stat = gdal.VSIStatL(filep, gdal.VSI_STAT_SIZE_FLAG)
# open file
vsifile = gdal.VSIFOpenL(filep, 'r')
# read entire contents
vsimem_content = gdal.VSIFReadL(1, stat.size, vsifile)
In the case of a VRT the content would be text, shown with something like print(vsimem_content.decode()). For a tiff it would of course be binary data.
I came back to this after putting in a workaround, and upon swapping things back over it seems to work fine. #mmomtchev suggested looking at the CPL_DEBUG output, which showed nothing unusual (and was silent during the actual VSIGetMemFileBuffer call).
In particular, for other reasons I had to put a GDALWarp call in between calling GDALTranslate and accessing the buffer, and it seems that this is what makes the difference. My guess is that GDALWarp is calling VSIFOpenL internally - although I can't find this in the source - and this does some kind of initialisation for VSIGetMemFileBuffer. Something to try for anyone else who encounters this.
Right now, I am facing a new problem that I can't figure out how to fix. I have two files. One is a video file and other is a thumbnail. They have same name. I want to rename these two files using C++. I am using the rename function and it works. This is what I've written:
if(rename(videoFile) == 0)
{
if(rename(thumbnail) != 0)
{
printf("Fail rename \n");
}
}
The problem occurs when the video file is renamed successfully but for some reason the thumbnail can't be renamed. When this happens, I would like to rollback the renaming of the video file because the video file name and the thumbnail file name should be the same in my program. What I want to do is to rename after both files are okay to rename. Please guide me, any design pattern for function like rollback or third party software.
There is no absolutely foolproof way to do this.
Fundamental rule of disk I/O: The filesystem can change at any time. You can't check whether a rename would succeed; your answer is already wrong. You can't be certain that undoing the rename will succeed; somebody else might have taken the name while you briefly weren't using it.
On systems that support hard links, you can use them to get about 90% of the way there, assuming you're not moving between filesystems. Suppose you're renaming A to B and C to D. Then do these things:
Create hard link B which links to A. This is written as link("A", "B") in C, using the Unix link(2) system call. Windows users should call CreateHardLink() instead.
If (1) succeeded, create hard link D which links to C. Otherwise, return failure now.
If (2) succeeded, delete A and C and return success. Otherwise, delete B and return failure. If the deletions fail, there is no obvious means of recovery. In practice, you can probably ignore failed deletions assuming the reason for failure was "file not found" or equivalent for your platform.
This is still vulnerable to race conditions if someone deletes one of the files out from under you at the wrong time, but that is arguably not an issue since it is largely equivalent to the rename failing (or succeeding) and then the person deleting the file afterwards.
Technically, you should also be opening the containing directory (in O_RDONLY mode) and fsync(2)'ing it after each operation, at least under Unix. If moving between directories, that's both the source and the destination directories. In practice, nobody does this, particularly since it will lead to degraded performance under ext3. Linus takes the position that the filesystem ought to DTRT without this call, but it is formally required under POSIX. As for Windows, I've been unable to find any authoritative reference on this issue on MSDN or elsewhere. So far as I'm aware, Windows does not provide an API for synchronizing directory entries (you can't open() a directory, so you can't get a file descriptor suitable to pass to fsync()).
Nitpick: To some extent, this sort of thing can be done perfectly on transactional filesystems, but just about the only one in common use right now is NTFS, and Microsoft specifically tells developers not to use that feature. If/when btrfs hits stable, transactions might become genuinely useful.
On Windows platform starting from Vista, you can use code such as the following.
#include "KtmW32.h"
bool RenameFileTransact( LPCTSTR lpctszOldVideoFile, LPCTSTR lpctszNewVideoFile, LPCTSTR lpctszOldThumbnailFile, LPCTSTR lpctszNewThumbnailFile )
{
bool bReturn = false;
HANDLE hRnameTransaction = CreateTransaction(NULL, NULL, 0, 0, 0, 0, NULL);
if (MoveFileTransacted(lpctszOldVideoFile, lpctszNewVideoFile, NULL, NULL, 0, hRnameTransaction) &&
MoveFileTransacted(lpctszOldThumbnailFile, lpctszNewThumbnailFile, NULL, NULL, 0, hRnameTransaction))
{
if ( CommitTransaction(hRnameTransaction))
{
bReturn = true;
}
}
CloseHandle( hRnameTransaction );
return bReturn;
}
But as #Kevin pointed out above, Microsoft discourages the usage of this good feature.
I'm trying to use GetDiskFreeSpaceEx in my C++ win32 application to get the total available bytes on the 'current' drive. I'm on Windows 7.
I'm using this sample code: http://support.microsoft.com/kb/231497
And it works! Well, almost. It works if I provide a drive, such as:
...
szDrive[0] = 'C'; // <-- specifying drive
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = '\0';
pszDrive = szDrive;
...
fResult = pGetDiskFreeSpaceEx ((LPCTSTR)pszDrive,
(PULARGE_INTEGER)&i64FreeBytesToCaller,
(PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
fResult becomes true and i can go on to accurately calculate the number of free bytes available.
The problem, however, is that I was hoping to not have to specify the drive, but instead just use the 'current' one. The docs I found online (Here) state:
lpDirectoryName [in, optional]
A directory on the disk. If this parameter is NULL, the function uses the root of the current disk.
But if I pass in NULL for the Directory Name then GetDiskFreeSpaceEx ends up returning false and the data remains as garbage.
fResult = pGetDiskFreeSpaceEx (NULL,
(PULARGE_INTEGER)&i64FreeBytesToCaller,
(PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
//fResult == false
Is this odd? Surely I'm missing something? Any help is appreciated!
EDIT
As per JosephH's comment, I did a GetLastError() call. It returned the DWORD for:
ERROR_INVALID_NAME 123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
2nd EDIT
Buried down in the comments I mentioned:
I tried GetCurrentDirectory and it returns the correct absolute path, except it prefixes it with \\?\
it returns the correct absolute path, except it prefixes it with \\?\
That's the key to this mystery. What you got back is the name of the directory with the native api path name. Windows is an operating system that internally looks very different from what you are familiar with winapi programming. The Windows kernel has a completely different api, it resembles the DEC VMS operating system a lot. No coincidence, David Cutler used to work for DEC. On top of that native OS were originally three api layers, Win32, POSIX and OS/2. They made it easy to port programs from other operating systems to Windows NT. Nobody cared much for the POSIX and OS/2 layers, they were dropped at XP time.
One infamous restriction in Win32 is the value of MAX_PATH, 260. It sets the largest permitted size of a C string that stores a file path name. The native api permits much larger names, 32000 characters. You can bypass the Win32 restriction by using the path name using the native api format. Which is simply the same path name as you are familiar with, but prefixed with \\?\.
So surely the reason that you got such a string back from GetCurrentDirectory() is because your current directory name is longer than 259 characters. Extrapolating further, GetDiskFreeSpaceEx() failed because it has a bug, it rejects the long name it sees when you pass NULL. Somewhat understandable, it isn't normally asked to deal with long names. Everybody just passes the drive name.
This is fairly typical for what happens when you create directories with such long names. Stuff just starts falling over randomly. In general there is a lot of C code around that uses MAX_PATH and that code will fail miserably when it has to deal with path names that are longer than that. This is a pretty exploitable problem too for its ability to create stack buffer overflow in a C program, technically a carefully crafted file name could be used to manipulate programs and inject malware.
There is no real cure for this problem, that bug in GetDiskFreeSpaceEx() isn't going to be fixed any time soon. Delete that directory, it can cause lots more trouble, and write this off as a learning experience.
I am pretty sure you will have to retrieve the current drive and directory and pass that to the function. I remember attempting to use GetDiskFreeSpaceEx() with the directory name as ".", but that did not work.
I was wondering if there is a Windows API that can tell me if there is a empty CD is inside a CD-ROM/DVD-Rom drive.
I've already looked at GetVolumeInformation(), but that only brings back information on the actual CD-ROM drive, not the media that is inside it, if there's even a CD in it or not.
All I'm trying to do is see if there's a cd in the drive or not and return a boolean value.
Thanks for any help
Call GetFileAttributes() on the root directory. GetFileAttributes() is quite optimized as it's commonly used as a check whether a file or directory exists.
Another method is to call GetDiskFreeSpace, which (despite its name) also returns the total disk size.
The Shell also has some useful functions. SHGetDriveMedia will tell you what's loaded, but you should first call GetDriveType().
The API you're looking for is most probably IMAPI.
I think this article here could be of help for you http://msdn.microsoft.com/en-us/magazine/cc163992.aspx
You can use DeviceIoControl API passing IOCTL_STORAGE_CHECK_VERIFY as the dwIoControlCode. This will check if a particular disc drive is ready i. e. has a disc in it and, of course, the tray is closed. Check the DeviceIoControl MSDN documentation for more info on this function.
// FROM VISTA to ....
BOOL CDYesNo(WCHAR letter) {// like F
DWORD pdwMediaContent=0;
BOOL ret =1;
WCHAR catw[3]; // create wchar string
catw[0]=letter;
catw[1]=L':';
catw[2]=NULL; `enter code here`
HRESULT rcd=SHGetDriveMedia( catw, &pdwMediaContent);
//rcd normally is S_OK, maybe tested.
if(pdwMediaContent ==0) ret=0;
return ret; // 0=empty
}
I'm new here and my english is not really good. Apologize any inconvenience!
I'm programming an application for windows mobile with native code (MFC). I'm trying to open a file and this is driving me crazy. I've tried to open it in a thousand diferent ways... And I really achieve it, but when I try to read (fread or getline) the program crashes without any explanation:
The program 'x' finalize with code 0 (0x0)
The GetLastError() method, in some cases, returns me a 183.
Then, I put the code I've used to open the file:
std::wifstream file(L"\\Archivos de programa\\Prog\\properties.ini");
wchar_t lol[100];
if (file) {
if(!file.eof()) {
file.getline(lol,99);
}
}
It enters on all the if's, but the getline crashes.
FILE * lol = NULL;
lol = _wfope n(ruta, L"rb");
DWORD a = GetLastError();
if ( lol != NULL )
return 1;
else
return -1;
It returns 1 (correct), and after, in a later getline, it stores trash on the string. However, it doesn't crash!!
fp.open (ruta, ifstream::in);
if ( fp.is_open() ) {
return 1;
}else{
return -1;
}
It enters on the return 1, but when executing the later getline() crashes.
I've debugged the getline() method and it crashes on the library fstream, right there:
if ((_Meta = fget c (_File)) == EOF)
return (false);
In the if. The fgetc(), I supose.
I'm going completely crazy!! I need some clue, please!!
The path of the file is correct. First, because, in theory, the methods open the file, and second, I obtain the path dinamically and it matches.
Emphasize that the fread method also crashes.
Thanks in advance!
P.S.:
Say that when I do any fopen, the method fp.good() returns me FALSE, and the GetLastError returns me 183. By the other hand, if I use fp.fopen(path, ifstream::in); or std::wifstream fp(path); the fp.good(); returns me TRUE, and the GetLastError() doesn't throw any error (0).
A hint: use the Process Monitor tool to see what goes wrong in the file system calls.
The path accepted by wifstream is lacking a drive ("C:" or the like) (I don't know what the ruta variable points to)
Apart from the streams problem itself, you can save yourself a lot of trouble by using the GetProfileString and related functions, when using a windows .ini file.
I'm shooting in the dark here, but your description sounds like a runtime mismatch story. Check that MFC and your project use the same runtime link model (static/dynamic). If you link to MFC dynamically, then the restriction is stricter: both MFC and your project have to use dynamic runtime.
I don't know why, but with the CFile class... it works...
Programming mysteries!
Shooting in the dark too.
Unexplained random crash in MFC often comes from a mismatch message handler prototype.
For example the following code is wrong but it won't generate any warning during compilation and it may work most of the time :
ON_MESSAGE(WM_LBUTTONDOWN, onClick)
...
void onClick(void) //wrong prototype given the macro used (ON_MESSAGE)
{
//do some stuff
}
Here the prototype should be :
LRESULT onClick(WPARAM, LPARAM)
{
}
It often happens when people get confident enough to start modifying manually the message maps.